diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-30 22:47:30 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-31 16:31:51 +0200 |
| commit | 8981b18fee9dc1db7faa8343d0d2151c3c0671fd (patch) | |
| tree | 57fccb7375a3ef130b153ed5c12755d1f1d85de9 /lib/std/os.zig | |
| parent | 66bbe4ec4c11839217d6a9d65771d60d45cd6bc1 (diff) | |
| download | zig-8981b18fee9dc1db7faa8343d0d2151c3c0671fd.tar.gz zig-8981b18fee9dc1db7faa8343d0d2151c3c0671fd.zip | |
Move delete file logic into windows.DeleteFile fn
This way, we can remove more `kernel32` calls such as `RemoveDirectoryW`
or `DeleteFileW`, and use `std.os.windows.DeleteFile` instead which
is purely NT-based.
Diffstat (limited to 'lib/std/os.zig')
| -rw-r--r-- | lib/std/os.zig | 89 |
1 files changed, 22 insertions, 67 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig index 664b6c35b9..0a21c98808 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1683,7 +1683,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { @compileError("unlink is not supported in WASI; use unlinkat instead"); } else if (builtin.os.tag == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); - return windows.DeleteFileW(file_path_w.span().ptr); + return unlinkW(file_path_w.span()); } else { const file_path_c = try toPosixPath(file_path); return unlinkZ(&file_path_c); @@ -1696,7 +1696,7 @@ pub const unlinkC = @compileError("deprecated: renamed to unlinkZ"); pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void { if (builtin.os.tag == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); - return windows.DeleteFileW(file_path_w.span().ptr); + return unlinkW(file_path_w.span()); } switch (errno(system.unlink(file_path))) { 0 => return, @@ -1717,6 +1717,11 @@ pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void { } } +/// Windows-only. Same as `unlink` except the parameter is null-terminated, WTF16 encoded. +pub fn unlinkW(file_path_w: []const u16) UnlinkError!void { + return windows.DeleteFile(file_path_w, .{ .dir = std.fs.cwd().fd }); +} + pub const UnlinkatError = UnlinkError || error{ /// When passing `AT_REMOVEDIR`, this error occurs when the named directory is not empty. DirNotEmpty, @@ -1727,7 +1732,7 @@ pub const UnlinkatError = UnlinkError || error{ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { if (builtin.os.tag == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); - return unlinkatW(dirfd, file_path_w.span().ptr, flags); + return unlinkatW(dirfd, file_path_w.span(), flags); } else if (builtin.os.tag == .wasi) { return unlinkatWasi(dirfd, file_path, flags); } else { @@ -1774,7 +1779,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { if (builtin.os.tag == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); - return unlinkatW(dirfd, file_path_w.span().ptr, flags); + return unlinkatW(dirfd, file_path_w.span(), flags); } switch (errno(system.unlinkat(dirfd, file_path_c, flags))) { 0 => return, @@ -1800,67 +1805,9 @@ pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatEr } /// Same as `unlinkat` but `sub_path_w` is UTF16LE, NT prefixed. Windows only. -pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatError!void { - const w = windows; - - const want_rmdir_behavior = (flags & AT_REMOVEDIR) != 0; - const create_options_flags = if (want_rmdir_behavior) - @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT) - else - @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_NON_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT); // would we ever want to delete the target instead? - - const path_len_bytes = @intCast(u16, mem.lenZ(sub_path_w) * 2); - var nt_name = w.UNICODE_STRING{ - .Length = path_len_bytes, - .MaximumLength = path_len_bytes, - // The Windows API makes this mutable, but it will not mutate here. - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), - }; - - if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { - // Windows does not recognize this, but it does work with empty string. - nt_name.Length = 0; - } - if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { - // Can't remove the parent directory with an open handle. - return error.FileBusy; - } - - var attr = w.OBJECT_ATTRIBUTES{ - .Length = @sizeOf(w.OBJECT_ATTRIBUTES), - .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd, - .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. - .ObjectName = &nt_name, - .SecurityDescriptor = null, - .SecurityQualityOfService = null, - }; - var io: w.IO_STATUS_BLOCK = undefined; - var tmp_handle: w.HANDLE = undefined; - var rc = w.ntdll.NtCreateFile( - &tmp_handle, - w.SYNCHRONIZE | w.DELETE, - &attr, - &io, - null, - 0, - w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE, - w.FILE_OPEN, - create_options_flags, - null, - 0, - ); - if (rc == .SUCCESS) { - rc = w.ntdll.NtClose(tmp_handle); - } - switch (rc) { - .SUCCESS => return, - .OBJECT_NAME_INVALID => unreachable, - .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, - .INVALID_PARAMETER => unreachable, - .FILE_IS_A_DIRECTORY => return error.IsDir, - .NOT_A_DIRECTORY => return error.NotDir, - else => return w.unexpectedStatus(rc), - } +pub fn unlinkatW(dirfd: fd_t, sub_path_w: []const u16, flags: u32) UnlinkatError!void { + const remove_dir = (flags & AT_REMOVEDIR) != 0; + return windows.DeleteFile(sub_path_w, .{ .dir = dirfd, .remove_dir = remove_dir }); } const RenameError = error{ @@ -2256,7 +2203,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { @compileError("rmdir is not supported in WASI; use unlinkat instead"); } else if (builtin.os.tag == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); - return windows.RemoveDirectoryW(dir_path_w.span().ptr); + return rmdirW(dir_path_w.span()); } else { const dir_path_c = try toPosixPath(dir_path); return rmdirZ(&dir_path_c); @@ -2269,7 +2216,7 @@ pub const rmdirC = @compileError("deprecated: renamed to rmdirZ"); pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void { if (builtin.os.tag == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); - return windows.RemoveDirectoryW(dir_path_w.span().ptr); + return rmdirW(dir_path_w.span()); } switch (errno(system.rmdir(dir_path))) { 0 => return, @@ -2290,6 +2237,14 @@ pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void { } } +/// Windows-only. Same as `rmdir` except the parameter is null-terminated, WTF16 encoded. +pub fn rmdirW(dir_path_w: []const u16) DeleteDirError!void { + return windows.DeleteFile(dir_path_w, .{ .dir = std.fs.cwd().fd, .remove_dir = true }) catch |err| switch (err) { + error.IsDir => unreachable, + else => |e| return e, + }; +} + pub const ChangeCurDirError = error{ AccessDenied, FileSystem, |
