diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-14 23:30:05 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-22 08:51:22 +0200 |
| commit | c47cb8d09f7cf1c02d3af59ebbca665ce78c85ca (patch) | |
| tree | febc011d21f115dfbd95fa0e8250e2c0327fc3ce /lib/std | |
| parent | ae8abedbeda33ff5cd93ca2fb21ef2f5453dfb37 (diff) | |
| download | zig-c47cb8d09f7cf1c02d3af59ebbca665ce78c85ca.tar.gz zig-c47cb8d09f7cf1c02d3af59ebbca665ce78c85ca.zip | |
Fix unlinkatW to allow file symlink deletion on Windows
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/os.zig | 10 | ||||
| -rw-r--r-- | lib/std/os/test.zig | 79 | ||||
| -rw-r--r-- | lib/std/os/windows/bits.zig | 4 |
3 files changed, 51 insertions, 42 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig index e3e44b6a30..7b85871446 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1834,7 +1834,7 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr const create_options_flags = if (want_rmdir_behavior) @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_DIRECTORY_FILE) else - @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_NON_DIRECTORY_FILE); + @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_NON_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT); // would we ever want to delete the target instead? const path_len_bytes = @intCast(u16, mem.lenZ(sub_path_w) * 2); var nt_name = w.UNICODE_STRING{ @@ -2371,7 +2371,7 @@ pub const ReadLinkError = error{ InvalidUtf8, BadPathName, /// Windows-only. - UnsupportedSymlinkType, + UnsupportedReparsePointType, } || UnexpectedError; /// Read value of a symbolic link. @@ -2412,7 +2412,7 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 const reparse_struct = @ptrCast(*const w.REPARSE_DATA_BUFFER, @alignCast(@alignOf(w.REPARSE_DATA_BUFFER), &reparse_buf[0])); switch (reparse_struct.ReparseTag) { w.IO_REPARSE_TAG_SYMLINK => { - const buf = @ptrCast(*const w.SymbolicLinkReparseBuffer, @alignCast(@alignOf(w.SymbolicLinkReparseBuffer), &reparse_struct.DataBuffer[0])); + const buf = @ptrCast(*const w.SYMBOLIC_LINK_REPARSE_BUFFER, @alignCast(@alignOf(w.SYMBOLIC_LINK_REPARSE_BUFFER), &reparse_struct.DataBuffer[0])); const offset = buf.SubstituteNameOffset >> 1; const len = buf.SubstituteNameLength >> 1; const path_buf = @as([*]const u16, &buf.PathBuffer); @@ -2420,7 +2420,7 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 return parseReadlinkPath(path_buf[offset .. offset + len], is_relative, out_buffer); }, w.IO_REPARSE_TAG_MOUNT_POINT => { - const buf = @ptrCast(*const w.MountPointReparseBuffer, @alignCast(@alignOf(w.MountPointReparseBuffer), &reparse_struct.DataBuffer[0])); + const buf = @ptrCast(*const w.MOUNT_POINT_REPARSE_BUFFER, @alignCast(@alignOf(w.MOUNT_POINT_REPARSE_BUFFER), &reparse_struct.DataBuffer[0])); const offset = buf.SubstituteNameOffset >> 1; const len = buf.SubstituteNameLength >> 1; const path_buf = @as([*]const u16, &buf.PathBuffer); @@ -2428,7 +2428,7 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 }, else => |value| { std.debug.warn("unsupported symlink type: {}", .{value}); - return error.UnsupportedSymlinkType; + return error.UnsupportedReparsePointType; }, } } diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index a444df3e87..6b9c19c484 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -43,42 +43,51 @@ test "fstatat" { test "readlink" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - - var cwd = fs.cwd(); - try cwd.writeFile("file.txt", "nonsense"); - try os.symlink("file.txt", "symlinked"); - var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; - const given = try os.readlink("symlinked", buffer[0..]); - expect(mem.eql(u8, "file.txt", given)); - - // var tmp = tmpDir(.{}); - // defer tmp.cleanup(); - - // // create file - // try tmp.dir.writeFile("file.txt", "nonsense"); - - // // get paths - // // TODO: use Dir's realpath function once that exists - // var arena = ArenaAllocator.init(testing.allocator); - // defer arena.deinit(); - - // const base_path = blk: { - // const relative_path = try fs.path.join(&arena.allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..]}); - // break :blk try fs.realpathAlloc(&arena.allocator, relative_path); - // }; - // const target_path = try fs.path.join(&arena.allocator, &[_][]const u8{base_path, "file.txt"}); - // const symlink_path = try fs.path.join(&arena.allocator, &[_][]const u8{base_path, "symlinked"}); - // 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); - - // // now, read the link and verify - // var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; - // const given = try os.readlink(symlink_path, buffer[0..]); - // expect(mem.eql(u8, symlink_path, given)); + // First, try relative paths + { + var cwd = fs.cwd(); + try cwd.writeFile("file.txt", "nonsense"); + try os.symlink("file.txt", "symlinked"); + + var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; + const given = try os.readlink("symlinked", buffer[0..]); + expect(mem.eql(u8, "file.txt", given)); + + try cwd.deleteFile("file.txt"); + try cwd.deleteFile("symlinked"); + } + + // Next, let's try fully-qualified paths + { + var tmp = tmpDir(.{}); + // defer tmp.cleanup(); + + // create file + try tmp.dir.writeFile("file.txt", "nonsense"); + + // get paths + // TODO: use Dir's realpath function once that exists + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + + const base_path = blk: { + const relative_path = try fs.path.join(&arena.allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); + break :blk try fs.realpathAlloc(&arena.allocator, relative_path); + }; + const target_path = try fs.path.join(&arena.allocator, &[_][]const u8{ base_path, "file.txt" }); + const symlink_path = try fs.path.join(&arena.allocator, &[_][]const u8{ base_path, "symlinked" }); + 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); + + // now, read the link and verify + var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; + const given = try os.readlink(symlink_path, buffer[0..]); + expect(mem.eql(u8, symlink_path, given)); + } } test "readlinkat" { diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 8d3043f76f..1c5e1a3f70 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -1549,7 +1549,7 @@ pub const REPARSE_DATA_BUFFER = extern struct { Reserved: USHORT, DataBuffer: [1]UCHAR, }; -pub const SymbolicLinkReparseBuffer = extern struct { +pub const SYMBOLIC_LINK_REPARSE_BUFFER = extern struct { SubstituteNameOffset: USHORT, SubstituteNameLength: USHORT, PrintNameOffset: USHORT, @@ -1557,7 +1557,7 @@ pub const SymbolicLinkReparseBuffer = extern struct { Flags: ULONG, PathBuffer: [1]WCHAR, }; -pub const MountPointReparseBuffer = extern struct { +pub const MOUNT_POINT_REPARSE_BUFFER = extern struct { SubstituteNameOffset: USHORT, SubstituteNameLength: USHORT, PrintNameOffset: USHORT, |
