From 9fdb42b4b9f45588bbd938946cb95d2bcbf9f5a8 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Sat, 4 Dec 2021 17:03:46 +0100 Subject: [PATCH 1/2] Directory.Delete: prefer DirectoryNotFoundException over UnauthorizedAccess IOException. --- .../src/System/IO/FileSystem.Unix.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs index 3367fd0e29b9b..14d9f6c9896a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs @@ -497,8 +497,14 @@ private static bool RemoveEmptyDirectory(string fullPath, bool topLevel = false, case Interop.Error.EACCES: case Interop.Error.EPERM: case Interop.Error.EROFS: + // Prefer throwing DirectoryNotFoundException over UnauthorizedAccess IOException. + if (topLevel && !DirectoryExists(fullPath, out Interop.ErrorInfo existErr) && existErr.Error == Interop.Error.ENOENT) + { + throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath, isDirectory: true); + } + throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); case Interop.Error.EISDIR: - throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); // match Win32 exception + throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); case Interop.Error.ENOENT: // When we're recursing, don't throw for items that go missing. if (!topLevel) From 6a4ebc78f804ef52789c5fe9966dd4360daeb9e1 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Sun, 12 Dec 2021 01:26:29 +0100 Subject: [PATCH 2/2] Refactor error handling. --- .../src/System/IO/FileSystem.Unix.cs | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs index 14d9f6c9896a1..a2d35f500e00c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs @@ -492,49 +492,45 @@ private static bool RemoveEmptyDirectory(string fullPath, bool topLevel = false, if (Interop.Sys.RmDir(fullPath) < 0) { Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); - switch (errorInfo.Error) + + if (errorInfo.Error == Interop.Error.ENOTEMPTY) { - case Interop.Error.EACCES: - case Interop.Error.EPERM: - case Interop.Error.EROFS: - // Prefer throwing DirectoryNotFoundException over UnauthorizedAccess IOException. - if (topLevel && !DirectoryExists(fullPath, out Interop.ErrorInfo existErr) && existErr.Error == Interop.Error.ENOENT) - { - throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath, isDirectory: true); - } - throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); - case Interop.Error.EISDIR: - throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); - case Interop.Error.ENOENT: - // When we're recursing, don't throw for items that go missing. - if (!topLevel) - { - return true; - } - goto default; - case Interop.Error.ENOTDIR: - // When the top-level path is a symlink to a directory, delete the link. - // In other cases, throw because we expect path to be a real directory. - if (topLevel) - { - if (!DirectoryExists(fullPath)) - { - throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath, isDirectory: true); - } + if (!throwWhenNotEmpty) + { + return false; + } + } + else if (errorInfo.Error == Interop.Error.ENOENT) + { + // When we're recursing, don't throw for items that go missing. + if (!topLevel) + { + return true; + } + } + else if (DirectoryExists(fullPath, out Interop.ErrorInfo existErr)) + { + // Top-level path is a symlink to a directory, delete the link. + if (topLevel && errorInfo.Error == Interop.Error.ENOTDIR) + { + DeleteFile(fullPath); + return true; + } + } + else if (existErr.Error == Interop.Error.ENOENT) + { + // Prefer throwing DirectoryNotFoundException over other exceptions. + errorInfo = existErr; + } - DeleteFile(fullPath); - return true; - } - goto default; - case Interop.Error.ENOTEMPTY: - if (!throwWhenNotEmpty) - { - return false; - } - goto default; - default: - throw Interop.GetExceptionForIoErrno(errorInfo, fullPath, isDirectory: true); + if (errorInfo.Error == Interop.Error.EACCES || + errorInfo.Error == Interop.Error.EPERM || + errorInfo.Error == Interop.Error.EROFS) + { + throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); } + + throw Interop.GetExceptionForIoErrno(errorInfo, fullPath, isDirectory: true); } return true;