| author | |
| committer | |
| log | 612b1772014aa016dddd4703818973c8dec6104f |
| tree | 05d6643fe7c475eef29a82f006016a25b2ba44df |
| parent | 1b88ce3b0cdeec7d23ded22e04aee8fc43f7bb5f |
Windows: Fix `TooManyParentDirs` handling for paths that shouldn't be cwd-relative7 files changed, 133 insertions(+), 72 deletions(-)
lib/std/child_process.zig+1-1| ... | @@ -963,7 +963,7 @@ fn windowsCreateProcessPathExt( | ... | @@ -963,7 +963,7 @@ fn windowsCreateProcessPathExt( |
| 963 | try dir_buf.append(allocator, 0); | 963 | try dir_buf.append(allocator, 0); |
| 964 | defer dir_buf.shrinkRetainingCapacity(dir_path_len); | 964 | defer dir_buf.shrinkRetainingCapacity(dir_path_len); |
| 965 | const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0]; | 965 | const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0]; |
| 966 | const prefixed_path = try windows.wToPrefixedFileW(dir_path_z); | 966 | const prefixed_path = try windows.wToPrefixedFileW(null, dir_path_z); |
| 967 | break :dir fs.cwd().openDirW(prefixed_path.span().ptr, .{}, true) catch return error.FileNotFound; | 967 | break :dir fs.cwd().openDirW(prefixed_path.span().ptr, .{}, true) catch return error.FileNotFound; |
| 968 | }; | 968 | }; |
| 969 | defer dir.close(); | 969 | defer dir.close(); |
lib/std/dynamic_library.zig+2-2| ... | @@ -319,12 +319,12 @@ pub const WindowsDynLib = struct { | ... | @@ -319,12 +319,12 @@ pub const WindowsDynLib = struct { |
| 319 | dll: windows.HMODULE, | 319 | dll: windows.HMODULE, |
| 320 | 320 | ||
| 321 | pub fn open(path: []const u8) !WindowsDynLib { | 321 | pub fn open(path: []const u8) !WindowsDynLib { |
| 322 | const path_w = try windows.sliceToPrefixedFileW(path); | 322 | const path_w = try windows.sliceToPrefixedFileW(null, path); |
| 323 | return openW(path_w.span().ptr); | 323 | return openW(path_w.span().ptr); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | pub fn openZ(path_c: [*:0]const u8) !WindowsDynLib { | 326 | pub fn openZ(path_c: [*:0]const u8) !WindowsDynLib { |
| 327 | const path_w = try windows.cStrToPrefixedFileW(path_c); | 327 | const path_w = try windows.cStrToPrefixedFileW(null, path_c); |
| 328 | return openW(path_w.span().ptr); | 328 | return openW(path_w.span().ptr); |
| 329 | } | 329 | } |
| 330 | 330 |
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 | } |
| 1162 | 1162 | ||
| ... | @@ -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 | } |
| 1329 | 1329 | ||
| ... | @@ -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 | } |
| 1530 | 1530 | ||
| ... | @@ -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 immediately | 2957 | // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately |
lib/std/fs/test.zig+21| ... | @@ -101,6 +101,27 @@ test "openDir cwd parent .." { | ... | @@ -101,6 +101,27 @@ test "openDir cwd parent .." { |
| 101 | defer dir.close(); | 101 | defer dir.close(); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | test "openDir non-cwd parent .." { | ||
| 105 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 106 | |||
| 107 | var tmp = tmpDir(.{}); | ||
| 108 | defer tmp.cleanup(); | ||
| 109 | |||
| 110 | var subdir = try tmp.dir.makeOpenPath("subdir", .{}); | ||
| 111 | defer subdir.close(); | ||
| 112 | |||
| 113 | var dir = try subdir.openDir("..", .{}); | ||
| 114 | defer dir.close(); | ||
| 115 | |||
| 116 | const expected_path = try tmp.dir.realpathAlloc(testing.allocator, "."); | ||
| 117 | defer testing.allocator.free(expected_path); | ||
| 118 | |||
| 119 | const actual_path = try dir.realpathAlloc(testing.allocator, "."); | ||
| 120 | defer testing.allocator.free(actual_path); | ||
| 121 | |||
| 122 | try testing.expectEqualStrings(expected_path, actual_path); | ||
| 123 | } | ||
| 124 | |||
| 104 | test "readLinkAbsolute" { | 125 | test "readLinkAbsolute" { |
| 105 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 126 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 106 | 127 |
lib/std/os.zig+37-31| ... | @@ -1467,7 +1467,7 @@ pub const OpenError = error{ | ... | @@ -1467,7 +1467,7 @@ pub const OpenError = error{ |
| 1467 | /// See also `openZ`. | 1467 | /// See also `openZ`. |
| 1468 | pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { | 1468 | pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { |
| 1469 | if (builtin.os.tag == .windows) { | 1469 | if (builtin.os.tag == .windows) { |
| 1470 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 1470 | const file_path_w = try windows.sliceToPrefixedFileW(null, file_path); |
| 1471 | return openW(file_path_w.span(), flags, perm); | 1471 | return openW(file_path_w.span(), flags, perm); |
| 1472 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 1472 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1473 | return openat(wasi.AT.FDCWD, file_path, flags, perm); | 1473 | return openat(wasi.AT.FDCWD, file_path, flags, perm); |
| ... | @@ -1480,7 +1480,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { | ... | @@ -1480,7 +1480,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { |
| 1480 | /// See also `open`. | 1480 | /// See also `open`. |
| 1481 | pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t { | 1481 | pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t { |
| 1482 | if (builtin.os.tag == .windows) { | 1482 | if (builtin.os.tag == .windows) { |
| 1483 | const file_path_w = try windows.cStrToPrefixedFileW(file_path); | 1483 | const file_path_w = try windows.cStrToPrefixedFileW(null, file_path); |
| 1484 | return openW(file_path_w.span(), flags, perm); | 1484 | return openW(file_path_w.span(), flags, perm); |
| 1485 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 1485 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1486 | return open(mem.sliceTo(file_path, 0), flags, perm); | 1486 | return open(mem.sliceTo(file_path, 0), flags, perm); |
| ... | @@ -1571,7 +1571,7 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t | ... | @@ -1571,7 +1571,7 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t |
| 1571 | /// See also `openatZ`. | 1571 | /// See also `openatZ`. |
| 1572 | pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { | 1572 | pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 1573 | if (builtin.os.tag == .windows) { | 1573 | if (builtin.os.tag == .windows) { |
| 1574 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 1574 | const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path); |
| 1575 | return openatW(dir_fd, file_path_w.span(), flags, mode); | 1575 | return openatW(dir_fd, file_path_w.span(), flags, mode); |
| 1576 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 1576 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1577 | // `mode` is ignored on WASI, which does not support unix-style file permissions | 1577 | // `mode` is ignored on WASI, which does not support unix-style file permissions |
| ... | @@ -1693,7 +1693,7 @@ pub fn openatWasi( | ... | @@ -1693,7 +1693,7 @@ pub fn openatWasi( |
| 1693 | /// See also `openat`. | 1693 | /// See also `openat`. |
| 1694 | pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { | 1694 | pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 1695 | if (builtin.os.tag == .windows) { | 1695 | if (builtin.os.tag == .windows) { |
| 1696 | const file_path_w = try windows.cStrToPrefixedFileW(file_path); | 1696 | const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path); |
| 1697 | return openatW(dir_fd, file_path_w.span(), flags, mode); | 1697 | return openatW(dir_fd, file_path_w.span(), flags, mode); |
| 1698 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 1698 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 1699 | return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode); | 1699 | return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode); |
| ... | @@ -2308,7 +2308,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { | ... | @@ -2308,7 +2308,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { |
| 2308 | else => |e| return e, | 2308 | else => |e| return e, |
| 2309 | }; | 2309 | }; |
| 2310 | } else if (builtin.os.tag == .windows) { | 2310 | } else if (builtin.os.tag == .windows) { |
| 2311 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 2311 | const file_path_w = try windows.sliceToPrefixedFileW(null, file_path); |
| 2312 | return unlinkW(file_path_w.span()); | 2312 | return unlinkW(file_path_w.span()); |
| 2313 | } else { | 2313 | } else { |
| 2314 | const file_path_c = try toPosixPath(file_path); | 2314 | const file_path_c = try toPosixPath(file_path); |
| ... | @@ -2319,7 +2319,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { | ... | @@ -2319,7 +2319,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { |
| 2319 | /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. | 2319 | /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. |
| 2320 | pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void { | 2320 | pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void { |
| 2321 | if (builtin.os.tag == .windows) { | 2321 | if (builtin.os.tag == .windows) { |
| 2322 | const file_path_w = try windows.cStrToPrefixedFileW(file_path); | 2322 | const file_path_w = try windows.cStrToPrefixedFileW(null, file_path); |
| 2323 | return unlinkW(file_path_w.span()); | 2323 | return unlinkW(file_path_w.span()); |
| 2324 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2324 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2325 | return unlink(mem.sliceTo(file_path, 0)); | 2325 | return unlink(mem.sliceTo(file_path, 0)); |
| ... | @@ -2357,7 +2357,7 @@ pub const UnlinkatError = UnlinkError || error{ | ... | @@ -2357,7 +2357,7 @@ pub const UnlinkatError = UnlinkError || error{ |
| 2357 | /// Asserts that the path parameter has no null bytes. | 2357 | /// Asserts that the path parameter has no null bytes. |
| 2358 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { | 2358 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { |
| 2359 | if (builtin.os.tag == .windows) { | 2359 | if (builtin.os.tag == .windows) { |
| 2360 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 2360 | const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path); |
| 2361 | return unlinkatW(dirfd, file_path_w.span(), flags); | 2361 | return unlinkatW(dirfd, file_path_w.span(), flags); |
| 2362 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2362 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2363 | return unlinkatWasi(dirfd, file_path, flags); | 2363 | return unlinkatWasi(dirfd, file_path, flags); |
| ... | @@ -2402,7 +2402,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro | ... | @@ -2402,7 +2402,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro |
| 2402 | /// Same as `unlinkat` but `file_path` is a null-terminated string. | 2402 | /// Same as `unlinkat` but `file_path` is a null-terminated string. |
| 2403 | pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { | 2403 | pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { |
| 2404 | if (builtin.os.tag == .windows) { | 2404 | if (builtin.os.tag == .windows) { |
| 2405 | const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); | 2405 | const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path_c); |
| 2406 | return unlinkatW(dirfd, file_path_w.span(), flags); | 2406 | return unlinkatW(dirfd, file_path_w.span(), flags); |
| 2407 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2407 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2408 | return unlinkat(dirfd, mem.sliceTo(file_path_c, 0), flags); | 2408 | return unlinkat(dirfd, mem.sliceTo(file_path_c, 0), flags); |
| ... | @@ -2471,8 +2471,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { | ... | @@ -2471,8 +2471,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { |
| 2471 | if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2471 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2472 | return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path); | 2472 | return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path); |
| 2473 | } else if (builtin.os.tag == .windows) { | 2473 | } else if (builtin.os.tag == .windows) { |
| 2474 | const old_path_w = try windows.sliceToPrefixedFileW(old_path); | 2474 | const old_path_w = try windows.sliceToPrefixedFileW(null, old_path); |
| 2475 | const new_path_w = try windows.sliceToPrefixedFileW(new_path); | 2475 | const new_path_w = try windows.sliceToPrefixedFileW(null, new_path); |
| 2476 | return renameW(old_path_w.span().ptr, new_path_w.span().ptr); | 2476 | return renameW(old_path_w.span().ptr, new_path_w.span().ptr); |
| 2477 | } else { | 2477 | } else { |
| 2478 | const old_path_c = try toPosixPath(old_path); | 2478 | const old_path_c = try toPosixPath(old_path); |
| ... | @@ -2484,8 +2484,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { | ... | @@ -2484,8 +2484,8 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { |
| 2484 | /// Same as `rename` except the parameters are null-terminated byte arrays. | 2484 | /// Same as `rename` except the parameters are null-terminated byte arrays. |
| 2485 | pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void { | 2485 | pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void { |
| 2486 | if (builtin.os.tag == .windows) { | 2486 | if (builtin.os.tag == .windows) { |
| 2487 | const old_path_w = try windows.cStrToPrefixedFileW(old_path); | 2487 | const old_path_w = try windows.cStrToPrefixedFileW(null, old_path); |
| 2488 | const new_path_w = try windows.cStrToPrefixedFileW(new_path); | 2488 | const new_path_w = try windows.cStrToPrefixedFileW(null, new_path); |
| 2489 | return renameW(old_path_w.span().ptr, new_path_w.span().ptr); | 2489 | return renameW(old_path_w.span().ptr, new_path_w.span().ptr); |
| 2490 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2490 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2491 | return rename(mem.sliceTo(old_path, 0), mem.sliceTo(new_path, 0)); | 2491 | return rename(mem.sliceTo(old_path, 0), mem.sliceTo(new_path, 0)); |
| ... | @@ -2529,8 +2529,8 @@ pub fn renameat( | ... | @@ -2529,8 +2529,8 @@ pub fn renameat( |
| 2529 | new_path: []const u8, | 2529 | new_path: []const u8, |
| 2530 | ) RenameError!void { | 2530 | ) RenameError!void { |
| 2531 | if (builtin.os.tag == .windows) { | 2531 | if (builtin.os.tag == .windows) { |
| 2532 | const old_path_w = try windows.sliceToPrefixedFileW(old_path); | 2532 | const old_path_w = try windows.sliceToPrefixedFileW(old_dir_fd, old_path); |
| 2533 | const new_path_w = try windows.sliceToPrefixedFileW(new_path); | 2533 | const new_path_w = try windows.sliceToPrefixedFileW(new_dir_fd, new_path); |
| 2534 | return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); | 2534 | return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); |
| 2535 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2535 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2536 | const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; | 2536 | const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; |
| ... | @@ -2579,8 +2579,8 @@ pub fn renameatZ( | ... | @@ -2579,8 +2579,8 @@ pub fn renameatZ( |
| 2579 | new_path: [*:0]const u8, | 2579 | new_path: [*:0]const u8, |
| 2580 | ) RenameError!void { | 2580 | ) RenameError!void { |
| 2581 | if (builtin.os.tag == .windows) { | 2581 | if (builtin.os.tag == .windows) { |
| 2582 | const old_path_w = try windows.cStrToPrefixedFileW(old_path); | 2582 | const old_path_w = try windows.cStrToPrefixedFileW(old_dir_fd, old_path); |
| 2583 | const new_path_w = try windows.cStrToPrefixedFileW(new_path); | 2583 | const new_path_w = try windows.cStrToPrefixedFileW(new_dir_fd, new_path); |
| 2584 | return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); | 2584 | return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); |
| 2585 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2585 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2586 | return renameat(old_dir_fd, mem.sliceTo(old_path, 0), new_dir_fd, mem.sliceTo(new_path, 0)); | 2586 | return renameat(old_dir_fd, mem.sliceTo(old_path, 0), new_dir_fd, mem.sliceTo(new_path, 0)); |
| ... | @@ -2673,7 +2673,7 @@ pub fn renameatW( | ... | @@ -2673,7 +2673,7 @@ pub fn renameatW( |
| 2673 | 2673 | ||
| 2674 | pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void { | 2674 | pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void { |
| 2675 | if (builtin.os.tag == .windows) { | 2675 | if (builtin.os.tag == .windows) { |
| 2676 | const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path); | 2676 | const sub_dir_path_w = try windows.sliceToPrefixedFileW(dir_fd, sub_dir_path); |
| 2677 | return mkdiratW(dir_fd, sub_dir_path_w.span(), mode); | 2677 | return mkdiratW(dir_fd, sub_dir_path_w.span(), mode); |
| 2678 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2678 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2679 | return mkdiratWasi(dir_fd, sub_dir_path, mode); | 2679 | return mkdiratWasi(dir_fd, sub_dir_path, mode); |
| ... | @@ -2708,7 +2708,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr | ... | @@ -2708,7 +2708,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr |
| 2708 | 2708 | ||
| 2709 | pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void { | 2709 | pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void { |
| 2710 | if (builtin.os.tag == .windows) { | 2710 | if (builtin.os.tag == .windows) { |
| 2711 | const sub_dir_path_w = try windows.cStrToPrefixedFileW(sub_dir_path); | 2711 | const sub_dir_path_w = try windows.cStrToPrefixedFileW(dir_fd, sub_dir_path); |
| 2712 | return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode); | 2712 | return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode); |
| 2713 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2713 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2714 | return mkdirat(dir_fd, mem.sliceTo(sub_dir_path, 0), mode); | 2714 | return mkdirat(dir_fd, mem.sliceTo(sub_dir_path, 0), mode); |
| ... | @@ -2779,7 +2779,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { | ... | @@ -2779,7 +2779,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { |
| 2779 | if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2779 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2780 | return mkdirat(wasi.AT.FDCWD, dir_path, mode); | 2780 | return mkdirat(wasi.AT.FDCWD, dir_path, mode); |
| 2781 | } else if (builtin.os.tag == .windows) { | 2781 | } else if (builtin.os.tag == .windows) { |
| 2782 | const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); | 2782 | const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path); |
| 2783 | return mkdirW(dir_path_w.span(), mode); | 2783 | return mkdirW(dir_path_w.span(), mode); |
| 2784 | } else { | 2784 | } else { |
| 2785 | const dir_path_c = try toPosixPath(dir_path); | 2785 | const dir_path_c = try toPosixPath(dir_path); |
| ... | @@ -2790,7 +2790,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { | ... | @@ -2790,7 +2790,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { |
| 2790 | /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. | 2790 | /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. |
| 2791 | pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { | 2791 | pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { |
| 2792 | if (builtin.os.tag == .windows) { | 2792 | if (builtin.os.tag == .windows) { |
| 2793 | const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); | 2793 | const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path); |
| 2794 | return mkdirW(dir_path_w.span(), mode); | 2794 | return mkdirW(dir_path_w.span(), mode); |
| 2795 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2795 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2796 | return mkdir(mem.sliceTo(dir_path, 0), mode); | 2796 | return mkdir(mem.sliceTo(dir_path, 0), mode); |
| ... | @@ -2857,7 +2857,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { | ... | @@ -2857,7 +2857,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { |
| 2857 | else => |e| return e, | 2857 | else => |e| return e, |
| 2858 | }; | 2858 | }; |
| 2859 | } else if (builtin.os.tag == .windows) { | 2859 | } else if (builtin.os.tag == .windows) { |
| 2860 | const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); | 2860 | const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path); |
| 2861 | return rmdirW(dir_path_w.span()); | 2861 | return rmdirW(dir_path_w.span()); |
| 2862 | } else { | 2862 | } else { |
| 2863 | const dir_path_c = try toPosixPath(dir_path); | 2863 | const dir_path_c = try toPosixPath(dir_path); |
| ... | @@ -2868,7 +2868,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { | ... | @@ -2868,7 +2868,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { |
| 2868 | /// Same as `rmdir` except the parameter is null-terminated. | 2868 | /// Same as `rmdir` except the parameter is null-terminated. |
| 2869 | pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void { | 2869 | pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void { |
| 2870 | if (builtin.os.tag == .windows) { | 2870 | if (builtin.os.tag == .windows) { |
| 2871 | const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); | 2871 | const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path); |
| 2872 | return rmdirW(dir_path_w.span()); | 2872 | return rmdirW(dir_path_w.span()); |
| 2873 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 2873 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 2874 | return rmdir(mem.sliceTo(dir_path, 0)); | 2874 | return rmdir(mem.sliceTo(dir_path, 0)); |
| ... | @@ -3006,7 +3006,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { | ... | @@ -3006,7 +3006,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { |
| 3006 | if (builtin.os.tag == .wasi and !builtin.link_libc) { | 3006 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 3007 | return readlinkat(wasi.AT.FDCWD, file_path, out_buffer); | 3007 | return readlinkat(wasi.AT.FDCWD, file_path, out_buffer); |
| 3008 | } else if (builtin.os.tag == .windows) { | 3008 | } else if (builtin.os.tag == .windows) { |
| 3009 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 3009 | const file_path_w = try windows.sliceToPrefixedFileW(null, file_path); |
| 3010 | return readlinkW(file_path_w.span(), out_buffer); | 3010 | return readlinkW(file_path_w.span(), out_buffer); |
| 3011 | } else { | 3011 | } else { |
| 3012 | const file_path_c = try toPosixPath(file_path); | 3012 | const file_path_c = try toPosixPath(file_path); |
| ... | @@ -3052,7 +3052,7 @@ pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLink | ... | @@ -3052,7 +3052,7 @@ pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLink |
| 3052 | return readlinkatWasi(dirfd, file_path, out_buffer); | 3052 | return readlinkatWasi(dirfd, file_path, out_buffer); |
| 3053 | } | 3053 | } |
| 3054 | if (builtin.os.tag == .windows) { | 3054 | if (builtin.os.tag == .windows) { |
| 3055 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 3055 | const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path); |
| 3056 | return readlinkatW(dirfd, file_path_w.span(), out_buffer); | 3056 | return readlinkatW(dirfd, file_path_w.span(), out_buffer); |
| 3057 | } | 3057 | } |
| 3058 | const file_path_c = try toPosixPath(file_path); | 3058 | const file_path_c = try toPosixPath(file_path); |
| ... | @@ -3089,7 +3089,7 @@ pub fn readlinkatW(dirfd: fd_t, file_path: []const u16, out_buffer: []u8) ReadLi | ... | @@ -3089,7 +3089,7 @@ pub fn readlinkatW(dirfd: fd_t, file_path: []const u16, out_buffer: []u8) ReadLi |
| 3089 | /// See also `readlinkat`. | 3089 | /// See also `readlinkat`. |
| 3090 | pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { | 3090 | pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { |
| 3091 | if (builtin.os.tag == .windows) { | 3091 | if (builtin.os.tag == .windows) { |
| 3092 | const file_path_w = try windows.cStrToPrefixedFileW(file_path); | 3092 | const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path); |
| 3093 | return readlinkatW(dirfd, file_path_w.span(), out_buffer); | 3093 | return readlinkatW(dirfd, file_path_w.span(), out_buffer); |
| 3094 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 3094 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 3095 | return readlinkat(dirfd, mem.sliceTo(file_path, 0), out_buffer); | 3095 | return readlinkat(dirfd, mem.sliceTo(file_path, 0), out_buffer); |
| ... | @@ -4446,7 +4446,10 @@ pub const AccessError = error{ | ... | @@ -4446,7 +4446,10 @@ pub const AccessError = error{ |
| 4446 | /// TODO currently this assumes `mode` is `F.OK` on Windows. | 4446 | /// TODO currently this assumes `mode` is `F.OK` on Windows. |
| 4447 | pub fn access(path: []const u8, mode: u32) AccessError!void { | 4447 | pub fn access(path: []const u8, mode: u32) AccessError!void { |
| 4448 | if (builtin.os.tag == .windows) { | 4448 | if (builtin.os.tag == .windows) { |
| 4449 | const path_w = try windows.sliceToPrefixedFileW(path); | 4449 | const path_w = windows.sliceToPrefixedFileW(null, path) catch |err| switch (err) { |
| 4450 | error.AccessDenied => return error.PermissionDenied, | ||
| 4451 | else => |e| return e, | ||
| 4452 | }; | ||
| 4450 | _ = try windows.GetFileAttributesW(path_w.span().ptr); | 4453 | _ = try windows.GetFileAttributesW(path_w.span().ptr); |
| 4451 | return; | 4454 | return; |
| 4452 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 4455 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| ... | @@ -4459,7 +4462,10 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { | ... | @@ -4459,7 +4462,10 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { |
| 4459 | /// Same as `access` except `path` is null-terminated. | 4462 | /// Same as `access` except `path` is null-terminated. |
| 4460 | pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { | 4463 | pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { |
| 4461 | if (builtin.os.tag == .windows) { | 4464 | if (builtin.os.tag == .windows) { |
| 4462 | const path_w = try windows.cStrToPrefixedFileW(path); | 4465 | const path_w = windows.cStrToPrefixedFileW(null, path) catch |err| switch (err) { |
| 4466 | error.AccessDenied => return error.PermissionDenied, | ||
| 4467 | else => |e| return e, | ||
| 4468 | }; | ||
| 4463 | _ = try windows.GetFileAttributesW(path_w.span().ptr); | 4469 | _ = try windows.GetFileAttributesW(path_w.span().ptr); |
| 4464 | return; | 4470 | return; |
| 4465 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 4471 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| ... | @@ -4503,7 +4509,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v | ... | @@ -4503,7 +4509,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v |
| 4503 | /// TODO currently this ignores `mode` and `flags` on Windows. | 4509 | /// TODO currently this ignores `mode` and `flags` on Windows. |
| 4504 | pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void { | 4510 | pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void { |
| 4505 | if (builtin.os.tag == .windows) { | 4511 | if (builtin.os.tag == .windows) { |
| 4506 | const path_w = try windows.sliceToPrefixedFileW(path); | 4512 | const path_w = try windows.sliceToPrefixedFileW(dirfd, path); |
| 4507 | return faccessatW(dirfd, path_w.span().ptr, mode, flags); | 4513 | return faccessatW(dirfd, path_w.span().ptr, mode, flags); |
| 4508 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 4514 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 4509 | var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path }; | 4515 | var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path }; |
| ... | @@ -4546,7 +4552,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr | ... | @@ -4546,7 +4552,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr |
| 4546 | /// Same as `faccessat` except the path parameter is null-terminated. | 4552 | /// Same as `faccessat` except the path parameter is null-terminated. |
| 4547 | pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void { | 4553 | pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void { |
| 4548 | if (builtin.os.tag == .windows) { | 4554 | if (builtin.os.tag == .windows) { |
| 4549 | const path_w = try windows.cStrToPrefixedFileW(path); | 4555 | const path_w = try windows.cStrToPrefixedFileW(dirfd, path); |
| 4550 | return faccessatW(dirfd, path_w.span().ptr, mode, flags); | 4556 | return faccessatW(dirfd, path_w.span().ptr, mode, flags); |
| 4551 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 4557 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 4552 | return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags); | 4558 | return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags); |
| ... | @@ -5082,7 +5088,7 @@ pub const RealPathError = error{ | ... | @@ -5082,7 +5088,7 @@ pub const RealPathError = error{ |
| 5082 | /// See also `realpathZ` and `realpathW`. | 5088 | /// See also `realpathZ` and `realpathW`. |
| 5083 | pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { | 5089 | pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 5084 | if (builtin.os.tag == .windows) { | 5090 | if (builtin.os.tag == .windows) { |
| 5085 | const pathname_w = try windows.sliceToPrefixedFileW(pathname); | 5091 | const pathname_w = try windows.sliceToPrefixedFileW(null, pathname); |
| 5086 | return realpathW(pathname_w.span(), out_buffer); | 5092 | return realpathW(pathname_w.span(), out_buffer); |
| 5087 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 5093 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 5088 | @compileError("WASI does not support os.realpath"); | 5094 | @compileError("WASI does not support os.realpath"); |
| ... | @@ -5094,7 +5100,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE | ... | @@ -5094,7 +5100,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE |
| 5094 | /// Same as `realpath` except `pathname` is null-terminated. | 5100 | /// Same as `realpath` except `pathname` is null-terminated. |
| 5095 | pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { | 5101 | pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 5096 | if (builtin.os.tag == .windows) { | 5102 | if (builtin.os.tag == .windows) { |
| 5097 | const pathname_w = try windows.cStrToPrefixedFileW(pathname); | 5103 | const pathname_w = try windows.cStrToPrefixedFileW(null, pathname); |
| 5098 | return realpathW(pathname_w.span(), out_buffer); | 5104 | return realpathW(pathname_w.span(), out_buffer); |
| 5099 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { | 5105 | } else if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 5100 | return realpath(mem.sliceTo(pathname, 0), out_buffer); | 5106 | 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 | } |
| 171 | 171 | ||
| 172 | pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE { | 172 | pub 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 | } |
| 176 | 176 | ||
| ... | @@ -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 |
| 1007 | pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected }; | 1007 | pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected }; |
| 1008 | 1008 | ||
| 1009 | pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void { | 1009 | pub 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 | } |
| 1014 | 1014 | ||
| ... | @@ -1317,7 +1317,7 @@ pub const GetFileAttributesError = error{ | ... | @@ -1317,7 +1317,7 @@ pub const GetFileAttributesError = error{ |
| 1317 | }; | 1317 | }; |
| 1318 | 1318 | ||
| 1319 | pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD { | 1319 | pub 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 | } |
| 1323 | 1323 | ||
| ... | @@ -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 { |
| 2120 | 2120 | ||
| 2121 | /// Same as `sliceToPrefixedFileW` but accepts a pointer | 2121 | /// Same as `sliceToPrefixedFileW` but accepts a pointer |
| 2122 | /// to a null-terminated path. | 2122 | /// to a null-terminated path. |
| 2123 | pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace { | 2123 | pub 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 | } |
| 2126 | 2126 | ||
| 2127 | /// Same as `wToPrefixedFileW` but accepts a UTF-8 encoded path. | 2127 | /// Same as `wToPrefixedFileW` but accepts a UTF-8 encoded path. |
| 2128 | pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace { | 2128 | pub 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 | } |
| 2134 | 2134 | ||
| 2135 | /// Converts the `path` to WTF16, null-terminated. If the path contains any | 2135 | /// 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 resolved | 2142 | /// 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) |
| 2146 | pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace { | 2146 | pub 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 { |
| 2194 | 2194 | ||
| 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 to | 2197 | // 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 { |
| 28 | fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path: []const u8) !void { | 28 | fn 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. |
| 46 | fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void { | 46 | fn 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()) }); |