Skip to content

Commit

Permalink
Add missing cross-platform Dir.readLink fns
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Jul 22, 2020
1 parent 65581b3 commit aa6fcaf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
22 changes: 21 additions & 1 deletion lib/std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
26 changes: 26 additions & 0 deletions lib/std/fs/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
14 changes: 2 additions & 12 deletions lib/std/os.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit aa6fcaf

Please sign in to comment.