-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std.fs: Iterator.next
doesn't handle ENOENT
, but it can happen in valid scenarios
#12211
Comments
ENOENT
as unexpected, but it can happen in valid scenariosIterator.next
treats ENOENT
as unexpected, but it can happen in valid scenarios
Iterator.next
treats ENOENT
as unexpected, but it can happen in valid scenariosIterator.next
doesn't handle ENOENT
, but it can happen in valid scenarios
After a bit of investigation, I think a reasonable change here might be to just add .NOENT => return null, to the Some reasoning:
iter.next() catch |err| switch (err) {
error.DirNotFound => null,
else => |e| return e,
} which is exactly what returning null from within |
I think your reasoning for returning null makes sense and should go in a PR. |
…ENT` `getdents` on Linux can return `ENOENT` if the directory referred to by the fd is deleted during iteration. Returning null when this happens makes sense because: - `ENOENT` is specific to the Linux implementation of `getdents` - On other platforms like FreeBSD, `getdents` returns `0` in this scenario, which is functionally equivalent to the `.NOENT => return null` handling on Linux - In all the usage sites of `Iterator.next` throughout the standard library, translating `ENOENT` returned from `next` as null was the best way to handle it, so the use-case for handling the exact `ENOENT` scenario specifically may not exist to a relevant extent Previously, ENOENT being returned would trigger `os.unexpectedErrno`. Closes ziglang#12211
… `ENOENT` `getdents` on Linux can return `ENOENT` if the directory referred to by the fd is deleted during iteration. Returning null when this happens makes sense because: - `ENOENT` is specific to the Linux implementation of `getdents` - On other platforms like FreeBSD, `getdents` returns `0` in this scenario, which is functionally equivalent to the `.NOENT => return null` handling on Linux - In all the usage sites of `Iterator.next` throughout the standard library, translating `ENOENT` returned from `next` as null was the best way to handle it, so the use-case for handling the exact `ENOENT` scenario specifically may not exist to a relevant extent Previously, ENOENT being returned would trigger `os.unexpectedErrno`. Closes #12211
If we return a I can imagine applications that might care about this distinction. For example, say an application is reading config files from a directory. If that directory gets removed while it's iterating, rather than continuing on like it's finished with all the files, it may want to stop and assert an error. (I would want this behavior in my It would also be problematic for programs that do want to handle this case differently to detect it afterwards. This would mean you'd always have to check whether the directory still exists after you're done iterating over it (an extra check for the "happy path") and this check will always be a race condition since the directory could have been removed and recreated. The only correct solution they would have is to use the lower-level APIs to iterate over the directory. Actually now that I've thought about it, I would think that in most cases you'd probably want to assert an error if a directory is removed while you're iterating over it. In zig for example, if you're iterating over the files in a cache directory to copy, then you wouldn't want to continue like nothing happened if the source directory was suddenly removed. |
@marler8997 I would normally agree with you, and had similar thoughts initially, but AFAIK the APIs in So, if you wrote some code that handles I figured that making Linux behave like non-Linux was the better route than trying to get non-Linux to behave like Linux (which would involve something like an |
Some systems will have extra error codes that others do not. When this is the case, I think it's better to return the error when possible rather than ignore it by default. I believe this is what the rest of the std library does and I think it's the right choice in general. Maybe you missed it, but I addressed the solution you suggested where you check whether the directory still exists afterwards. This solution is a race condition since the directory can be deleted/re-created. After I had thought on it, it seemed like most programs (or at least many) would want to handle the case where the directory is deleted as a non-happy path. With this API, all cases that want the "correct behavior" are forced to duplicate their directory traversal code to use the lower-level API for any systems that can detect this error and fallback to the higher level API otherwise. |
I agree with marler: returning |
I can see pros/cons to both approaches, and this general topic seems to be something that remains unresolved in terms of how the
I personally still lean towards returning null in this instance, though:
One potential compromise might be to split |
…latform-specific errors Follow up to ziglang#12226, implements the compromise detailed in ziglang#12211 (comment)
…latform-specific errors Follow up to #12226, implements the compromise detailed in #12211 (comment)
Zig Version
master
Steps to Reproduce
getdents
can returnENOENT
if the directory referred to by the fd is deleted before the nextgetdents
call (but after the fd is opened). Currently this causes an unexpected error to be returned fromIterableDir.Iterator.next
.Relevant code for the Linux implementation of
Iterator.next
:zig/lib/std/fs.zig
Lines 604 to 612 in a2ab9e3
Contrived test case (note that I've run into this in a non-contrived use case, though):
Expected Behavior
ENOENT
to be handled in some way byIterator.next
(unsure in what way exactly, but it shouldn't be unreachable or an unexpected error).Note: I've only tested this on Linux, unsure how this manifests on other platforms.
Actual Behavior
The text was updated successfully, but these errors were encountered: