mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
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
This commit is contained in:
parent
ac95cfe449
commit
3f9294c735
@ -961,7 +961,7 @@ fn windowsCreateProcessPathExt(
|
||||
try dir_buf.append(allocator, 0);
|
||||
defer dir_buf.shrinkRetainingCapacity(dir_path_len);
|
||||
const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0];
|
||||
const prefixed_path = try windows.wToPrefixedFileW(dir_path_z);
|
||||
const prefixed_path = try windows.wToPrefixedFileW(null, dir_path_z);
|
||||
break :dir fs.cwd().openDirW(prefixed_path.span().ptr, .{}, true) catch return error.FileNotFound;
|
||||
};
|
||||
defer dir.close();
|
||||
|
||||
@ -317,12 +317,12 @@ pub const WindowsDynLib = struct {
|
||||
dll: windows.HMODULE,
|
||||
|
||||
pub fn open(path: []const u8) !WindowsDynLib {
|
||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||
const path_w = try windows.sliceToPrefixedFileW(null, path);
|
||||
return openW(path_w.span().ptr);
|
||||
}
|
||||
|
||||
pub fn openZ(path_c: [*:0]const u8) !WindowsDynLib {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path_c);
|
||||
const path_w = try windows.cStrToPrefixedFileW(null, path_c);
|
||||
return openW(path_w.span().ptr);
|
||||
}
|
||||
|
||||
|
||||
@ -1118,7 +1118,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
}
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
@ -1156,7 +1156,7 @@ pub const Dir = struct {
|
||||
/// Same as `openFile` but the path parameter is null-terminated.
|
||||
pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
}
|
||||
|
||||
@ -1282,7 +1282,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
}
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
@ -1323,7 +1323,7 @@ pub const Dir = struct {
|
||||
/// Same as `createFile` but the path parameter is null-terminated.
|
||||
pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
}
|
||||
|
||||
@ -1513,7 +1513,7 @@ pub const Dir = struct {
|
||||
@compileError("realpath is not available on WASI");
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try os.windows.sliceToPrefixedFileW(pathname);
|
||||
const pathname_w = try os.windows.sliceToPrefixedFileW(self.fd, pathname);
|
||||
return self.realpathW(pathname_w.span(), out_buffer);
|
||||
}
|
||||
const pathname_c = try os.toPosixPath(pathname);
|
||||
@ -1524,7 +1524,7 @@ pub const Dir = struct {
|
||||
/// See also `Dir.realpath`, `realpathZ`.
|
||||
pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try os.windows.cStrToPrefixedFileW(pathname);
|
||||
const pathname_w = try os.windows.cStrToPrefixedFileW(self.fd, pathname);
|
||||
return self.realpathW(pathname_w.span(), out_buffer);
|
||||
}
|
||||
|
||||
@ -1656,7 +1656,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openDirW(sub_path_w.span().ptr, args, false);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return self.openDirWasi(sub_path, args);
|
||||
@ -1672,7 +1672,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openIterableDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!IterableDir {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return IterableDir{ .dir = try self.openDirW(sub_path_w.span().ptr, args, true) };
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return IterableDir{ .dir = try self.openDirWasi(sub_path, args) };
|
||||
@ -1732,7 +1732,7 @@ pub const Dir = struct {
|
||||
/// Same as `openDir` except the parameter is null-terminated.
|
||||
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions, iterable: bool) OpenError!Dir {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.openDirW(sub_path_w.span().ptr, args, iterable);
|
||||
}
|
||||
const symlink_flags: u32 = if (args.no_follow) os.O.NOFOLLOW else 0x0;
|
||||
@ -1831,7 +1831,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.deleteFileW(sub_path_w.span());
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
|
||||
@ -1894,7 +1894,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.deleteDirW(sub_path_w.span());
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
os.unlinkat(self.fd, sub_path, os.AT.REMOVEDIR) catch |err| switch (err) {
|
||||
@ -1959,8 +1959,8 @@ pub const Dir = struct {
|
||||
return self.symLinkWasi(target_path, sym_link_path, flags);
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
const target_path_w = try os.windows.sliceToPrefixedFileW(target_path);
|
||||
const sym_link_path_w = try os.windows.sliceToPrefixedFileW(sym_link_path);
|
||||
const target_path_w = try os.windows.sliceToPrefixedFileW(self.fd, target_path);
|
||||
const sym_link_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);
|
||||
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
||||
}
|
||||
const target_path_c = try os.toPosixPath(target_path);
|
||||
@ -1986,8 +1986,8 @@ pub const Dir = struct {
|
||||
flags: SymLinkFlags,
|
||||
) !void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const target_path_w = try os.windows.cStrToPrefixedFileW(target_path_c);
|
||||
const sym_link_path_w = try os.windows.cStrToPrefixedFileW(sym_link_path_c);
|
||||
const target_path_w = try os.windows.cStrToPrefixedFileW(self.fd, target_path_c);
|
||||
const sym_link_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sym_link_path_c);
|
||||
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
||||
}
|
||||
return os.symlinkatZ(target_path_c, self.fd, sym_link_path_c);
|
||||
@ -2012,7 +2012,7 @@ pub const Dir = struct {
|
||||
return self.readLinkWasi(sub_path, buffer);
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.readLinkW(sub_path_w.span(), buffer);
|
||||
}
|
||||
const sub_path_c = try os.toPosixPath(sub_path);
|
||||
@ -2027,7 +2027,7 @@ pub const Dir = struct {
|
||||
/// Same as `readLink`, except the `pathname` parameter is null-terminated.
|
||||
pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.readLinkW(sub_path_w.span(), buffer);
|
||||
}
|
||||
return os.readlinkatZ(self.fd, sub_path_c, buffer);
|
||||
@ -2501,7 +2501,10 @@ pub const Dir = struct {
|
||||
/// open it and handle the error for file not found.
|
||||
pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
const sub_path_w = os.windows.sliceToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
||||
error.AccessDenied => return error.PermissionDenied,
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.accessW(sub_path_w.span().ptr, flags);
|
||||
}
|
||||
const path_c = try os.toPosixPath(sub_path);
|
||||
@ -2511,7 +2514,10 @@ pub const Dir = struct {
|
||||
/// Same as `access` except the path parameter is null-terminated.
|
||||
pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
|
||||
const sub_path_w = os.windows.cStrToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
||||
error.AccessDenied => return error.PermissionDenied,
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.accessW(sub_path_w.span().ptr, flags);
|
||||
}
|
||||
const os_mode = switch (flags.mode) {
|
||||
@ -2894,8 +2900,8 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags
|
||||
assert(path.isAbsolute(target_path));
|
||||
assert(path.isAbsolute(sym_link_path));
|
||||
if (builtin.os.tag == .windows) {
|
||||
const target_path_w = try os.windows.sliceToPrefixedFileW(target_path);
|
||||
const sym_link_path_w = try os.windows.sliceToPrefixedFileW(sym_link_path);
|
||||
const target_path_w = try os.windows.sliceToPrefixedFileW(null, target_path);
|
||||
const sym_link_path_w = try os.windows.sliceToPrefixedFileW(null, sym_link_path);
|
||||
return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
||||
}
|
||||
return os.symlink(target_path, sym_link_path);
|
||||
@ -2945,7 +2951,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
const wide_slice = selfExePathW();
|
||||
const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
|
||||
const prefixed_path_w = try os.windows.wToPrefixedFileW(null, wide_slice);
|
||||
return cwd().openFileW(prefixed_path_w.span(), flags);
|
||||
}
|
||||
// Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
|
||||
|
||||
@ -1464,7 +1464,7 @@ pub const OpenError = error{
|
||||
/// See also `openZ`.
|
||||
pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
|
||||
return openW(file_path_w.span(), flags, perm);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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 {
|
||||
/// See also `open`.
|
||||
pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
|
||||
return openW(file_path_w.span(), flags, perm);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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
|
||||
/// See also `openatZ`.
|
||||
pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path);
|
||||
return openatW(dir_fd, file_path_w.span(), flags, mode);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
// `mode` is ignored on WASI, which does not support unix-style file permissions
|
||||
@ -1690,7 +1690,7 @@ pub fn openatWasi(
|
||||
/// See also `openat`.
|
||||
pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path);
|
||||
return openatW(dir_fd, file_path_w.span(), flags, mode);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);
|
||||
@ -2305,7 +2305,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
|
||||
else => |e| return e,
|
||||
};
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
|
||||
return unlinkW(file_path_w.span());
|
||||
} else {
|
||||
const file_path_c = try toPosixPath(file_path);
|
||||
@ -2316,7 +2316,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
|
||||
/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
|
||||
pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
|
||||
return unlinkW(file_path_w.span());
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return unlink(mem.sliceTo(file_path, 0));
|
||||
@ -2354,7 +2354,7 @@ pub const UnlinkatError = UnlinkError || error{
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path);
|
||||
return unlinkatW(dirfd, file_path_w.span(), flags);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return unlinkatWasi(dirfd, file_path, flags);
|
||||
@ -2399,7 +2399,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro
|
||||
/// Same as `unlinkat` but `file_path` is a null-terminated string.
|
||||
pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path_c);
|
||||
return unlinkatW(dirfd, file_path_w.span(), flags);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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 {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path);
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(new_path);
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(null, old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(null, new_path);
|
||||
return renameW(old_path_w.span().ptr, new_path_w.span().ptr);
|
||||
} else {
|
||||
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 {
|
||||
/// Same as `rename` except the parameters are null-terminated byte arrays.
|
||||
pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.cStrToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.cStrToPrefixedFileW(new_path);
|
||||
const old_path_w = try windows.cStrToPrefixedFileW(null, old_path);
|
||||
const new_path_w = try windows.cStrToPrefixedFileW(null, new_path);
|
||||
return renameW(old_path_w.span().ptr, new_path_w.span().ptr);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return rename(mem.sliceTo(old_path, 0), mem.sliceTo(new_path, 0));
|
||||
@ -2526,8 +2526,8 @@ pub fn renameat(
|
||||
new_path: []const u8,
|
||||
) RenameError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(new_path);
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(old_dir_fd, old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(new_dir_fd, new_path);
|
||||
return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path };
|
||||
@ -2576,8 +2576,8 @@ pub fn renameatZ(
|
||||
new_path: [*:0]const u8,
|
||||
) RenameError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.cStrToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.cStrToPrefixedFileW(new_path);
|
||||
const old_path_w = try windows.cStrToPrefixedFileW(old_dir_fd, old_path);
|
||||
const new_path_w = try windows.cStrToPrefixedFileW(new_dir_fd, new_path);
|
||||
return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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(
|
||||
|
||||
pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);
|
||||
const sub_dir_path_w = try windows.sliceToPrefixedFileW(dir_fd, sub_dir_path);
|
||||
return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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
|
||||
|
||||
pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_dir_path_w = try windows.cStrToPrefixedFileW(sub_dir_path);
|
||||
const sub_dir_path_w = try windows.cStrToPrefixedFileW(dir_fd, sub_dir_path);
|
||||
return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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 {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return mkdirat(wasi.AT.FDCWD, dir_path, mode);
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
|
||||
return mkdirW(dir_path_w.span(), mode);
|
||||
} else {
|
||||
const dir_path_c = try toPosixPath(dir_path);
|
||||
@ -2787,7 +2787,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
|
||||
/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
|
||||
pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path);
|
||||
return mkdirW(dir_path_w.span(), mode);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return mkdir(mem.sliceTo(dir_path, 0), mode);
|
||||
@ -2854,7 +2854,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
|
||||
else => |e| return e,
|
||||
};
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
|
||||
return rmdirW(dir_path_w.span());
|
||||
} else {
|
||||
const dir_path_c = try toPosixPath(dir_path);
|
||||
@ -2865,7 +2865,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
|
||||
/// Same as `rmdir` except the parameter is null-terminated.
|
||||
pub fn rmdirZ(dir_path: [*:0]const u8) DeleteDirError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path);
|
||||
return rmdirW(dir_path_w.span());
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return rmdir(mem.sliceTo(dir_path, 0));
|
||||
@ -3003,7 +3003,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return readlinkat(wasi.AT.FDCWD, file_path, out_buffer);
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
|
||||
return readlinkW(file_path_w.span(), out_buffer);
|
||||
} else {
|
||||
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
|
||||
return readlinkatWasi(dirfd, file_path, out_buffer);
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(dirfd, file_path);
|
||||
return readlinkatW(dirfd, file_path_w.span(), out_buffer);
|
||||
}
|
||||
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
|
||||
/// See also `readlinkat`.
|
||||
pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(dirfd, file_path);
|
||||
return readlinkatW(dirfd, file_path_w.span(), out_buffer);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return readlinkat(dirfd, mem.sliceTo(file_path, 0), out_buffer);
|
||||
@ -4443,7 +4443,10 @@ pub const AccessError = error{
|
||||
/// TODO currently this assumes `mode` is `F.OK` on Windows.
|
||||
pub fn access(path: []const u8, mode: u32) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||
const path_w = windows.sliceToPrefixedFileW(null, path) catch |err| switch (err) {
|
||||
error.AccessDenied => return error.PermissionDenied,
|
||||
else => |e| return e,
|
||||
};
|
||||
_ = try windows.GetFileAttributesW(path_w.span().ptr);
|
||||
return;
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
@ -4456,7 +4459,10 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
|
||||
/// Same as `access` except `path` is null-terminated.
|
||||
pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||
const path_w = windows.cStrToPrefixedFileW(null, path) catch |err| switch (err) {
|
||||
error.AccessDenied => return error.PermissionDenied,
|
||||
else => |e| return e,
|
||||
};
|
||||
_ = try windows.GetFileAttributesW(path_w.span().ptr);
|
||||
return;
|
||||
} 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
|
||||
/// TODO currently this ignores `mode` and `flags` on Windows.
|
||||
pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||
const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
|
||||
return faccessatW(dirfd, path_w.span().ptr, mode, flags);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
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
|
||||
/// Same as `faccessat` except the path parameter is null-terminated.
|
||||
pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||
const path_w = try windows.cStrToPrefixedFileW(dirfd, path);
|
||||
return faccessatW(dirfd, path_w.span().ptr, mode, flags);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags);
|
||||
@ -5079,7 +5085,7 @@ pub const RealPathError = error{
|
||||
/// See also `realpathZ` and `realpathW`.
|
||||
pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.sliceToPrefixedFileW(pathname);
|
||||
const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);
|
||||
return realpathW(pathname_w.span(), out_buffer);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
@compileError("WASI does not support os.realpath");
|
||||
@ -5091,7 +5097,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
|
||||
/// Same as `realpath` except `pathname` is null-terminated.
|
||||
pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.cStrToPrefixedFileW(pathname);
|
||||
const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);
|
||||
return realpathW(pathname_w.span(), out_buffer);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return realpath(mem.sliceTo(pathname, 0), out_buffer);
|
||||
|
||||
@ -170,7 +170,7 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C
|
||||
}
|
||||
|
||||
pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {
|
||||
const nameW = try sliceToPrefixedFileW(name);
|
||||
const nameW = try sliceToPrefixedFileW(null, name);
|
||||
return CreateEventExW(attributes, nameW.span().ptr, flags, desired_access);
|
||||
}
|
||||
|
||||
@ -1007,8 +1007,8 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
|
||||
pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
|
||||
|
||||
pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
|
||||
const old_path_w = try sliceToPrefixedFileW(old_path);
|
||||
const new_path_w = try sliceToPrefixedFileW(new_path);
|
||||
const old_path_w = try sliceToPrefixedFileW(null, old_path);
|
||||
const new_path_w = try sliceToPrefixedFileW(null, new_path);
|
||||
return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags);
|
||||
}
|
||||
|
||||
@ -1317,7 +1317,7 @@ pub const GetFileAttributesError = error{
|
||||
};
|
||||
|
||||
pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
|
||||
const filename_w = try sliceToPrefixedFileW(filename);
|
||||
const filename_w = try sliceToPrefixedFileW(null, filename);
|
||||
return GetFileAttributesW(filename_w.span().ptr);
|
||||
}
|
||||
|
||||
@ -2120,16 +2120,16 @@ pub fn normalizePath(comptime T: type, path: []T) RemoveDotDirsError!usize {
|
||||
|
||||
/// Same as `sliceToPrefixedFileW` but accepts a pointer
|
||||
/// to a null-terminated path.
|
||||
pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {
|
||||
return sliceToPrefixedFileW(mem.sliceTo(s, 0));
|
||||
pub fn cStrToPrefixedFileW(dir: ?HANDLE, s: [*:0]const u8) !PathSpace {
|
||||
return sliceToPrefixedFileW(dir, mem.sliceTo(s, 0));
|
||||
}
|
||||
|
||||
/// Same as `wToPrefixedFileW` but accepts a UTF-8 encoded path.
|
||||
pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace {
|
||||
pub fn sliceToPrefixedFileW(dir: ?HANDLE, path: []const u8) !PathSpace {
|
||||
var temp_path: PathSpace = undefined;
|
||||
temp_path.len = try std.unicode.utf8ToUtf16Le(&temp_path.data, path);
|
||||
temp_path.data[temp_path.len] = 0;
|
||||
return wToPrefixedFileW(temp_path.span());
|
||||
return wToPrefixedFileW(dir, temp_path.span());
|
||||
}
|
||||
|
||||
/// Converts the `path` to WTF16, null-terminated. If the path contains any
|
||||
@ -2139,11 +2139,11 @@ pub fn sliceToPrefixedFileW(path: []const u8) !PathSpace {
|
||||
/// Similar to RtlDosPathNameToNtPathName_U with a few differences:
|
||||
/// - Does not allocate on the heap.
|
||||
/// - Relative paths are kept as relative unless they contain too many ..
|
||||
/// components, in which case they are treated as drive-relative and resolved
|
||||
/// against the CWD.
|
||||
/// components, in which case they are resolved against the `dir` if it
|
||||
/// is non-null, or the CWD if it is null.
|
||||
/// - Special case device names like COM1, NUL, etc are not handled specially (TODO)
|
||||
/// - . and space are not stripped from the end of relative paths (potential TODO)
|
||||
pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {
|
||||
pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) !PathSpace {
|
||||
const nt_prefix = [_]u16{ '\\', '?', '?', '\\' };
|
||||
switch (getNamespacePrefix(u16, path)) {
|
||||
// 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 {
|
||||
|
||||
@memcpy(path_space.data[0..path.len], path);
|
||||
// Try to normalize, but if we get too many parent directories,
|
||||
// then this is effectively a 'drive relative' path, so we need to
|
||||
// start over and use RtlGetFullPathName_U instead.
|
||||
// then we need to start over and use RtlGetFullPathName_U instead.
|
||||
path_space.len = normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) {
|
||||
error.TooManyParentDirs => break :relative,
|
||||
};
|
||||
@ -2224,8 +2223,37 @@ pub fn wToPrefixedFileW(path: [:0]const u16) !PathSpace {
|
||||
else => nt_prefix.len,
|
||||
};
|
||||
const buf_len = @as(u32, @intCast(path_space.data.len - path_buf_offset));
|
||||
const path_to_get: [:0]const u16 = path_to_get: {
|
||||
// If dir is null, then we don't need to bother with GetFinalPathNameByHandle because
|
||||
// RtlGetFullPathName_U will resolve relative paths against the CWD for us.
|
||||
if (path_type != .relative or dir == null) {
|
||||
break :path_to_get path;
|
||||
}
|
||||
// We can also skip GetFinalPathNameByHandle if the handle matches
|
||||
// the handle returned by fs.cwd()
|
||||
if (dir.? == std.fs.cwd().fd) {
|
||||
break :path_to_get path;
|
||||
}
|
||||
// At this point, we know we have a relative path that had too many
|
||||
// `..` components to be resolved by normalizePath, so we need to
|
||||
// convert it into an absolute path and let RtlGetFullPathName_U
|
||||
// canonicalize it. We do this by getting the path of the `dir`
|
||||
// and appending the relative path to it.
|
||||
var dir_path_buf: [PATH_MAX_WIDE:0]u16 = undefined;
|
||||
const dir_path = try GetFinalPathNameByHandle(dir.?, .{}, &dir_path_buf);
|
||||
if (dir_path.len + 1 + path.len > PATH_MAX_WIDE) {
|
||||
return error.NameTooLong;
|
||||
}
|
||||
// We don't have to worry about potentially doubling up path separators
|
||||
// here since RtlGetFullPathName_U will handle canonicalizing it.
|
||||
dir_path_buf[dir_path.len] = '\\';
|
||||
@memcpy(dir_path_buf[dir_path.len + 1 ..][0..path.len], path);
|
||||
const full_len = dir_path.len + 1 + path.len;
|
||||
dir_path_buf[full_len] = 0;
|
||||
break :path_to_get dir_path_buf[0..full_len :0];
|
||||
};
|
||||
const path_byte_len = ntdll.RtlGetFullPathName_U(
|
||||
path.ptr,
|
||||
path_to_get.ptr,
|
||||
buf_len * 2,
|
||||
path_space.data[path_buf_offset..].ptr,
|
||||
null,
|
||||
|
||||
@ -28,7 +28,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !windows.PathSpace {
|
||||
fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path: []const u8) !void {
|
||||
const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);
|
||||
const expected_path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(expected_path);
|
||||
const actual_path = try windows.wToPrefixedFileW(path_utf16);
|
||||
const actual_path = try windows.wToPrefixedFileW(null, path_utf16);
|
||||
std.testing.expectEqualSlices(u16, expected_path_utf16, actual_path.span()) catch |e| {
|
||||
std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(actual_path.span()), std.unicode.fmtUtf16le(expected_path_utf16) });
|
||||
return e;
|
||||
@ -45,7 +45,7 @@ fn testToPrefixedFileWithOracle(comptime path: []const u8, comptime expected_pat
|
||||
/// Test that the Zig conversion matches the conversion that RtlDosPathNameToNtPathName_U does.
|
||||
fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void {
|
||||
const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path);
|
||||
const zig_result = try windows.wToPrefixedFileW(path_utf16);
|
||||
const zig_result = try windows.wToPrefixedFileW(null, path_utf16);
|
||||
const win32_api_result = try RtlDosPathNameToNtPathName_U(path_utf16);
|
||||
std.testing.expectEqualSlices(u16, win32_api_result.span(), zig_result.span()) catch |e| {
|
||||
std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16le(zig_result.span()), std.unicode.fmtUtf16le(win32_api_result.span()) });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user