Commit 14c3c47fb7

Ryan Liptak <squeek502@hotmail.com>
2020-06-27 00:49:31
fs.deleteFile: Translate to error.IsDir when appropriate on POSIX systems
Linux deviates from POSIX and returns EISDIR while other POSIX systems return EPERM. To make all platforms consistent in their errors when calling deleteFile on a directory, we have to do a stat to translate EPERM (AccessDenied) to EISDIR (IsDir).
1 parent 0e3d74d
Changed files (1)
lib
std
lib/std/fs.zig
@@ -1112,6 +1112,16 @@ pub const Dir = struct {
     pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
         os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
             error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
+            error.AccessDenied => |e| switch (builtin.os.tag) {
+                // non-Linux POSIX systems return EPERM when trying to delete a directory, so
+                // we need to handle that case specifically and translate the error
+                .macosx, .ios, .freebsd, .netbsd, .dragonfly => {
+                    const fstat = os.fstatat(self.fd, sub_path, 0) catch return e;
+                    const is_dir = fstat.mode & os.S_IFMT == os.S_IFDIR;
+                    return if (is_dir) error.IsDir else e;
+                },
+                else => return e,
+            },
             else => |e| return e,
         };
     }
@@ -1122,6 +1132,16 @@ pub const Dir = struct {
     pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
         os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {
             error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
+            error.AccessDenied => |e| switch (builtin.os.tag) {
+                // non-Linux POSIX systems return EPERM when trying to delete a directory, so
+                // we need to handle that case specifically and translate the error
+                .macosx, .ios, .freebsd, .netbsd, .dragonfly => {
+                    const fstat = os.fstatatZ(self.fd, sub_path_c, 0) catch return e;
+                    const is_dir = fstat.mode & os.S_IFMT == os.S_IFDIR;
+                    return if (is_dir) error.IsDir else e;
+                },
+                else => return e,
+            },
             else => |e| return e,
         };
     }