From aa6fcaf76f00453f160545e760c37d64588f4517 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 21 Jul 2020 20:40:34 +0200 Subject: [PATCH] Add missing cross-platform Dir.readLink fns --- lib/std/fs.zig | 22 +++++++++++++++++++++- lib/std/fs/test.zig | 26 ++++++++++++++++++++++++++ lib/std/os.zig | 14 ++------------ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 830a4ac7c..9070fd0a9 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1215,7 +1215,6 @@ pub const Dir = struct { /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent /// one; the latter case is known as a dangling link. /// If `sym_link_path` exists, it will not be overwritten. - /// TODO add Windows support pub fn symLink( self: Dir, target_path: []const u8, @@ -1275,17 +1274,38 @@ pub const Dir = struct { /// The return value is a slice of `buffer`, from index `0`. /// Asserts that the path parameter has no null bytes. pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 { + if (builtin.os.tag == .wasi) { + return self.readLinkWasi(sub_path, buffer); + } + if (builtin.os.tag == .windows) { + return os.windows.ReadLink(self.fd, sub_path, buffer); + } const sub_path_c = try os.toPosixPath(sub_path); return self.readLinkZ(&sub_path_c, buffer); } pub const readLinkC = @compileError("deprecated: renamed to readLinkZ"); + /// WASI-only. Same as `readLink` except targeting WASI. + pub fn readLinkWasi(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 { + return os.readlinkatWasi(self.fd, sub_path, buffer); + } + /// 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); + return self.readLinkW(sub_path_w, buffer); + } return os.readlinkatZ(self.fd, sub_path_c, buffer); } + /// Windows-only. Same as `readLink` except the pathname parameter + /// is null-terminated, WTF16 encoded. + pub fn readLinkW(self: Dir, sub_path_w: [*:0]const u16, buffer: []u8) ![]u8 { + return os.windows.ReadLinkW(self.fd, sub_path_w, buffer); + } + /// On success, caller owns returned buffer. /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 4fecf3c9c..c9f171196 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -10,6 +10,32 @@ const Dir = std.fs.Dir; const File = std.fs.File; const tmpDir = testing.tmpDir; +test "Dir.readLink" { + var tmp = tmpDir(.{}); + defer tmp.cleanup(); + + // Create some targets + try tmp.dir.writeFile("file.txt", "nonsense"); + try tmp.dir.makeDir("subdir"); + + { + // Create symbolic link by path + try tmp.dir.symLink("file.txt", "symlink1", .{}); + try testReadLink(tmp.dir, "file.txt", "symlink1"); + } + { + // Create symbolic link by path + try tmp.dir.symLink("subdir", "symlink2", .{ .is_directory = true }); + try testReadLink(tmp.dir, "subdir", "symlink2"); + } +} + +fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void { + var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; + const given = try dir.readLink(symlink_path, buffer[0..]); + testing.expect(mem.eql(u8, target_path, given)); +} + test "readLinkAbsolute" { if (builtin.os.tag == .wasi) return error.SkipZigTest; diff --git a/lib/std/os.zig b/lib/std/os.zig index 71bf34acf..3e05ac41e 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1594,9 +1594,7 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const return symlinkatWasi(target_path, newdirfd, sym_link_path); } 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); - return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path_w.span().ptr); + @compileError("symlinkat is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } const target_path_c = try toPosixPath(target_path); const sym_link_path_c = try toPosixPath(sym_link_path); @@ -1629,19 +1627,11 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c } } -/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded. -/// See also `symlinkat`. -pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymLinkError!void { - @compileError("TODO implement on Windows"); -} - /// The same as `symlinkat` except the parameters are null-terminated pointers. /// See also `symlinkat`. pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) 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); - return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path.span().ptr); + @compileError("symlinkat is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) { 0 => return,