Commit 3ab5e6b1a9
Changed files (3)
lib
lib/std/os/test.zig
@@ -80,8 +80,6 @@ test "readlink" {
{
const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "file.txt" });
const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink1" });
- std.debug.warn("\ntarget_path={}\n", .{target_path});
- std.debug.warn("symlink_path={}\n", .{symlink_path});
// Create symbolic link by path
try os.symlink(target_path, symlink_path, .{ .is_directory = false });
@@ -90,8 +88,6 @@ test "readlink" {
{
const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "subdir" });
const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink2" });
- std.debug.warn("\ntarget_path={}\n", .{target_path});
- std.debug.warn("symlink_path={}\n", .{symlink_path});
// Create symbolic link by path
try os.symlink(target_path, symlink_path, .{ .is_directory = true });
@@ -108,7 +104,6 @@ test "readlink" {
fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
const given = try os.readlink(symlink_path, buffer[0..]);
- std.debug.warn("given={}\n", .{given});
expect(mem.eql(u8, target_path, given));
}
lib/std/os/windows.zig
@@ -1263,40 +1263,80 @@ pub const PathSpace = struct {
pub fn span(self: PathSpace) [:0]const u16 {
return self.data[0..self.len :0];
}
+
+ fn ensureNtStyle(self: *PathSpace) void {
+ // > File I/O functions in the Windows API convert "/" to "\" as part of
+ // > converting the name to an NT-style name, except when using the "\\?\"
+ // > prefix as detailed in the following sections.
+ // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
+ // Because we want the larger maximum path length for absolute paths, we
+ // convert forward slashes to backward slashes here.
+ for (self.data[0..self.len]) |*elem| {
+ if (elem.* == '/') {
+ elem.* = '\\';
+ }
+ }
+ self.data[self.len] = 0;
+ }
};
+/// Same as `sliceToPrefixedFileW` but accepts a pointer
+/// to a null-terminated path.
pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {
return sliceToPrefixedFileW(mem.spanZ(s));
}
+/// Same as `sliceToWin32PrefixedFileW` but accepts a pointer
+/// to a null-terminated path.
+pub fn cStrToWin32PrefixedFileW(s: [*:0]const u8) !PathSpace {
+ return sliceToWin32PrefixedFileW(mem.spanZ(s));
+}
+
+/// Converts the path `s` to WTF16, null-terminated. If the path is absolute,
+/// it will get NT-style prefix `\??\` prepended automatically. For prepending
+/// Win32-style prefix, see `sliceToWin32PrefixedFileW` instead.
pub fn sliceToPrefixedFileW(s: []const u8) !PathSpace {
// TODO https://github.com/ziglang/zig/issues/2765
var path_space: PathSpace = undefined;
- for (s) |byte| {
+ const prefix_index: usize = if (mem.startsWith(u8, s, "\\??\\")) 4 else 0;
+ for (s[prefix_index..]) |byte| {
switch (byte) {
'*', '?', '"', '<', '>', '|' => return error.BadPathName,
else => {},
}
}
- const start_index = if (mem.startsWith(u8, s, "\\?") or !std.fs.path.isAbsolute(s)) 0 else blk: {
+ const start_index = if (prefix_index > 0 or !std.fs.path.isAbsolute(s)) 0 else blk: {
const prefix = [_]u16{ '\\', '?', '?', '\\' };
mem.copy(u16, path_space.data[0..], &prefix);
break :blk prefix.len;
};
path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);
if (path_space.len > path_space.data.len) return error.NameTooLong;
- // > File I/O functions in the Windows API convert "/" to "\" as part of
- // > converting the name to an NT-style name, except when using the "\\?\"
- // > prefix as detailed in the following sections.
- // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
- // Because we want the larger maximum path length for absolute paths, we
- // convert forward slashes to backward slashes here.
- for (path_space.data[0..path_space.len]) |*elem| {
- if (elem.* == '/') {
- elem.* = '\\';
+ path_space.ensureNtStyle();
+ return path_space;
+}
+
+/// Converts the path `s` to WTF16, null-terminated. If the path is absolute,
+/// it will get Win32-style extended prefix `\\?\` prepended automatically. For prepending
+/// NT-style prefix, see `sliceToPrefixedFileW` instead.
+pub fn sliceToWin32PrefixedFileW(s: []const u8) !PathSpace {
+ // TODO https://github.com/ziglang/zig/issues/2765
+ var path_space: PathSpace = undefined;
+ const prefix_index: usize = if (mem.startsWith(u8, s, "\\\\?\\")) 4 else 0;
+ for (s[prefix_index..]) |byte| {
+ switch (byte) {
+ '*', '?', '"', '<', '>', '|' => return error.BadPathName,
+ else => {},
}
}
- path_space.data[path_space.len] = 0;
+ const start_index = if (prefix_index > 0 or !std.fs.path.isAbsolute(s)) 0 else blk: {
+ const prefix = [_]u16{ '\\', '\\', '?', '\\' };
+ mem.copy(u16, path_space.data[0..], &prefix);
+ break :blk prefix.len;
+ };
+ path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);
+ if (path_space.len > path_space.data.len) return error.NameTooLong;
+ path_space.ensureNtStyle();
return path_space;
}
@@ -1313,12 +1353,7 @@ pub fn wToPrefixedFileW(s: []const u16) !PathSpace {
path_space.len = start_index + s.len;
if (path_space.len > path_space.data.len) return error.NameTooLong;
mem.copy(u16, path_space.data[start_index..], s);
- for (path_space.data[0..path_space.len]) |*elem| {
- if (elem.* == '/') {
- elem.* = '\\';
- }
- }
- path_space.data[path_space.len] = 0;
+ path_space.ensureNtStyle();
return path_space;
}
lib/std/os.zig
@@ -1556,8 +1556,8 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8, flags: Symlin
@compileError("symlink is not supported in WASI; use symlinkat instead");
}
if (builtin.os.tag == .windows) {
- const target_path_w = try windows.sliceToPrefixedFileW(target_path);
- const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
+ const target_path_w = try windows.sliceToWin32PrefixedFileW(target_path);
+ const sym_link_path_w = try windows.sliceToWin32PrefixedFileW(sym_link_path);
return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr, flags);
}
const target_path_c = try toPosixPath(target_path);
@@ -1578,8 +1578,8 @@ pub fn symlinkW(target_path: [*:0]const u16, sym_link_path: [*:0]const u16, flag
/// See also `symlink`.
pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8, flags: SymlinkFlags) SymLinkError!void {
if (builtin.os.tag == .windows) {
- const target_path_w = try windows.cStrToPrefixedFileW(target_path);
- const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
+ const target_path_w = try windows.cStrToWin32PrefixedFileW(target_path);
+ const sym_link_path_w = try windows.cStrToWin32PrefixedFileW(sym_link_path);
return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr);
}
switch (errno(system.symlink(target_path, sym_link_path))) {
@@ -2382,7 +2382,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
if (builtin.os.tag == .wasi) {
@compileError("readlink is not supported in WASI; use readlinkat instead");
} else if (builtin.os.tag == .windows) {
- const file_path_w = try windows.sliceToPrefixedFileW(file_path);
+ const file_path_w = try windows.sliceToWin32PrefixedFileW(file_path);
return readlinkW(file_path_w.span().ptr, out_buffer);
} else {
const file_path_c = try toPosixPath(file_path);
@@ -2448,7 +2448,7 @@ fn parseReadlinkPath(path: []const u16, is_relative: bool, out_buffer: []u8) []u
/// Same as `readlink` except `file_path` is null-terminated.
pub fn readlinkZ(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.cStrToWin32PrefixedFileW(file_path);
return readlinkW(file_path_w.span().ptr, out_buffer);
}
const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);