read_dir: handle u64 directory cookies that exceed i64::MAX
Some filesystems (e.g., AWS EFS) can produce directory cookies (d_off values) with the high bit set, which makes them larger than i64::MAX. Since lseek64 takes off64_t (i64), these cookies are interpreted as negative offsets and rejected with EINVAL, making the directory unreadable.
Handle this by detecting the EINVAL failure for high-bit offsets and falling back to a scan-and-skip approach (new_walk_to). The fallback rewinds to the beginning of the directory and reads batches via getdents64, skipping entries until it finds the one whose d_off matches the target cookie, then returns the entries after it.
Two alternative approaches were considered:
-
Skip the seek entirely for large cookies, relying on the kernel fd position being correct from the previous getdents64 call. This works for strict sequential access but silently returns wrong entries on retries, backward seeks, or concurrent handle use.
-
Cache the last returned cookie per directory handle (an AtomicU64 in HandleData). On the next readdir, if the target matches the cache, the fd is already positioned and we skip both lseek and scanning. This turns sequential listing from O(n^2) to O(n) at the cost of one u64 per open directory. Left as a future optimization since the current fix prioritizes correctness with minimal changes.
The scan-and-skip fallback is O(n) per call, making a full sequential listing O(n^2) when all cookies have the high bit set. This is acceptable because without the fix these directories are completely unreadable, and in practice many kernel/filesystem combinations accept the cast and never enter the fallback.
Fixes #232 (closed)