-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Unix: Move 'FileNotFound to DirectoryNotFound' handling to GetExceptionForIoErrno. #70661
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
Conversation
…onForIoErrno. On Windows, APIs throw DirectoryNotFoundException instead of FileNotFoundException when the base components of a path don't exist. SafeFileHandle, and FileSystemInfo have some specific code to detect that case and to the same on Unix. This change moves that mapping to Interop.IOErrors so it applies to all users of GetExceptionForIoErrno.
|
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsOn Windows, APIs throw DirectoryNotFoundException instead of SafeFileHandle, and FileSystemInfo have some specific code to detect This change moves that mapping to Interop.IOErrors so it applies
|
@danmoseley @stephentoub I don't understand the error. What does this mean? |
|
On Windows, APIs return different errors for the parent directory not being there ( On Unix, Currently those checks are implemented at different places. To implement the exist check in CI gives me an error I don't understand for using
@dotnet/area-system-io @stephentoub ptal. |
| if (isDirectory && errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) | ||
| errorCode = Interop.Errors.ERROR_PATH_NOT_FOUND; | ||
| if (isDirectory && errorCode == Interop.Errors.ERROR_ACCESS_DENIED && ignoreAccessDenied) | ||
| if (ignoreAccessDenied && errorCode == Interop.Errors.ERROR_ACCESS_DENIED) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is unrelated. I can move it to a separate PR.
|
@dotnet/area-system-io ptal. Example where this change changes applies: DirectoryInfo di = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));
FileInfo fi = new FileInfo(Path.Combine(di.FullName, "file"));
fi.OpenWrite().Dispose();
fi.LastWriteTimeUtc = DateTime.UtcNow;
Directory.Delete(di.FullName, recursive: true);
fi.LastWriteTimeUtc = DateTime.UtcNow;On Linux, the last statement currently throws |
@dotnet/interop-contrib what does this error mean? And what can I do to fix it? |
|
System.IO.Ports supports downlevel TFMs. On those TFMs, we try to have the generator generate an old-style DllImport. Some functionality cannot be translated automatically to the old system. I’d recommend that you use an |
|
CI fail is unrelated. @dotnet/area-system-io ptal. |
|
@adamsitnik @jeffhandley ptal. |
| // Windows distinguishes between whether the directory or the file isn't found, | ||
| // and throws a different exception in these cases. We attempt to approximate that | ||
| // here; there is a race condition here, where something could change between | ||
| // when the error occurs and our checks, but it's the best we can do, and the | ||
| // worst case in such a race condition (which could occur if the file system is | ||
| // being manipulated concurrently with these checks) is that we throw a | ||
| // FileNotFoundException instead of DirectoryNotFoundException. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth keeping this comment inside GetExceptionForIoErrno?
| // macOS returns ENOTDIR when the path refers to a file and ends with '/'. | ||
| // Trim the separator so we get EEXIST instead. | ||
| ReadOnlySpan<char> path = PathInternal.TrimEndingDirectorySeparator(fullPath.AsSpan()); | ||
| int result = Interop.Sys.MkDir(path, (int)unixCreateMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume there is no test that ensures we don't get DirectoryNotFoundException when the path ends with '/'? Could you please add it?
|
|
||
| if (attributes == (FileAttributes)(-1)) | ||
| FileSystemInfo.ThrowNotFound(fullPath); | ||
| throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), fullPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), fullPath); | |
| throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath); |
|
|
||
| if (mode == (UnixFileMode)(-1)) | ||
| FileSystemInfo.ThrowNotFound(fullPath); | ||
| throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), fullPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), fullPath); | |
| throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath); |
|
This appears to have broken main, at least Android AOT builds:
|
|
@jozkee This seems to have broken many, many builds. E.g., https://dev.azure.com/dnceng/public/_build/results?buildId=1944354&view=results |
|
Almost everything - https://dev.azure.com/dnceng/public/_build/results?buildId=1944413&view=results |
|
Sorry for that, I don't know why that was not caught by this PR's build. |
The breaking call site was added a few days ago. And the CI build here was 18 days ago. that's why it didn't get caught. |
|
It is because the validation ran 18 days ago. In the meantime this change went in, and collided. It happens, but for something touching common code like this it might be good to ensure validation is fresher. commit 9fd407a |
On Windows, APIs throw DirectoryNotFoundException instead of
FileNotFoundException when the base components of a path don't exist.
SafeFileHandle, and FileSystemInfo have some specific code to detect
that case and do the same on Unix.
This change moves that mapping to Interop.IOErrors so it applies
to all users of GetExceptionForIoErrno.