From 14c3c47fb7315e6199751082f9ef544972bb13e6 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Fri, 26 Jun 2020 15:49:31 -0700 Subject: [PATCH] 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). --- lib/std/fs.zig | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 6cb7d478b2..c574737194 100644 --- a/lib/std/fs.zig +++ b/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, }; }