Add various build fixes

Fix WASI build, fix atomicSymlink by using `cwd().symLink`, add
`Dir.symLink` on supported targets.
This commit is contained in:
Jakub Konka 2020-07-19 23:18:20 +02:00
parent e0b77a6b77
commit 2c9c13f624
2 changed files with 64 additions and 17 deletions

View File

@ -66,7 +66,15 @@ pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) {
/// TODO remove the allocator requirement from this API
pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
if (symLinkAbsolute(existing_path, new_path, .{})) {
const res = blk: {
// TODO this is just a temporary until Dir.symLink is implemented on Windows
if (builtin.os.tag == .windows) {
break :blk os.windows.CreateSymbolicLink(new_path, existing_path, false);
} else {
break :blk cwd().symLink(existing_path, new_path, .{});
}
};
if (res) {
return;
} else |err| switch (err) {
error.PathAlreadyExists => {},
@ -84,7 +92,15 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
try crypto.randomBytes(rand_buf[0..]);
base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf);
if (symLinkAbsolute(existing_path, tmp_path, .{})) {
const res2 = blk: {
// TODO this is just a temporary until Dir.symLink is implemented on Windows
if (builtin.os.tag == .windows) {
break :blk os.windows.CreateSymbolicLink(tmp_path, existing_path, false);
} else {
break :blk cwd().symLink(existing_path, new_path, .{});
}
};
if (res2) {
return rename(tmp_path, new_path);
} else |err| switch (err) {
error.PathAlreadyExists => continue,
@ -669,7 +685,7 @@ pub const Dir = struct {
w.RIGHT_FD_FILESTAT_SET_TIMES |
w.RIGHT_FD_FILESTAT_SET_SIZE;
}
const fd = try os.openatWasi(self.fd, sub_path, 0x0, fdflags, base, 0x0);
const fd = try os.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0);
return File{ .handle = fd };
}
@ -789,7 +805,7 @@ pub const Dir = struct {
if (flags.exclusive) {
oflags |= w.O_EXCL;
}
const fd = try os.openatWasi(self.fd, sub_path, oflags, 0x0, base, 0x0);
const fd = try os.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0);
return File{ .handle = fd };
}
@ -952,7 +968,7 @@ pub const Dir = struct {
/// of the result. It means the `iterate` function can be called.
iterate: bool = false,
/// `true` means it won't dereference the symlink.
/// `true` means it won't dereference the symlinks.
no_follow: bool = false,
};
@ -1001,7 +1017,7 @@ pub const Dir = struct {
// TODO do we really need all the rights here?
const inheriting: w.rights_t = w.RIGHT_ALL ^ w.RIGHT_SOCK_SHUTDOWN;
const result = os.openatWasi(self.fd, sub_path, w.O_DIRECTORY, symlink_flags, base, inheriting);
const result = os.openatWasi(self.fd, sub_path, symlink_flags, w.O_DIRECTORY, 0x0, base, inheriting);
const fd = result catch |err| switch (err) {
error.FileTooBig => unreachable, // can't happen for directories
error.IsDir => unreachable, // we're providing O_DIRECTORY
@ -1211,6 +1227,38 @@ pub const Dir = struct {
};
}
/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
/// 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,
sym_link_path: []const u8,
flags: SymLinkFlags,
) !void {
if (builtin.os.tag == .wasi) {
return self.symLinkWasi(target_path, sym_link_path);
}
if (builtin.os.tag == .windows) {
@compileError("TODO implement Dir.symLink on Windows");
}
const target_path_c = try os.toPosixPath(target_path);
const sym_link_path_c = try os.toPosixPath(sym_link_path);
return self.symLinkZ(&target_path_c, &sym_link_path_c, flags);
}
/// WASI-only. Same as `symLink` except targeting WASI.
pub fn symLinkWasi(self: Dir, target_path: []const u8, sym_link_path: []const u8, flags: SymLinkFlags) !void {
return os.symlinkatWasi(target_path, self.fd, sym_link_path);
}
/// Same as `symLink`, except the pathname parameters are null-terminated.
pub fn symLinkZ(self: Dir, target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymLinkFlags) !void {
return os.symlinkatZ(target_path_c, self.fd, sym_link_path_c);
}
/// Read value of a symbolic link.
/// The return value is a slice of `buffer`, from index `0`.
/// Asserts that the path parameter has no null bytes.
@ -1305,7 +1353,6 @@ pub const Dir = struct {
error.Unexpected,
=> |e| return e,
}
var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) {
error.NotDir => {
if (got_access_denied) {
@ -1718,7 +1765,7 @@ pub const readLinkC = @compileError("deprecated; use Dir.readLinkZ or readLinkAb
/// or a directory. This value is ignored on all hosts except Windows where
/// creating symlinks to different resource types, requires different flags.
/// By default, `symLinkAbsolute` is assumed to point to a file.
pub const SymlinkFlags = struct {
pub const SymLinkFlags = struct {
is_directory: bool = false,
};
@ -1727,9 +1774,9 @@ pub const SymlinkFlags = struct {
/// one; the latter case is known as a dangling link.
/// If `sym_link_path` exists, it will not be overwritten.
/// See also `symLinkAbsoluteZ` and `symLinkAbsoluteW`.
pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags: SymlinkFlags) !void {
pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags: SymLinkFlags) !void {
if (builtin.os.tag == .wasi) {
@compileError("symLinkAbsolute is not supported in WASI");
@compileError("symLinkAbsolute is not supported in WASI; use Dir.symLinkWasi instead");
}
assert(path.isAbsolute(target_path));
assert(path.isAbsolute(sym_link_path));
@ -1741,9 +1788,9 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags
/// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 encoded.
/// Note that this function will by default try creating a symbolic link to a file. If you would
/// like to create a symbolic link to a directory, specify this with `SymlinkFlags{ .is_directory = true }`.
/// like to create a symbolic link to a directory, specify this with `SymLinkFlags{ .is_directory = true }`.
/// See also `symLinkAbsolute`, `symLinkAbsoluteZ`.
pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]const u16, flags: SymlinkFlags) !void {
pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]const u16, flags: SymLinkFlags) !void {
assert(path.isAbsoluteWindowsW(target_path_w));
assert(path.isAbsoluteWindowsW(sym_link_path_w));
return os.windows.CreateSymbolicLinkW(sym_link_path_w, target_path_w, flags.is_directory);
@ -1751,7 +1798,7 @@ pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]con
/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
/// See also `symLinkAbsolute`.
pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymlinkFlags) !void {
pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymLinkFlags) !void {
assert(path.isAbsoluteZ(target_path_c));
assert(path.isAbsoluteZ(sym_link_path_c));
if (builtin.os.tag == .windows) {
@ -1762,8 +1809,8 @@ pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]cons
return os.symlinkZ(target_path_c, sym_link_path_c);
}
pub const symLink = @compileError("deprecated: use symLinkAbsolute");
pub const symLinkC = @compileError("deprecated: use symLinkAbsoluteC");
pub const symLink = @compileError("deprecated: use Dir.symLink or symLinkAbsolute");
pub const symLinkC = @compileError("deprecated: use Dir.symLinkZ or symLinkAbsoluteZ");
pub const Walker = struct {
stack: std.ArrayList(StackItem),

View File

@ -1109,10 +1109,10 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
}
/// Open and possibly create a file in WASI.
pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, base: rights_t, inheriting: rights_t) OpenError!fd_t {
pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, lookup_flags: lookupflags_t, oflags: oflags_t, fdflags: fdflags_t, base: rights_t, inheriting: rights_t) OpenError!fd_t {
while (true) {
var fd: fd_t = undefined;
switch (wasi.path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) {
switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) {
wasi.ESUCCESS => return fd,
wasi.EINTR => continue,