Uh oh!
There was an error while loading. Please reload this page.
Unix: Move 'FileNotFound to DirectoryNotFound' handling to GetExceptionForIoErrno. - #70661
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.
ghost
commented
Jun 13, 2022
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
|
tmds
commented
Jun 13, 2022
@danmoseley@stephentoub I don't understand the error. What does this mean? |
tmds
commented
Jun 24, 2022
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.
This change is unrelated. I can move it to a separate PR.
tmds
commented
Jul 5, 2022
@dotnet/area-system-io ptal. Example where this change changes applies: DirectoryInfodi=Directory.CreateDirectory(Path.Combine(Path.GetTempPath(),Path.GetRandomFileName()));FileInfofi=newFileInfo(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 |
tmds
commented
Jul 8, 2022
@dotnet/interop-contrib what does this error mean? And what can I do to fix it? |
jkoritzinsky
commented
Jul 8, 2022
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 |
tmds
commented
Jul 29, 2022
CI fail is unrelated. @dotnet/area-system-io ptal. |
tmds
commented
Aug 5, 2022
@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.
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.
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.
| throwInterop.GetExceptionForIoErrno(newInterop.ErrorInfo(Interop.Error.ENOENT),fullPath); | |
| throwInterop.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.
| throwInterop.GetExceptionForIoErrno(newInterop.ErrorInfo(Interop.Error.ENOENT),fullPath); | |
| throwInterop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(),fullPath); |
directhex
commented
Aug 15, 2022
This appears to have broken main, at least Android AOT builds:
|
BruceForstall
commented
Aug 15, 2022
@jozkee This seems to have broken many, many builds. E.g., https://dev.azure.com/dnceng/public/_build/results?buildId=1944354&view=results |
radical
commented
Aug 15, 2022
Almost everything - https://dev.azure.com/dnceng/public/_build/results?buildId=1944413&view=results |
jozkee
commented
Aug 15, 2022
Sorry for that, I don't know why that was not caught by this PR's build. |
radical
commented
Aug 15, 2022
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. |
danmoseley
commented
Aug 15, 2022
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.