authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-08-11 14:19:59-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-08-11 18:58:40-07:00
log3f9294c73501f55bcba1fe8b5da1ad2f2b0af9e5
tree86fce350a6c04eeffbc28f9860865090e8115256
parentac95cfe4496a5504b42bf37b02f34eff390fe956

Windows: Fix `TooManyParentDirs` handling for paths that shouldn't be cwd-relative

Previously, a relative path like `..` would: - Attempt to be normalized (i.e. remove . and .. without any path resolution), but would error with TooManyParentDirs - This would make wToPrefixedFileW run it through `RtlGetFullPathName_U` to do the necessary path resolution, but `RtlGetFullPathName_U` always resolves relative paths relative to the CWD Instead, when TooManyParentDirs occurs, we now look up the path of the passed in `dir` (if it's non-null) and append the relative path to it before giving it to `RtlGetFullPathName_U`. If `dir` is null, then we just give it RtlGetFullPathName_U directly and let it resolve it relative to the CWD. Closes #16779

6 files changed, 112 insertions(+), 72 deletions(-)

lib/std/child_process.zig+1-1
...@@ -961,7 +961,7 @@ fn windowsCreateProcessPathExt(...@@ -961,7 +961,7 @@ fn windowsCreateProcessPathExt(
961 try dir_buf.append(allocator, 0);961 try dir_buf.append(allocator, 0);
962 defer dir_buf.shrinkRetainingCapacity(dir_path_len);962 defer dir_buf.shrinkRetainingCapacity(dir_path_len);
963 const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0];963 const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0];
964 const prefixed_path = try windows.wToPrefixedFileW(dir_path_z);964 const prefixed_path = try windows.wToPrefixedFileW(null, dir_path_z);
965 break :dir fs.cwd().openDirW(prefixed_path.span().ptr, .{}, true) catch return error.FileNotFound;965 break :dir fs.cwd().openDirW(prefixed_path.span().ptr, .{}, true) catch return error.FileNotFound;
966 };966 };
967 defer dir.close();967 defer dir.close();
lib/std/dynamic_library.zig+2-2
...@@ -317,12 +317,12 @@ pub const WindowsDynLib = struct {...@@ -317,12 +317,12 @@ pub const WindowsDynLib = struct {
317 dll: windows.HMODULE,317 dll: windows.HMODULE,
318318
319 pub fn open(path: []const u8) !WindowsDynLib {319 pub fn open(path: []const u8) !WindowsDynLib {
320 const path_w = try windows.sliceToPrefixedFileW(path);320 const path_w = try windows.sliceToPrefixedFileW(null, path);
321 return openW(path_w.span().ptr);321 return openW(path_w.span().ptr);
322 }322 }
323323
324 pub fn openZ(path_c: [*:0]const u8) !WindowsDynLib {324 pub fn openZ(path_c: [*:0]const u8) !WindowsDynLib {
325 const path_w = try windows.cStrToPrefixedFileW(path_c);325 const path_w = try windows.cStrToPrefixedFileW(null, path_c);
326 return openW(path_w.span().ptr);326 return openW(path_w.span().ptr);
327 }327 }
328328
lib/std/fs.zig+28-22
...@@ -1118,7 +1118,7 @@ pub const Dir = struct {...@@ -1118,7 +1118,7 @@ pub const Dir = struct {
1118 /// Asserts that the path parameter has no null bytes.1118 /// Asserts that the path parameter has no null bytes.
1119 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {1119 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
1120 if (builtin.os.tag == .windows) {1120 if (builtin.os.tag == .windows) {
1121 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);1121 const path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1122 return self.openFileW(path_w.span(), flags);1122 return self.openFileW(path_w.span(), flags);
1123 }1123 }
1124 if (builtin.os.tag == .wasi and !builtin.link_libc) {1124 if (builtin.os.tag == .wasi and !builtin.link_libc) {
...@@ -1156,7 +1156,7 @@ pub const Dir = struct {...@@ -1156,7 +1156,7 @@ pub const Dir = struct {
1156 /// Same as `openFile` but the path parameter is null-terminated.1156 /// Same as `openFile` but the path parameter is null-terminated.
1157 pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {1157 pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
1158 if (builtin.os.tag == .windows) {1158 if (builtin.os.tag == .windows) {
1159 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);1159 const path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path);
1160 return self.openFileW(path_w.span(), flags);1160 return self.openFileW(path_w.span(), flags);
1161 }1161 }
11621162
...@@ -1282,7 +1282,7 @@ pub const Dir = struct {...@@ -1282,7 +1282,7 @@ pub const Dir = struct {
1282 /// Asserts that the path parameter has no null bytes.1282 /// Asserts that the path parameter has no null bytes.
1283 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {1283 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
1284 if (builtin.os.tag == .windows) {1284 if (builtin.os.tag == .windows) {
1285 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);1285 const path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1286 return self.createFileW(path_w.span(), flags);1286 return self.createFileW(path_w.span(), flags);
1287 }1287 }
1288 if (builtin.os.tag == .wasi and !builtin.link_libc) {1288 if (builtin.os.tag == .wasi and !builtin.link_libc) {
...@@ -1323,7 +1323,7 @@ pub const Dir = struct {...@@ -1323,7 +1323,7 @@ pub const Dir = struct {
1323 /// Same as `createFile` but the path parameter is null-terminated.1323 /// Same as `createFile` but the path parameter is null-terminated.
1324 pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {1324 pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
1325 if (builtin.os.tag == .windows) {1325 if (builtin.os.tag == .windows) {
1326 const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);1326 const path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1327 return self.createFileW(path_w.span(), flags);1327 return self.createFileW(path_w.span(), flags);
1328 }1328 }
13291329
...@@ -1513,7 +1513,7 @@ pub const Dir = struct {...@@ -1513,7 +1513,7 @@ pub const Dir = struct {
1513 @compileError("realpath is not available on WASI");1513 @compileError("realpath is not available on WASI");
1514 }1514 }
1515 if (builtin.os.tag == .windows) {1515 if (builtin.os.tag == .windows) {
1516 const pathname_w = try os.windows.sliceToPrefixedFileW(pathname);1516 const pathname_w = try os.windows.sliceToPrefixedFileW(self.fd, pathname);
1517 return self.realpathW(pathname_w.span(), out_buffer);1517 return self.realpathW(pathname_w.span(), out_buffer);
1518 }1518 }
1519 const pathname_c = try os.toPosixPath(pathname);1519 const pathname_c = try os.toPosixPath(pathname);
...@@ -1524,7 +1524,7 @@ pub const Dir = struct {...@@ -1524,7 +1524,7 @@ pub const Dir = struct {
1524 /// See also `Dir.realpath`, `realpathZ`.1524 /// See also `Dir.realpath`, `realpathZ`.
1525 pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {1525 pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {
1526 if (builtin.os.tag == .windows) {1526 if (builtin.os.tag == .windows) {
1527 const pathname_w = try os.windows.cStrToPrefixedFileW(pathname);1527 const pathname_w = try os.windows.cStrToPrefixedFileW(self.fd, pathname);
1528 return self.realpathW(pathname_w.span(), out_buffer);1528 return self.realpathW(pathname_w.span(), out_buffer);
1529 }1529 }
15301530
...@@ -1656,7 +1656,7 @@ pub const Dir = struct {...@@ -1656,7 +1656,7 @@ pub const Dir = struct {
1656 /// Asserts that the path parameter has no null bytes.1656 /// Asserts that the path parameter has no null bytes.
1657 pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {1657 pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
1658 if (builtin.os.tag == .windows) {1658 if (builtin.os.tag == .windows) {
1659 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1659 const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1660 return self.openDirW(sub_path_w.span().ptr, args, false);1660 return self.openDirW(sub_path_w.span().ptr, args, false);
1661 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1661 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1662 return self.openDirWasi(sub_path, args);1662 return self.openDirWasi(sub_path, args);
...@@ -1672,7 +1672,7 @@ pub const Dir = struct {...@@ -1672,7 +1672,7 @@ pub const Dir = struct {
1672 /// Asserts that the path parameter has no null bytes.1672 /// Asserts that the path parameter has no null bytes.
1673 pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir {1673 pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir {
1674 if (builtin.os.tag == .windows) {1674 if (builtin.os.tag == .windows) {
1675 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1675 const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1676 return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) };1676 return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) };
1677 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1677 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1678 return IterableDir{ .dir = try self.openDirWasi(sub_path, args) };1678 return IterableDir{ .dir = try self.openDirWasi(sub_path, args) };
...@@ -1732,7 +1732,7 @@ pub const Dir = struct {...@@ -1732,7 +1732,7 @@ pub const Dir = struct {
1732 /// Same as `openDir` except the parameter is null-terminated.1732 /// Same as `openDir` except the parameter is null-terminated.
1733 pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir {1733 pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir {
1734 if (builtin.os.tag == .windows) {1734 if (builtin.os.tag == .windows) {
1735 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);1735 const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1736 return self.openDirW(sub_path_w.span().ptr, args, iterable);1736 return self.openDirW(sub_path_w.span().ptr, args, iterable);
1737 }1737 }
1738 const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;1738 const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;
...@@ -1831,7 +1831,7 @@ pub const Dir = struct {...@@ -1831,7 +1831,7 @@ pub const Dir = struct {
1831 /// Asserts that the path parameter has no null bytes.1831 /// Asserts that the path parameter has no null bytes.
1832 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {1832 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
1833 if (builtin.os.tag == .windows) {1833 if (builtin.os.tag == .windows) {
1834 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1834 const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1835 return self.deleteFileW(sub_path_w.span());1835 return self.deleteFileW(sub_path_w.span());
1836 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1836 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1837 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {1837 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
...@@ -1894,7 +1894,7 @@ pub const Dir = struct {...@@ -1894,7 +1894,7 @@ pub const Dir = struct {
1894 /// Asserts that the path parameter has no null bytes.1894 /// Asserts that the path parameter has no null bytes.
1895 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {1895 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
1896 if (builtin.os.tag == .windows) {1896 if (builtin.os.tag == .windows) {
1897 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1897 const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
1898 return self.deleteDirW(sub_path_w.span());1898 return self.deleteDirW(sub_path_w.span());
1899 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1899 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1900 os.unlinkat(self.fd, sub_path, os.AT.REMOVEDIR) catch |err| switch (err) {1900 os.unlinkat(self.fd, sub_path, os.AT.REMOVEDIR) catch |err| switch (err) {
...@@ -1959,8 +1959,8 @@ pub const Dir = struct {...@@ -1959,8 +1959,8 @@ pub const Dir = struct {
1959 return self.symLinkWasi(target_path, sym_link_path, flags);1959 return self.symLinkWasi(target_path, sym_link_path, flags);
1960 }1960 }
1961 if (builtin.os.tag == .windows) {1961 if (builtin.os.tag == .windows) {
1962 const target_path_w = try os.windows.sliceToPrefixedFileW(target_path);1962 const target_path_w = try os.windows.sliceToPrefixedFileW(self.fd, target_path);
1963 const sym_link_path_w = try os.windows.sliceToPrefixedFileW(sym_link_path);1963 const sym_link_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);
1964 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);1964 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
1965 }1965 }
1966 const target_path_c = try os.toPosixPath(target_path);1966 const target_path_c = try os.toPosixPath(target_path);
...@@ -1986,8 +1986,8 @@ pub const Dir = struct {...@@ -1986,8 +1986,8 @@ pub const Dir = struct {
1986 flags: SymLinkFlags,1986 flags: SymLinkFlags,
1987 ) !void {1987 ) !void {
1988 if (builtin.os.tag == .windows) {1988 if (builtin.os.tag == .windows) {
1989 const target_path_w = try os.windows.cStrToPrefixedFileW(target_path_c);1989 const target_path_w = try os.windows.cStrToPrefixedFileW(self.fd, target_path_c);
1990 const sym_link_path_w = try os.windows.cStrToPrefixedFileW(sym_link_path_c);1990 const sym_link_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sym_link_path_c);
1991 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);1991 return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
1992 }1992 }
1993 return os.symlinkatZ(target_path_c, self.fd, sym_link_path_c);1993 return os.symlinkatZ(target_path_c, self.fd, sym_link_path_c);
...@@ -2012,7 +2012,7 @@ pub const Dir = struct {...@@ -2012,7 +2012,7 @@ pub const Dir = struct {
2012 return self.readLinkWasi(sub_path, buffer);2012 return self.readLinkWasi(sub_path, buffer);
2013 }2013 }
2014 if (builtin.os.tag == .windows) {2014 if (builtin.os.tag == .windows) {
2015 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);2015 const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
2016 return self.readLinkW(sub_path_w.span(), buffer);2016 return self.readLinkW(sub_path_w.span(), buffer);
2017 }2017 }
2018 const sub_path_c = try os.toPosixPath(sub_path);2018 const sub_path_c = try os.toPosixPath(sub_path);
...@@ -2027,7 +2027,7 @@ pub const Dir = struct {...@@ -2027,7 +2027,7 @@ pub const Dir = struct {
2027 /// Same as `readLink`, except the `pathname` parameter is null-terminated.2027 /// Same as `readLink`, except the `pathname` parameter is null-terminated.
2028 pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {2028 pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {
2029 if (builtin.os.tag == .windows) {2029 if (builtin.os.tag == .windows) {
2030 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);2030 const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
2031 return self.readLinkW(sub_path_w.span(), buffer);2031 return self.readLinkW(sub_path_w.span(), buffer);
2032 }2032 }
2033 return os.readlinkatZ(self.fd, sub_path_c, buffer);2033 return os.readlinkatZ(self.fd, sub_path_c, buffer);
...@@ -2501,7 +2501,10 @@ pub const Dir = struct {...@@ -2501,7 +2501,10 @@ pub const Dir = struct {
2501 /// open it and handle the error for file not found.2501 /// open it and handle the error for file not found.
2502 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {2502 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
2503 if (builtin.os.tag == .windows) {2503 if (builtin.os.tag == .windows) {
2504 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);2504 const sub_path_w = os.windows.sliceToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
2505 error.AccessDenied => return error.PermissionDenied,
2506 else => |e| return e,
2507 };
2505 return self.accessW(sub_path_w.span().ptr, flags);2508 return self.accessW(sub_path_w.span().ptr, flags);
2506 }2509 }
2507 const path_c = try os.toPosixPath(sub_path);2510 const path_c = try os.toPosixPath(sub_path);
...@@ -2511,7 +2514,10 @@ pub const Dir = struct {...@@ -2511,7 +2514,10 @@ pub const Dir = struct {
2511 /// Same as `access` except the path parameter is null-terminated.2514 /// Same as `access` except the path parameter is null-terminated.
2512 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {2515 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
2513 if (builtin.os.tag == .windows) {2516 if (builtin.os.tag == .windows) {
2514 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);2517 const sub_path_w = os.windows.cStrToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
2518 error.AccessDenied => return error.PermissionDenied,
2519 else => |e| return e,
2520 };
2515 return self.accessW(sub_path_w.span().ptr, flags);2521 return self.accessW(sub_path_w.span().ptr, flags);
2516 }2522 }
2517 const os_mode = switch (flags.mode) {2523 const os_mode = switch (flags.mode) {
...@@ -2894,8 +2900,8 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags...@@ -2894,8 +2900,8 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags
2894 assert(path.isAbsolute(target_path));2900 assert(path.isAbsolute(target_path));
2895 assert(path.isAbsolute(sym_link_path));2901 assert(path.isAbsolute(sym_link_path));
2896 if (builtin.os.tag == .windows) {2902 if (builtin.os.tag == .windows) {
2897 const target_path_w = try os.windows.sliceToPrefixedFileW(target_path);2903 const target_path_w = try os.windows.sliceToPrefixedFileW(null, target_path);
2898 const sym_link_path_w = try os.windows.sliceToPrefixedFileW(sym_link_path);2904 const sym_link_path_w = try os.windows.sliceToPrefixedFileW(null, sym_link_path);
2899 return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);2905 return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
2900 }2906 }
2901 return os.symlink(target_path, sym_link_path);2907 return os.symlink(target_path, sym_link_path);
...@@ -2945,7 +2951,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {...@@ -2945,7 +2951,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
2945 }2951 }
2946 if (builtin.os.tag == .windows) {2952 if (builtin.os.tag == .windows) {
2947 const wide_slice = selfExePathW();2953 const wide_slice = selfExePathW();
2948 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);2954 const prefixed_path_w = try os.windows.wToPrefixedFileW(null, wide_slice);
2949 return cwd().openFileW(prefixed_path_w.span(), flags);2955 return cwd().openFileW(prefixed_path_w.span(), flags);
2950 }2956 }
2951 // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately2957 // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
lib/std/os.zig+37-31
...@@ -1464,7 +1464,7 @@ pub const OpenError = error{...@@ -1464,7 +1464,7 @@ pub const OpenError = error{
1464/// See also `openZ`.1464/// See also `openZ`.
1465pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {1465pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
1466 if (builtin.os.tag == .windows) {1466 if (builtin.os.tag == .windows) {
1467 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1467 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
1468 return openW(file_path_w.span(), flags, perm);1468 return openW(file_path_w.span(), flags, perm);
1469 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1469 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1470 return openat(wasi.AT.FDCWD, file_path, flags, perm);1470 return openat(wasi.AT.FDCWD, file_path, flags, perm);
...@@ -1477,7 +1477,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {...@@ -1477,7 +1477,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
1477/// See also `open`.1477/// See also `open`.
1478pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t {1478pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t {
1479 if (builtin.os.tag == .windows) {1479 if (builtin.os.tag == .windows) {
1480 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1480 const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
1481 return openW(file_path_w.span(), flags, perm);1481 return openW(file_path_w.span(), flags, perm);
1482 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1482 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1483 return open(mem.sliceTo(file_path, 0), flags, perm);1483 return open(mem.sliceTo(file_path, 0), flags, perm);
...@@ -1568,7 +1568,7 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t...@@ -1568,7 +1568,7 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t
1568/// See also `openatZ`.1568/// See also `openatZ`.
1569pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {1569pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {
1570 if (builtin.os.tag == .windows) {1570 if (builtin.os.tag == .windows) {
1571 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1571 const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path);
1572 return openatW(dir_fd, file_path_w.span(), flags, mode);1572 return openatW(dir_fd, file_path_w.span(), flags, mode);
1573 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1573 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1574 // `mode` is ignored on WASI, which does not support unix-style file permissions1574 // `mode` is ignored on WASI, which does not support unix-style file permissions
...@@ -1690,7 +1690,7 @@ pub fn openatWasi(...@@ -1690,7 +1690,7 @@ pub fn openatWasi(
1690/// See also `openat`.1690/// See also `openat`.
1691pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {1691pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {
1692 if (builtin.os.tag == .windows) {1692 if (builtin.os.tag == .windows) {
1693 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1693 const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path);
1694 return openatW(dir_fd, file_path_w.span(), flags, mode);1694 return openatW(dir_fd, file_path_w.span(), flags, mode);
1695 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1695 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1696 return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);1696 return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);
...@@ -2305,7 +2305,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {...@@ -2305,7 +2305,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
2305 else => |e| return e,2305 else => |e| return e,
2306 };2306 };
2307 } else if (builtin.os.tag == .windows) {2307 } else if (builtin.os.tag == .windows) {
2308 const file_path_w = try windows.sliceToPrefixedFileW(file_path);2308 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
2309 return unlinkW(file_path_w.span());2309 return unlinkW(file_path_w.span());
2310 } else {2310 } else {
2311 const file_path_c = try toPosixPath(file_path);2311 const file_path_c = try toPosixPath(file_path);
...@@ -2316,7 +2316,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {...@@ -2316,7 +2316,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
2316/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.2316/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
2317pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void {2317pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void {
2318 if (builtin.os.tag == .windows) {2318 if (builtin.os.tag == .windows) {
2319 const file_path_w = try windows.cStrToPrefixedFileW(file_path);2319 const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
2320 return unlinkW(file_path_w.span());2320 return unlinkW(file_path_w.span());
2321 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2321 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2322 return unlink(mem.sliceTo(file_path, 0));2322 return unlink(mem.sliceTo(file_path, 0));
...@@ -2354,7 +2354,7 @@ pub const UnlinkatError = UnlinkError || error{...@@ -2354,7 +2354,7 @@ pub const UnlinkatError = UnlinkError || error{
2354/// Asserts that the path parameter has no null bytes.2354/// Asserts that the path parameter has no null bytes.
2355pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {2355pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
2356 if (builtin.os.tag == .windows) {2356 if (builtin.os.tag == .windows) {
2357 const file_path_w = try windows.sliceToPrefixedFileW(file_path);2357 const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path);
2358 return unlinkatW(dirfd, file_path_w.span(), flags);2358 return unlinkatW(dirfd, file_path_w.span(), flags);
2359 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2359 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2360 return unlinkatWasi(dirfd, file_path, flags);2360 return unlinkatWasi(dirfd, file_path, flags);
...@@ -2399,7 +2399,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro...@@ -2399,7 +2399,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro
2399/// Same as `unlinkat` but `file_path` is a null-terminated string.2399/// Same as `unlinkat` but `file_path` is a null-terminated string.
2400pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {2400pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {
2401 if (builtin.os.tag == .windows) {2401 if (builtin.os.tag == .windows) {
2402 const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);2402 const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path_c);
2403 return unlinkatW(dirfd, file_path_w.span(), flags);2403 return unlinkatW(dirfd, file_path_w.span(), flags);
2404 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2404 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2405 return unlinkat(dirfd, mem.sliceTo(file_path_c, 0), flags);2405 return unlinkat(dirfd, mem.sliceTo(file_path_c, 0), flags);
...@@ -2468,8 +2468,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {...@@ -2468,8 +2468,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
2468 if (builtin.os.tag == .wasi and !builtin.link_libc) {2468 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2469 return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path);2469 return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path);
2470 } else if (builtin.os.tag == .windows) {2470 } else if (builtin.os.tag == .windows) {
2471 const old_path_w = try windows.sliceToPrefixedFileW(old_path);2471 const old_path_w = try windows.sliceToPrefixedFileW(null, old_path);
2472 const new_path_w = try windows.sliceToPrefixedFileW(new_path);2472 const new_path_w = try windows.sliceToPrefixedFileW(null, new_path);
2473 return renameW(old_path_w.span().ptr, new_path_w.span().ptr);2473 return renameW(old_path_w.span().ptr, new_path_w.span().ptr);
2474 } else {2474 } else {
2475 const old_path_c = try toPosixPath(old_path);2475 const old_path_c = try toPosixPath(old_path);
...@@ -2481,8 +2481,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {...@@ -2481,8 +2481,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
2481/// Same as `rename` except the parameters are null-terminated byte arrays.2481/// Same as `rename` except the parameters are null-terminated byte arrays.
2482pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {2482pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {
2483 if (builtin.os.tag == .windows) {2483 if (builtin.os.tag == .windows) {
2484 const old_path_w = try windows.cStrToPrefixedFileW(old_path);2484 const old_path_w = try windows.cStrToPrefixedFileW(null, old_path);
2485 const new_path_w = try windows.cStrToPrefixedFileW(new_path);2485 const new_path_w = try windows.cStrToPrefixedFileW(null, new_path);
2486 return renameW(old_path_w.span().ptr, new_path_w.span().ptr);2486 return renameW(old_path_w.span().ptr, new_path_w.span().ptr);
2487 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2487 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2488 return rename(mem.sliceTo(old_path, 0), mem.sliceTo(new_path, 0));2488 return rename(mem.sliceTo(old_path, 0), mem.sliceTo(new_path, 0));
...@@ -2526,8 +2526,8 @@ pub fn renameat(...@@ -2526,8 +2526,8 @@ pub fn renameat(
2526 new_path: []const u8,2526 new_path: []const u8,
2527) RenameError!void {2527) RenameError!void {
2528 if (builtin.os.tag == .windows) {2528 if (builtin.os.tag == .windows) {
2529 const old_path_w = try windows.sliceToPrefixedFileW(old_path);2529 const old_path_w = try windows.sliceToPrefixedFileW(old_dir_fd, old_path);
2530 const new_path_w = try windows.sliceToPrefixedFileW(new_path);2530 const new_path_w = try windows.sliceToPrefixedFileW(new_dir_fd, new_path);
2531 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);2531 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
2532 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2532 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2533 const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path };2533 const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path };
...@@ -2576,8 +2576,8 @@ pub fn renameatZ(...@@ -2576,8 +2576,8 @@ pub fn renameatZ(
2576 new_path: [*:0]const u8,2576 new_path: [*:0]const u8,
2577) RenameError!void {2577) RenameError!void {
2578 if (builtin.os.tag == .windows) {2578 if (builtin.os.tag == .windows) {
2579 const old_path_w = try windows.cStrToPrefixedFileW(old_path);2579 const old_path_w = try windows.cStrToPrefixedFileW(old_dir_fd, old_path);
2580 const new_path_w = try windows.cStrToPrefixedFileW(new_path);2580 const new_path_w = try windows.cStrToPrefixedFileW(new_dir_fd, new_path);
2581 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);2581 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
2582 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2582 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2583 return renameat(old_dir_fd, mem.sliceTo(old_path, 0), new_dir_fd, mem.sliceTo(new_path, 0));2583 return renameat(old_dir_fd, mem.sliceTo(old_path, 0), new_dir_fd, mem.sliceTo(new_path, 0));
...@@ -2670,7 +2670,7 @@ pub fn renameatW(...@@ -2670,7 +2670,7 @@ pub fn renameatW(
26702670
2671pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {2671pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
2672 if (builtin.os.tag == .windows) {2672 if (builtin.os.tag == .windows) {
2673 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);2673 const sub_dir_path_w = try windows.sliceToPrefixedFileW(dir_fd, sub_dir_path);
2674 return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);2674 return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);
2675 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2675 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2676 return mkdiratWasi(dir_fd, sub_dir_path, mode);2676 return mkdiratWasi(dir_fd, sub_dir_path, mode);
...@@ -2705,7 +2705,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr...@@ -2705,7 +2705,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr
27052705
2706pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void {2706pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
2707 if (builtin.os.tag == .windows) {2707 if (builtin.os.tag == .windows) {
2708 const sub_dir_path_w = try windows.cStrToPrefixedFileW(sub_dir_path);2708 const sub_dir_path_w = try windows.cStrToPrefixedFileW(dir_fd, sub_dir_path);
2709 return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode);2709 return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode);
2710 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2710 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2711 return mkdirat(dir_fd, mem.sliceTo(sub_dir_path, 0), mode);2711 return mkdirat(dir_fd, mem.sliceTo(sub_dir_path, 0), mode);
...@@ -2776,7 +2776,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {...@@ -2776,7 +2776,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
2776 if (builtin.os.tag == .wasi and !builtin.link_libc) {2776 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2777 return mkdirat(wasi.AT.FDCWD, dir_path, mode);2777 return mkdirat(wasi.AT.FDCWD, dir_path, mode);
2778 } else if (builtin.os.tag == .windows) {2778 } else if (builtin.os.tag == .windows) {
2779 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);2779 const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
2780 return mkdirW(dir_path_w.span(), mode);2780 return mkdirW(dir_path_w.span(), mode);
2781 } else {2781 } else {
2782 const dir_path_c = try toPosixPath(dir_path);2782 const dir_path_c = try toPosixPath(dir_path);
...@@ -2787,7 +2787,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {...@@ -2787,7 +2787,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
2787/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.2787/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
2788pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {2788pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
2789 if (builtin.os.tag == .windows) {2789 if (builtin.os.tag == .windows) {
2790 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);2790 const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path);
2791 return mkdirW(dir_path_w.span(), mode);2791 return mkdirW(dir_path_w.span(), mode);
2792 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2792 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2793 return mkdir(mem.sliceTo(dir_path, 0), mode);2793 return mkdir(mem.sliceTo(dir_path, 0), mode);
...@@ -2854,7 +2854,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {...@@ -2854,7 +2854,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
2854 else => |e| return e,2854 else => |e| return e,
2855 };2855 };
2856 } else if (builtin.os.tag == .windows) {2856 } else if (builtin.os.tag == .windows) {
2857 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);2857 const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
2858 return rmdirW(dir_path_w.span());2858 return rmdirW(dir_path_w.span());
2859 } else {2859 } else {
2860 const dir_path_c = try toPosixPath(dir_path);2860 const dir_path_c = try toPosixPath(dir_path);
...@@ -2865,7 +2865,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {...@@ -2865,7 +2865,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
2865/// Same as `rmdir` except the parameter is null-terminated.2865/// Same as `rmdir` except the parameter is null-terminated.
2866pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void {2866pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void {
2867 if (builtin.os.tag == .windows) {2867 if (builtin.os.tag == .windows) {
2868 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);2868 const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path);
2869 return rmdirW(dir_path_w.span());2869 return rmdirW(dir_path_w.span());
2870 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {2870 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2871 return rmdir(mem.sliceTo(dir_path, 0));2871 return rmdir(mem.sliceTo(dir_path, 0));
...@@ -3003,7 +3003,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {...@@ -3003,7 +3003,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
3003 if (builtin.os.tag == .wasi and !builtin.link_libc) {3003 if (builtin.os.tag == .wasi and !builtin.link_libc) {
3004 return readlinkat(wasi.AT.FDCWD, file_path, out_buffer);3004 return readlinkat(wasi.AT.FDCWD, file_path, out_buffer);
3005 } else if (builtin.os.tag == .windows) {3005 } else if (builtin.os.tag == .windows) {
3006 const file_path_w = try windows.sliceToPrefixedFileW(file_path);3006 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
3007 return readlinkW(file_path_w.span(), out_buffer);3007 return readlinkW(file_path_w.span(), out_buffer);
3008 } else {3008 } else {
3009 const file_path_c = try toPosixPath(file_path);3009 const file_path_c = try toPosixPath(file_path);
...@@ -3049,7 +3049,7 @@ pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLink...@@ -3049,7 +3049,7 @@ pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLink
3049 return readlinkatWasi(dirfd, file_path, out_buffer);3049 return readlinkatWasi(dirfd, file_path, out_buffer);
3050 }3050 }
3051 if (builtin.os.tag == .windows) {3051 if (builtin.os.tag == .windows) {
3052 const file_path_w = try windows.sliceToPrefixedFileW(file_path);3052 const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path);
3053 return readlinkatW(dirfd, file_path_w.span(), out_buffer);3053 return readlinkatW(dirfd, file_path_w.span(), out_buffer);
3054 }3054 }
3055 const file_path_c = try toPosixPath(file_path);3055 const file_path_c = try toPosixPath(file_path);
...@@ -3086,7 +3086,7 @@ pub fn readlinkatW(dirfd: fd_t, file_path: []const u16, out_buffer: []u8) ReadLi...@@ -3086,7 +3086,7 @@ pub fn readlinkatW(dirfd: fd_t, file_path: []const u16, out_buffer: []u8) ReadLi
3086/// See also `readlinkat`.3086/// See also `readlinkat`.
3087pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {3087pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
3088 if (builtin.os.tag == .windows) {3088 if (builtin.os.tag == .windows) {
3089 const file_path_w = try windows.cStrToPrefixedFileW(file_path);3089 const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path);
3090 return readlinkatW(dirfd, file_path_w.span(), out_buffer);3090 return readlinkatW(dirfd, file_path_w.span(), out_buffer);
3091 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {3091 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
3092 return readlinkat(dirfd, mem.sliceTo(file_path, 0), out_buffer);3092 return readlinkat(dirfd, mem.sliceTo(file_path, 0), out_buffer);
...@@ -4443,7 +4443,10 @@ pub const AccessError = error{...@@ -4443,7 +4443,10 @@ pub const AccessError = error{
4443/// TODO currently this assumes `mode` is `F.OK` on Windows.4443/// TODO currently this assumes `mode` is `F.OK` on Windows.
4444pub fn access(path: []const u8, mode: u32) AccessError!void {4444pub fn access(path: []const u8, mode: u32) AccessError!void {
4445 if (builtin.os.tag == .windows) {4445 if (builtin.os.tag == .windows) {
4446 const path_w = try windows.sliceToPrefixedFileW(path);4446 const path_w = windows.sliceToPrefixedFileW(null, path) catch |err| switch (err) {
4447 error.AccessDenied => return error.PermissionDenied,
4448 else => |e| return e,
4449 };
4447 _ = try windows.GetFileAttributesW(path_w.span().ptr);4450 _ = try windows.GetFileAttributesW(path_w.span().ptr);
4448 return;4451 return;
4449 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {4452 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
...@@ -4456,7 +4459,10 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {...@@ -4456,7 +4459,10 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
4456/// Same as `access` except `path` is null-terminated.4459/// Same as `access` except `path` is null-terminated.
4457pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {4460pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
4458 if (builtin.os.tag == .windows) {4461 if (builtin.os.tag == .windows) {
4459 const path_w = try windows.cStrToPrefixedFileW(path);4462 const path_w = windows.cStrToPrefixedFileW(null, path) catch |err| switch (err) {
4463 error.AccessDenied => return error.PermissionDenied,
4464 else => |e| return e,
4465 };
4460 _ = try windows.GetFileAttributesW(path_w.span().ptr);4466 _ = try windows.GetFileAttributesW(path_w.span().ptr);
4461 return;4467 return;
4462 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {4468 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
...@@ -4500,7 +4506,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v...@@ -4500,7 +4506,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v
4500/// TODO currently this ignores `mode` and `flags` on Windows.4506/// TODO currently this ignores `mode` and `flags` on Windows.
4501pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {4507pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
4502 if (builtin.os.tag == .windows) {4508 if (builtin.os.tag == .windows) {
4503 const path_w = try windows.sliceToPrefixedFileW(path);4509 const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
4504 return faccessatW(dirfd, path_w.span().ptr, mode, flags);4510 return faccessatW(dirfd, path_w.span().ptr, mode, flags);
4505 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {4511 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
4506 var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path };4512 var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path };
...@@ -4543,7 +4549,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr...@@ -4543,7 +4549,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
4543/// Same as `faccessat` except the path parameter is null-terminated.4549/// Same as `faccessat` except the path parameter is null-terminated.
4544pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {4550pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {
4545 if (builtin.os.tag == .windows) {4551 if (builtin.os.tag == .windows) {
4546 const path_w = try windows.cStrToPrefixedFileW(path);4552 const path_w = try windows.cStrToPrefixedFileW(dirfd, path);
4547 return faccessatW(dirfd, path_w.span().ptr, mode, flags);4553 return faccessatW(dirfd, path_w.span().ptr, mode, flags);
4548 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {4554 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
4549 return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags);4555 return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags);
...@@ -5079,7 +5085,7 @@ pub const RealPathError = error{...@@ -5079,7 +5085,7 @@ pub const RealPathError = error{
5079/// See also `realpathZ` and `realpathW`.5085/// See also `realpathZ` and `realpathW`.
5080pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {5086pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
5081 if (builtin.os.tag == .windows) {5087 if (builtin.os.tag == .windows) {
5082 const pathname_w = try windows.sliceToPrefixedFileW(pathname);5088 const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);
5083 return realpathW(pathname_w.span(), out_buffer);5089 return realpathW(pathname_w.span(), out_buffer);
5084 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {5090 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
5085 @compileError("WASI does not support os.realpath");5091 @compileError("WASI does not support os.realpath");
...@@ -5091,7 +5097,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE...@@ -5091,7 +5097,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
5091/// Same as `realpath` except `pathname` is null-terminated.5097/// Same as `realpath` except `pathname` is null-terminated.
5092pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {5098pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
5093 if (builtin.os.tag == .windows) {5099 if (builtin.os.tag == .windows) {
5094 const pathname_w = try windows.cStrToPrefixedFileW(pathname);5100 const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);
5095 return realpathW(pathname_w.span(), out_buffer);5101 return realpathW(pathname_w.span(), out_buffer);
5096 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {5102 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
5097 return realpath(mem.sliceTo(pathname, 0), out_buffer);5103 return realpath(mem.sliceTo(pathname, 0), out_buffer);
lib/std/os/windows.zig+42-14
...@@ -170,7 +170,7 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C...@@ -170,7 +170,7 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C
170}170}
171171
172pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {172pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {
173 const nameW = try sliceToPrefixedFileW(name);173 const nameW = try sliceToPrefixedFileW(null, name);
174 return CreateEventExW(attributes, nameW.span().ptr, flags, desired_access);174 return CreateEventExW(attributes, nameW.span().ptr, flags, desired_access);
175}175}
176176
...@@ -1007,8 +1007,8 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil...@@ -1007,8 +1007,8 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
1007pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };1007pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
10081008
1009pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {1009pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
1010 const old_path_w = try sliceToPrefixedFileW(old_path);1010 const old_path_w = try sliceToPrefixedFileW(null, old_path);
1011 const new_path_w = try sliceToPrefixedFileW(new_path);1011 const new_path_w = try sliceToPrefixedFileW(null, new_path);
1012 return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags);1012 return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags);
1013}1013}
10141014
...@@ -1317,7 +1317,7 @@ pub const GetFileAttributesError = error{...@@ -1317,7 +1317,7 @@ pub const GetFileAttributesError = error{
1317};1317};
13181318
1319pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {1319pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
1320 const filename_w = try sliceToPrefixedFileW(filename);1320 const filename_w = try sliceToPrefixedFileW(null, filename);
1321 return GetFileAttributesW(filename_w.span().ptr);1321 return GetFileAttributesW(filename_w.span().ptr);
1322}1322}
13231323
...@@ -2120,16 +2120,16 @@ pub fn normalizePath(comptime T: type, path: []T) RemoveDotDirsError!usize {...@@ -2120,16 +2120,16 @@ pub fn normalizePath(comptime T: type, path: []T) RemoveDotDirsError!usize {
21202120
2121/// Same as `sliceToPrefixedFileW` but accepts a pointer2121/// Same as `sliceToPrefixedFileW` but accepts a pointer
2122/// to a null-terminated path.2122/// to a null-terminated path.
2123pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {2123pub fn cStrToPrefixedFileW(dir: ?HANDLE, s: [*:0]const u8) !PathSpace {
2124 return sliceToPrefixedFileW(mem.sliceTo(s, 0));2124 return sliceToPrefixedFileW(dir, mem.sliceTo(s, 0));
2125}2125}
21262126
2127/// Same as `wToPrefixedFileW` but accepts a UTF-8 encoded path.2127/// Same as `wToPrefixedFileW` but accepts a UTF-8 encoded path.
2128pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace {2128pub fn sliceToPrefixedFileW(dir: ?HANDLE, path: []const u8) !PathSpace {
2129 var temp_path: PathSpace = undefined;2129 var temp_path: PathSpace = undefined;
2130 temp_path.len = try std.unicode.utf8ToUtf16Le(&temp_path.data, path);2130 temp_path.len = try std.unicode.utf8ToUtf16Le(&temp_path.data, path);
2131 temp_path.data[temp_path.len] = 0;2131 temp_path.data[temp_path.len] = 0;
2132 return wToPrefixedFileW(temp_path.span());2132 return wToPrefixedFileW(dir, temp_path.span());
2133}2133}
21342134
2135/// Converts the `path` to WTF16, null-terminated. If the path contains any2135/// Converts the `path` to WTF16, null-terminated. If the path contains any
...@@ -2139,11 +2139,11 @@ pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace {...@@ -2139,11 +2139,11 @@ pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace {
2139/// Similar to RtlDosPathNameToNtPathName_U with a few differences:2139/// Similar to RtlDosPathNameToNtPathName_U with a few differences:
2140/// - Does not allocate on the heap.2140/// - Does not allocate on the heap.
2141/// - Relative paths are kept as relative unless they contain too many ..2141/// - Relative paths are kept as relative unless they contain too many ..
2142/// components, in which case they are treated as drive-relative and resolved2142/// components, in which case they are resolved against the `dir` if it
2143/// against the CWD.2143/// is non-null, or the CWD if it is null.
2144/// - Special case device names like COM1, NUL, etc are not handled specially (TODO)2144/// - Special case device names like COM1, NUL, etc are not handled specially (TODO)
2145/// - . and space are not stripped from the end of relative paths (potential TODO)2145/// - . and space are not stripped from the end of relative paths (potential TODO)
2146pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {2146pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) !PathSpace {
2147 const nt_prefix = [_]u16{ '\\', '?', '?', '\\' };2147 const nt_prefix = [_]u16{ '\\', '?', '?', '\\' };
2148 switch (getNamespacePrefix(u16, path)) {2148 switch (getNamespacePrefix(u16, path)) {
2149 // TODO: Figure out a way to design an API that can avoid the copy for .nt,2149 // TODO: Figure out a way to design an API that can avoid the copy for .nt,
...@@ -2194,8 +2194,7 @@ pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {...@@ -2194,8 +2194,7 @@ pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {
21942194
2195 @memcpy(path_space.data[0..path.len], path);2195 @memcpy(path_space.data[0..path.len], path);
2196 // Try to normalize, but if we get too many parent directories,2196 // Try to normalize, but if we get too many parent directories,
2197 // then this is effectively a 'drive relative' path, so we need to2197 // then we need to start over and use RtlGetFullPathName_U instead.
2198 // start over and use RtlGetFullPathName_U instead.
2199 path_space.len = normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) {2198 path_space.len = normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) {
2200 error.TooManyParentDirs => break :relative,2199 error.TooManyParentDirs => break :relative,
2201 };2200 };
...@@ -2224,8 +2223,37 @@ pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {...@@ -2224,8 +2223,37 @@ pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {
2224 else => nt_prefix.len,2223 else => nt_prefix.len,
2225 };2224 };
2226 const buf_len = @as(u32, @intCast(path_space.data.len - path_buf_offset));2225 const buf_len = @as(u32, @intCast(path_space.data.len - path_buf_offset));
2226 const path_to_get: [:0]const u16 = path_to_get: {
2227 // If dir is null, then we don't need to bother with GetFinalPathNameByHandle because
2228 // RtlGetFullPathName_U will resolve relative paths against the CWD for us.
2229 if (path_type != .relative or dir == null) {
2230 break :path_to_get path;
2231 }
2232 // We can also skip GetFinalPathNameByHandle if the handle matches
2233 // the handle returned by fs.cwd()
2234 if (dir.? == std.fs.cwd().fd) {
2235 break :path_to_get path;
2236 }
2237 // At this point, we know we have a relative path that had too many
2238 // `..` components to be resolved by normalizePath, so we need to
2239 // convert it into an absolute path and let RtlGetFullPathName_U
2240 // canonicalize it. We do this by getting the path of the `dir`
2241 // and appending the relative path to it.
2242 var dir_path_buf: [PATH_MAX_WIDE:0]u16 = undefined;
2243 const dir_path = try GetFinalPathNameByHandle(dir.?, .{}, &dir_path_buf);
2244 if (dir_path.len + 1 + path.len > PATH_MAX_WIDE) {
2245 return error.NameTooLong;
2246 }
2247 // We don't have to worry about potentially doubling up path separators
2248 // here since RtlGetFullPathName_U will handle canonicalizing it.
2249 dir_path_buf[dir_path.len] = '\\';
2250 @memcpy(dir_path_buf[dir_path.len + 1 ..][0..path.len], path);
2251 const full_len = dir_path.len + 1 + path.len;
2252 dir_path_buf[full_len] = 0;
2253 break :path_to_get dir_path_buf[0..full_len :0];
2254 };
2227 const path_byte_len = ntdll.RtlGetFullPathName_U(2255 const path_byte_len = ntdll.RtlGetFullPathName_U(
2228 path.ptr,2256 path_to_get.ptr,
2229 buf_len * 2,2257 buf_len * 2,
2230 path_space.data[path_buf_offset..].ptr,2258 path_space.data[path_buf_offset..].ptr,
2231 null,2259 null,
lib/std/os/windows/test.zig+2-2
...@@ -28,7 +28,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !windows.PathSpace {...@@ -28,7 +28,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !windows.PathSpace {
28fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path: []const u8) !void {28fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path: []const u8) !void {
29 const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);29 const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);
30 const expected_path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(expected_path);30 const expected_path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(expected_path);
31 const actual_path = try windows.wToPrefixedFileW(path_utf16);31 const actual_path = try windows.wToPrefixedFileW(null, path_utf16);
32 std.testing.expectEqualSlices(u16, expected_path_utf16, actual_path.span()) catch |e| {32 std.testing.expectEqualSlices(u16, expected_path_utf16, actual_path.span()) catch |e| {
33 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(actual_path.span()), std.unicode.fmtUtf16le(expected_path_utf16) });33 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(actual_path.span()), std.unicode.fmtUtf16le(expected_path_utf16) });
34 return e;34 return e;
...@@ -45,7 +45,7 @@ fn testToPrefixedFileWithOracle(comptime path: []const u8, comptime expected_pat...@@ -45,7 +45,7 @@ fn testToPrefixedFileWithOracle(comptime path: []const u8, comptime expected_pat
45/// Test that the Zig conversion matches the conversion that RtlDosPathNameToNtPathName_U does.45/// Test that the Zig conversion matches the conversion that RtlDosPathNameToNtPathName_U does.
46fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void {46fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void {
47 const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);47 const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);
48 const zig_result = try windows.wToPrefixedFileW(path_utf16);48 const zig_result = try windows.wToPrefixedFileW(null, path_utf16);
49 const win32_api_result = try RtlDosPathNameToNtPathName_U(path_utf16);49 const win32_api_result = try RtlDosPathNameToNtPathName_U(path_utf16);
50 std.testing.expectEqualSlices(u16, win32_api_result.span(), zig_result.span()) catch |e| {50 std.testing.expectEqualSlices(u16, win32_api_result.span(), zig_result.span()) catch |e| {
51 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(zig_result.span()), std.unicode.fmtUtf16le(win32_api_result.span()) });51 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(zig_result.span()), std.unicode.fmtUtf16le(win32_api_result.span()) });