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...@@ -1556,8 +1556,8 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8, flags: Symlin
1556 @compileError("symlink is not supported in WASI; use symlinkat instead");1556 @compileError("symlink is not supported in WASI; use symlinkat instead");
1557 }1557 }
1558 if (builtin.os.tag == .windows) {1558 if (builtin.os.tag == .windows) {
1559 const target_path_w = try windows.sliceToPrefixedFileW(target_path);1559 const target_path_w = try windows.sliceToWin32PrefixedFileW(target_path);
1560 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);1560 const sym_link_path_w = try windows.sliceToWin32PrefixedFileW(sym_link_path);
1561 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr, flags);1561 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr, flags);
1562 }1562 }
1563 const target_path_c = try toPosixPath(target_path);1563 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...@@ -1578,8 +1578,8 @@ pub fn symlinkW(target_path: [*:0]const u16, sym_link_path: [*:0]const u16, flag
1578/// See also `symlink`.1578/// See also `symlink`.
1579pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8, flags: SymlinkFlags) SymLinkError!void {1579pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8, flags: SymlinkFlags) SymLinkError!void {
1580 if (builtin.os.tag == .windows) {1580 if (builtin.os.tag == .windows) {
1581 const target_path_w = try windows.cStrToPrefixedFileW(target_path);1581 const target_path_w = try windows.cStrToWin32PrefixedFileW(target_path);
1582 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);1582 const sym_link_path_w = try windows.cStrToWin32PrefixedFileW(sym_link_path);
1583 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr);1583 return symlinkW(target_path_w.span().ptr, sym_link_path_w.span().ptr);
1584 }1584 }
1585 switch (errno(system.symlink(target_path, sym_link_path))) {1585 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 {...@@ -2382,7 +2382,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2382 if (builtin.os.tag == .wasi) {2382 if (builtin.os.tag == .wasi) {
2383 @compileError("readlink is not supported in WASI; use readlinkat instead");2383 @compileError("readlink is not supported in WASI; use readlinkat instead");
2384 } else if (builtin.os.tag == .windows) {2384 } 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);
2386 return readlinkW(file_path_w.span().ptr, out_buffer);2386 return readlinkW(file_path_w.span().ptr, out_buffer);
2387 } else {2387 } else {
2388 const file_path_c = try toPosixPath(file_path);2388 const file_path_c = try toPosixPath(file_path);
...@@ -2448,7 +2448,7 @@ fn parseReadlinkPath(path: []const u16, is_relative: bool, out_buffer: []u8) []u...@@ -2448,7 +2448,7 @@ fn parseReadlinkPath(path: []const u16, is_relative: bool, out_buffer: []u8) []u
2448/// Same as `readlink` except `file_path` is null-terminated.2448/// Same as `readlink` except `file_path` is null-terminated.
2449pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {2449pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
2450 if (builtin.os.tag == .windows) {2450 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);
2452 return readlinkW(file_path_w.span().ptr, out_buffer);2452 return readlinkW(file_path_w.span().ptr, out_buffer);
2453 }2453 }
2454 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);2454 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
lib/std/os/test.zig-5
...@@ -80,8 +80,6 @@ test "readlink" {...@@ -80,8 +80,6 @@ test "readlink" {
80 {80 {
81 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "file.txt" });81 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "file.txt" });
82 const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink1" });82 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
86 // Create symbolic link by path84 // Create symbolic link by path
87 try os.symlink(target_path, symlink_path, .{ .is_directory = false });85 try os.symlink(target_path, symlink_path, .{ .is_directory = false });
...@@ -90,8 +88,6 @@ test "readlink" {...@@ -90,8 +88,6 @@ test "readlink" {
90 {88 {
91 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "subdir" });89 const target_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "subdir" });
92 const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink2" });90 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
96 // Create symbolic link by path92 // Create symbolic link by path
97 try os.symlink(target_path, symlink_path, .{ .is_directory = true });93 try os.symlink(target_path, symlink_path, .{ .is_directory = true });
...@@ -108,7 +104,6 @@ test "readlink" {...@@ -108,7 +104,6 @@ test "readlink" {
108fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {104fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
109 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;105 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
110 const given = try os.readlink(symlink_path, buffer[0..]);106 const given = try os.readlink(symlink_path, buffer[0..]);
111 std.debug.warn("given={}\n", .{given});
112 expect(mem.eql(u8, target_path, given));107 expect(mem.eql(u8, target_path, given));
113}108}
114109
lib/std/os/windows.zig+53-18
...@@ -1263,40 +1263,80 @@ pub const PathSpace = struct {...@@ -1263,40 +1263,80 @@ pub const PathSpace = struct {
1263 pub fn span(self: PathSpace) [:0]const u16 {1263 pub fn span(self: PathSpace) [:0]const u16 {
1264 return self.data[0..self.len :0];1264 return self.data[0..self.len :0];
1265 }1265 }
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 }
1266};1281};
12671282
1283/// Same as `sliceToPrefixedFileW` but accepts a pointer
1284/// to a null-terminated path.
1268pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {1285pub fn cStrToPrefixedFileW(s: [*:0]const u8) !PathSpace {
1269 return sliceToPrefixedFileW(mem.spanZ(s));1286 return sliceToPrefixedFileW(mem.spanZ(s));
1270}1287}
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.
1272pub fn sliceToPrefixedFileW(s: []const u8) !PathSpace {1298pub fn sliceToPrefixedFileW(s: []const u8) !PathSpace {
1273 // TODO https://github.com/ziglang/zig/issues/27651299 // TODO https://github.com/ziglang/zig/issues/2765
1274 var path_space: PathSpace = undefined;1300 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| {
1276 switch (byte) {1303 switch (byte) {
1277 '*', '?', '"', '<', '>', '|' => return error.BadPathName,1304 '*', '?', '"', '<', '>', '|' => return error.BadPathName,
1278 else => {},1305 else => {},
1279 }1306 }
1280 }1307 }
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: {
1282 const prefix = [_]u16{ '\\', '?', '?', '\\' };1309 const prefix = [_]u16{ '\\', '?', '?', '\\' };
1283 mem.copy(u16, path_space.data[0..], &prefix);1310 mem.copy(u16, path_space.data[0..], &prefix);
1284 break :blk prefix.len;1311 break :blk prefix.len;
1285 };1312 };
1286 path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);1313 path_space.len = start_index + try std.unicode.utf8ToUtf16Le(path_space.data[start_index..], s);
1287 if (path_space.len > path_space.data.len) return error.NameTooLong;1314 if (path_space.len > path_space.data.len) return error.NameTooLong;
1288 // > File I/O functions in the Windows API convert "/" to "\" as part of1315 path_space.ensureNtStyle();
1289 // > converting the name to an NT-style name, except when using the "\\?\"1316 return path_space;
1290 // > prefix as detailed in the following sections.1317}
1291 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation1318
1292 // Because we want the larger maximum path length for absolute paths, we1319/// Converts the path `s` to WTF16, null-terminated. If the path is absolute,
1293 // convert forward slashes to backward slashes here.1320/// it will get Win32-style extended prefix `\\?\` prepended automatically. For prepending
1294 for (path_space.data[0..path_space.len]) |*elem| {1321/// NT-style prefix, see `sliceToPrefixedFileW` instead.
1295 if (elem.* == '/') {1322pub fn sliceToWin32PrefixedFileW(s: []const u8) !PathSpace {
1296 elem.* = '\\';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 => {},
1297 }1330 }
1298 }1331 }
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();
1300 return path_space;1340 return path_space;
1301}1341}
13021342
...@@ -1313,12 +1353,7 @@ pub fn wToPrefixedFileW(s: []const u16) !PathSpace {...@@ -1313,12 +1353,7 @@ pub fn wToPrefixedFileW(s: []const u16) !PathSpace {
1313 path_space.len = start_index + s.len;1353 path_space.len = start_index + s.len;
1314 if (path_space.len > path_space.data.len) return error.NameTooLong;1354 if (path_space.len > path_space.data.len) return error.NameTooLong;
1315 mem.copy(u16, path_space.data[start_index..], s);1355 mem.copy(u16, path_space.data[start_index..], s);
1316 for (path_space.data[0..path_space.len]) |*elem| {1356 path_space.ensureNtStyle();
1317 if (elem.* == '/') {
1318 elem.* = '\\';
1319 }
1320 }
1321 path_space.data[path_space.len] = 0;
1322 return path_space;1357 return path_space;
1323}1358}
13241359