authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-15 18:15:20+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-22 08:51:22+02:00
log3ab5e6b1a97160ddadb90d627ae127a62c3cbd96
treebefd4252e555fbca1a09079a7ad598d3fe69d989
parentcc9c5c5b0e7c37f96d7ea4c6bd22118ea72a0265

Ensure we use Win32 prefix in Win32 calls


3 files changed, 59 insertions(+), 29 deletions(-)

lib/std/os.zig+6-6
......@@ -1556,8 +1556,8 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8, flags: Symlin
15561556 @compileError("symlink is not supported in WASI; use symlinkat instead");
15571557 }
15581558 if (builtin.os.tag == .windows) {
1559 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
1560 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
1559 const target_path_w = try windows.sliceToWin32PrefixedFileW(target_path);
1560 const sym_link_path_w = try windows.sliceToWin32PrefixedFileW(sym_link_path);
15611561 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr, flags);
15621562 }
15631563 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
15781578/// See also `symlink`.
15791579pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8, flags: SymlinkFlags) SymLinkError!void {
15801580 if (builtin.os.tag == .windows) {
1581 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
1582 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
1581 const target_path_w = try windows.cStrToWin32PrefixedFileW(target_path);
1582 const sym_link_path_w = try windows.cStrToWin32PrefixedFileW(sym_link_path);
15831583 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr);
15841584 }
15851585 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 {
23822382 if (builtin.os.tag == .wasi) {
23832383 @compileError("readlink is not supported in WASI; use readlinkat instead");
23842384 } else if (builtin.os.tag == .windows) {
2385 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
2385 const file_path_w = try windows.sliceToWin32PrefixedFileW(file_path);
23862386 return readlinkW(file_path_w.span().ptr, out_buffer);
23872387 } else {
23882388 const file_path_c = try toPosixPath(file_path);
......@@ -2448,7 +2448,7 @@ fn parseReadlinkPath(path: []const u16, is_relative: bool, out_buffer: []u8) []u
24482448/// Same as `readlink` except `file_path` is null-terminated.
24492449pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
24502450 if (builtin.os.tag == .windows) {
2451 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
2451 const file_path_w = try windows.cStrToWin32PrefixedFileW(file_path);
24522452 return readlinkW(file_path_w.span().ptr, out_buffer);
24532453 }
24542454 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
lib/std/os/test.zig-5
......@@ -80,8 +80,6 @@ test "readlink" {
8080 {
8181 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "file.txt" });
8282 const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink1" });
83 std.debug.warn("\ntarget_path={}\n", .{target_path});
84 std.debug.warn("symlink_path={}\n", .{symlink_path});
8583
8684 // Create symbolic link by path
8785 try os.symlink(target_path, symlink_path, .{ .is_directory = false });
......@@ -90,8 +88,6 @@ test "readlink" {
9088 {
9189 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "subdir" });
9290 const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink2" });
93 std.debug.warn("\ntarget_path={}\n", .{target_path});
94 std.debug.warn("symlink_path={}\n", .{symlink_path});
9591
9692 // Create symbolic link by path
9793 try os.symlink(target_path, symlink_path, .{ .is_directory = true });
......@@ -108,7 +104,6 @@ test "readlink" {
108104fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
109105 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
110106 const given = try os.readlink(symlink_path, buffer[0..]);
111 std.debug.warn("given={}\n", .{given});
112107 expect(mem.eql(u8, target_path, given));
113108}
114109
lib/std/os/windows.zig+53-18
......@@ -1263,40 +1263,80 @@ pub const PathSpace = struct {
12631263 pub fn span(self: PathSpace) [:0]const u16 {
12641264 return self.data[0..self.len :0];
12651265 }
1266
1267 fn ensureNtStyle(self: *PathSpace) void {
1268 // > File I/O functions in the Windows API convert "/" to "\" as part of
1269 // > converting the name to an NT-style name, except when using the "\\?\"
1270 // > prefix as detailed in the following sections.
1271 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
1272 // Because we want the larger maximum path length for absolute paths, we
1273 // convert forward slashes to backward slashes here.
1274 for (self.data[0..self.len]) |*elem| {
1275 if (elem.* == '/') {
1276 elem.* = '\\';
1277 }
1278 }
1279 self.data[self.len] = 0;
1280 }
12661281};
12671282
1283/// Same as `sliceToPrefixedFileW` but accepts a pointer
1284/// to a null-terminated path.
12681285pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {
12691286 return sliceToPrefixedFileW(mem.spanZ(s));
12701287}
12711288
1289/// Same as `sliceToWin32PrefixedFileW` but accepts a pointer
1290/// to a null-terminated path.
1291pub fn cStrToWin32PrefixedFileW(s: [*:0]const u8) !PathSpace {
1292 return sliceToWin32PrefixedFileW(mem.spanZ(s));
1293}
1294
1295/// Converts the path `s` to WTF16, null-terminated. If the path is absolute,
1296/// it will get NT-style prefix `\??\` prepended automatically. For prepending
1297/// Win32-style prefix, see `sliceToWin32PrefixedFileW` instead.
12721298pub fn sliceToPrefixedFileW(s: []const u8) !PathSpace {
12731299 // TODO https://github.com/ziglang/zig/issues/2765
12741300 var path_space: PathSpace = undefined;
1275 for (s) |byte| {
1301 const prefix_index: usize = if (mem.startsWith(u8, s, "\\??\\")) 4 else 0;
1302 for (s[prefix_index..]) |byte| {
12761303 switch (byte) {
12771304 '*', '?', '"', '<', '>', '|' => return error.BadPathName,
12781305 else => {},
12791306 }
12801307 }
1281 const start_index = if (mem.startsWith(u8, s, "\\?") or !std.fs.path.isAbsolute(s)) 0 else blk: {
1308 const start_index = if (prefix_index > 0 or !std.fs.path.isAbsolute(s)) 0 else blk: {
12821309 const prefix = [_]u16{ '\\', '?', '?', '\\' };
12831310 mem.copy(u16, path_space.data[0..], &prefix);
12841311 break :blk prefix.len;
12851312 };
12861313 path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);
12871314 if (path_space.len > path_space.data.len) return error.NameTooLong;
1288 // > File I/O functions in the Windows API convert "/" to "\" as part of
1289 // > converting the name to an NT-style name, except when using the "\\?\"
1290 // > prefix as detailed in the following sections.
1291 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
1292 // Because we want the larger maximum path length for absolute paths, we
1293 // convert forward slashes to backward slashes here.
1294 for (path_space.data[0..path_space.len]) |*elem| {
1295 if (elem.* == '/') {
1296 elem.* = '\\';
1315 path_space.ensureNtStyle();
1316 return path_space;
1317}
1318
1319/// Converts the path `s` to WTF16, null-terminated. If the path is absolute,
1320/// it will get Win32-style extended prefix `\\?\` prepended automatically. For prepending
1321/// NT-style prefix, see `sliceToPrefixedFileW` instead.
1322pub fn sliceToWin32PrefixedFileW(s: []const u8) !PathSpace {
1323 // TODO https://github.com/ziglang/zig/issues/2765
1324 var path_space: PathSpace = undefined;
1325 const prefix_index: usize = if (mem.startsWith(u8, s, "\\\\?\\")) 4 else 0;
1326 for (s[prefix_index..]) |byte| {
1327 switch (byte) {
1328 '*', '?', '"', '<', '>', '|' => return error.BadPathName,
1329 else => {},
12971330 }
12981331 }
1299 path_space.data[path_space.len] = 0;
1332 const start_index = if (prefix_index > 0 or !std.fs.path.isAbsolute(s)) 0 else blk: {
1333 const prefix = [_]u16{ '\\', '\\', '?', '\\' };
1334 mem.copy(u16, path_space.data[0..], &prefix);
1335 break :blk prefix.len;
1336 };
1337 path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);
1338 if (path_space.len > path_space.data.len) return error.NameTooLong;
1339 path_space.ensureNtStyle();
13001340 return path_space;
13011341}
13021342
......@@ -1313,12 +1353,7 @@ pub fn wToPrefixedFileW(s: []const u16) !PathSpace {
13131353 path_space.len = start_index + s.len;
13141354 if (path_space.len > path_space.data.len) return error.NameTooLong;
13151355 mem.copy(u16, path_space.data[start_index..], s);
1316 for (path_space.data[0..path_space.len]) |*elem| {
1317 if (elem.* == '/') {
1318 elem.* = '\\';
1319 }
1320 }
1321 path_space.data[path_space.len] = 0;
1356 path_space.ensureNtStyle();
13221357 return path_space;
13231358}
13241359