mirror of
https://github.com/ziglang/zig.git
synced 2025-12-15 18:53:07 +00:00
std.fs.path.resolve: eliminate getcwd() syscall
This is a breaking change to the API. Instead of the first path
implicitly being the current working directory, it now asserts that the
number of paths passed is greater than zero.
Importantly, it never calls getcwd(); instead, it can possibly return
".", or a series of "../". This changes the error set to only be
`error{OutOfMemory}`.
closes #13613
This commit is contained in:
parent
21bd13626d
commit
d24aaf8847
@ -467,55 +467,49 @@ pub fn resolve(allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
|
||||
/// Note: all usage of this function should be audited due to the existence of symlinks.
|
||||
/// Without performing actual syscalls, resolving `..` could be incorrect.
|
||||
/// This API may break in the future: https://github.com/ziglang/zig/issues/13613
|
||||
pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) {
|
||||
assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
return process.getCwdAlloc(allocator);
|
||||
}
|
||||
assert(paths.len > 0);
|
||||
|
||||
// determine which disk designator we will result with, if any
|
||||
var result_drive_buf = "_:".*;
|
||||
var result_disk_designator: []const u8 = "";
|
||||
var have_drive_kind = WindowsPath.Kind.None;
|
||||
var disk_designator: []const u8 = "";
|
||||
var drive_kind = WindowsPath.Kind.None;
|
||||
var have_abs_path = false;
|
||||
var first_index: usize = 0;
|
||||
var max_size: usize = 0;
|
||||
for (paths) |p, i| {
|
||||
const parsed = windowsParsePath(p);
|
||||
if (parsed.is_abs) {
|
||||
have_abs_path = true;
|
||||
first_index = i;
|
||||
max_size = result_disk_designator.len;
|
||||
}
|
||||
switch (parsed.kind) {
|
||||
WindowsPath.Kind.Drive => {
|
||||
.Drive => {
|
||||
result_drive_buf[0] = ascii.toUpper(parsed.disk_designator[0]);
|
||||
result_disk_designator = result_drive_buf[0..];
|
||||
have_drive_kind = WindowsPath.Kind.Drive;
|
||||
disk_designator = result_drive_buf[0..];
|
||||
drive_kind = WindowsPath.Kind.Drive;
|
||||
},
|
||||
WindowsPath.Kind.NetworkShare => {
|
||||
result_disk_designator = parsed.disk_designator;
|
||||
have_drive_kind = WindowsPath.Kind.NetworkShare;
|
||||
.NetworkShare => {
|
||||
disk_designator = parsed.disk_designator;
|
||||
drive_kind = WindowsPath.Kind.NetworkShare;
|
||||
},
|
||||
WindowsPath.Kind.None => {},
|
||||
.None => {},
|
||||
}
|
||||
max_size += p.len + 1;
|
||||
}
|
||||
|
||||
// if we will result with a disk designator, loop again to determine
|
||||
// which is the last time the disk designator is absolutely specified, if any
|
||||
// and count up the max bytes for paths related to this disk designator
|
||||
if (have_drive_kind != WindowsPath.Kind.None) {
|
||||
if (drive_kind != WindowsPath.Kind.None) {
|
||||
have_abs_path = false;
|
||||
first_index = 0;
|
||||
max_size = result_disk_designator.len;
|
||||
var correct_disk_designator = false;
|
||||
|
||||
for (paths) |p, i| {
|
||||
const parsed = windowsParsePath(p);
|
||||
if (parsed.kind != WindowsPath.Kind.None) {
|
||||
if (parsed.kind == have_drive_kind) {
|
||||
correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
|
||||
if (parsed.kind == drive_kind) {
|
||||
correct_disk_designator = compareDiskDesignators(drive_kind, disk_designator, parsed.disk_designator);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -525,92 +519,51 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
}
|
||||
if (parsed.is_abs) {
|
||||
first_index = i;
|
||||
max_size = result_disk_designator.len;
|
||||
have_abs_path = true;
|
||||
}
|
||||
max_size += p.len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate result and fill in the disk designator, calling getCwd if we have to.
|
||||
var result: []u8 = undefined;
|
||||
var result_index: usize = 0;
|
||||
// Allocate result and fill in the disk designator.
|
||||
var result = std.ArrayList(u8).init(allocator);
|
||||
defer result.deinit();
|
||||
|
||||
if (have_abs_path) {
|
||||
switch (have_drive_kind) {
|
||||
WindowsPath.Kind.Drive => {
|
||||
result = try allocator.alloc(u8, max_size);
|
||||
|
||||
mem.copy(u8, result, result_disk_designator);
|
||||
result_index += result_disk_designator.len;
|
||||
const disk_designator_len: usize = l: {
|
||||
if (!have_abs_path) break :l 0;
|
||||
switch (drive_kind) {
|
||||
.Drive => {
|
||||
try result.appendSlice(disk_designator);
|
||||
break :l disk_designator.len;
|
||||
},
|
||||
WindowsPath.Kind.NetworkShare => {
|
||||
result = try allocator.alloc(u8, max_size);
|
||||
.NetworkShare => {
|
||||
var it = mem.tokenize(u8, paths[first_index], "/\\");
|
||||
const server_name = it.next().?;
|
||||
const other_name = it.next().?;
|
||||
|
||||
result[result_index] = '\\';
|
||||
result_index += 1;
|
||||
result[result_index] = '\\';
|
||||
result_index += 1;
|
||||
mem.copy(u8, result[result_index..], server_name);
|
||||
result_index += server_name.len;
|
||||
result[result_index] = '\\';
|
||||
result_index += 1;
|
||||
mem.copy(u8, result[result_index..], other_name);
|
||||
result_index += other_name.len;
|
||||
try result.ensureUnusedCapacity(2 + 1 + server_name.len + other_name.len);
|
||||
result.appendSliceAssumeCapacity("\\\\");
|
||||
result.appendSliceAssumeCapacity(server_name);
|
||||
result.appendAssumeCapacity('\\');
|
||||
result.appendSliceAssumeCapacity(other_name);
|
||||
|
||||
result_disk_designator = result[0..result_index];
|
||||
break :l result.items.len;
|
||||
},
|
||||
WindowsPath.Kind.None => {
|
||||
assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
const parsed_cwd = windowsParsePath(cwd);
|
||||
result = try allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1);
|
||||
mem.copy(u8, result, parsed_cwd.disk_designator);
|
||||
result_index += parsed_cwd.disk_designator.len;
|
||||
result_disk_designator = result[0..parsed_cwd.disk_designator.len];
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
result[0] = ascii.toUpper(result[0]);
|
||||
}
|
||||
have_drive_kind = parsed_cwd.kind;
|
||||
.None => {
|
||||
break :l 1;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
// TODO call get cwd for the result_disk_designator instead of the global one
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
};
|
||||
|
||||
result = try allocator.alloc(u8, max_size + cwd.len + 1);
|
||||
|
||||
mem.copy(u8, result, cwd);
|
||||
result_index += cwd.len;
|
||||
const parsed_cwd = windowsParsePath(result[0..result_index]);
|
||||
result_disk_designator = parsed_cwd.disk_designator;
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
result[0] = ascii.toUpper(result[0]);
|
||||
// Remove the trailing slash if present, eg. if the cwd is a root
|
||||
// directory.
|
||||
if (cwd.len > 0 and cwd[cwd.len - 1] == sep_windows) {
|
||||
result_index -= 1;
|
||||
}
|
||||
}
|
||||
have_drive_kind = parsed_cwd.kind;
|
||||
}
|
||||
errdefer allocator.free(result);
|
||||
|
||||
// Now we know the disk designator to use, if any, and what kind it is. And our result
|
||||
// is big enough to append all the paths to.
|
||||
var correct_disk_designator = true;
|
||||
var negative_count: usize = 0;
|
||||
|
||||
for (paths[first_index..]) |p| {
|
||||
const parsed = windowsParsePath(p);
|
||||
|
||||
if (parsed.kind != WindowsPath.Kind.None) {
|
||||
if (parsed.kind == have_drive_kind) {
|
||||
correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
|
||||
if (parsed.kind != .None) {
|
||||
if (parsed.kind == drive_kind) {
|
||||
const dd = result.items[0..disk_designator_len];
|
||||
correct_disk_designator = compareDiskDesignators(drive_kind, dd, parsed.disk_designator);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -619,154 +572,167 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
continue;
|
||||
}
|
||||
var it = mem.tokenize(u8, p[parsed.disk_designator.len..], "/\\");
|
||||
while (it.next()) |component| {
|
||||
component: while (it.next()) |component| {
|
||||
if (mem.eql(u8, component, ".")) {
|
||||
continue;
|
||||
} else if (mem.eql(u8, component, "..")) {
|
||||
while (true) {
|
||||
if (result_index == 0 or result_index == result_disk_designator.len)
|
||||
break;
|
||||
result_index -= 1;
|
||||
if (result[result_index] == '\\' or result[result_index] == '/')
|
||||
if (result.items.len == 0) {
|
||||
negative_count += 1;
|
||||
continue :component;
|
||||
}
|
||||
if (result.items.len == disk_designator_len) {
|
||||
break;
|
||||
}
|
||||
const end_with_sep = switch (result.items[result.items.len - 1]) {
|
||||
'\\', '/' => true,
|
||||
else => false,
|
||||
};
|
||||
result.items.len -= 1;
|
||||
if (end_with_sep) break;
|
||||
}
|
||||
} else if (!have_abs_path and result.items.len == 0) {
|
||||
try result.appendSlice(component);
|
||||
} else {
|
||||
result[result_index] = sep_windows;
|
||||
result_index += 1;
|
||||
mem.copy(u8, result[result_index..], component);
|
||||
result_index += component.len;
|
||||
try result.ensureUnusedCapacity(1 + component.len);
|
||||
result.appendAssumeCapacity('\\');
|
||||
result.appendSliceAssumeCapacity(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result_index == result_disk_designator.len) {
|
||||
result[result_index] = '\\';
|
||||
result_index += 1;
|
||||
if (disk_designator_len != 0 and result.items.len == disk_designator_len) {
|
||||
try result.append('\\');
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
return allocator.shrink(result, result_index);
|
||||
if (result.items.len == 0) {
|
||||
if (negative_count == 0) {
|
||||
return allocator.dupe(u8, ".");
|
||||
} else {
|
||||
const real_result = try allocator.alloc(u8, 3 * negative_count - 1);
|
||||
var count = negative_count - 1;
|
||||
var i: usize = 0;
|
||||
while (count > 0) : (count -= 1) {
|
||||
real_result[i..][0..3].* = "..\\".*;
|
||||
i += 3;
|
||||
}
|
||||
real_result[i..][0..2].* = "..".*;
|
||||
return real_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (negative_count == 0) {
|
||||
return result.toOwnedSlice();
|
||||
} else {
|
||||
const real_result = try allocator.alloc(u8, 3 * negative_count + result.items.len);
|
||||
var count = negative_count;
|
||||
var i: usize = 0;
|
||||
while (count > 0) : (count -= 1) {
|
||||
real_result[i..][0..3].* = "..\\".*;
|
||||
i += 3;
|
||||
}
|
||||
mem.copy(u8, real_result[i..], result.items);
|
||||
return real_result;
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is like a series of `cd` statements executed one after another.
|
||||
/// It resolves "." and "..".
|
||||
/// The result does not have a trailing path separator.
|
||||
/// If all paths are relative it uses the current working directory as a starting point.
|
||||
/// Note: all usage of this function should be audited due to the existence of symlinks.
|
||||
/// Without performing actual syscalls, resolving `..` could be incorrect.
|
||||
pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) {
|
||||
assert(native_os != .windows); // resolvePosix called on windows can't use getCwd
|
||||
return process.getCwdAlloc(allocator);
|
||||
}
|
||||
/// This function does not perform any syscalls. Executing this series of path
|
||||
/// lookups on the actual filesystem may produce different results due to
|
||||
/// symlinks.
|
||||
pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8 {
|
||||
assert(paths.len > 0);
|
||||
|
||||
var first_index: usize = 0;
|
||||
var have_abs = false;
|
||||
var max_size: usize = 0;
|
||||
for (paths) |p, i| {
|
||||
var result = std.ArrayList(u8).init(allocator);
|
||||
defer result.deinit();
|
||||
|
||||
var negative_count: usize = 0;
|
||||
var is_abs = false;
|
||||
|
||||
for (paths) |p| {
|
||||
if (isAbsolutePosix(p)) {
|
||||
first_index = i;
|
||||
have_abs = true;
|
||||
max_size = 0;
|
||||
is_abs = true;
|
||||
negative_count = 0;
|
||||
result.clearRetainingCapacity();
|
||||
}
|
||||
max_size += p.len + 1;
|
||||
}
|
||||
|
||||
var result: []u8 = undefined;
|
||||
var result_index: usize = 0;
|
||||
|
||||
if (have_abs) {
|
||||
result = try allocator.alloc(u8, max_size);
|
||||
} else {
|
||||
assert(native_os != .windows); // resolvePosix called on windows can't use getCwd
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
result = try allocator.alloc(u8, max_size + cwd.len + 1);
|
||||
mem.copy(u8, result, cwd);
|
||||
result_index += cwd.len;
|
||||
}
|
||||
errdefer allocator.free(result);
|
||||
|
||||
for (paths[first_index..]) |p| {
|
||||
var it = mem.tokenize(u8, p, "/");
|
||||
while (it.next()) |component| {
|
||||
component: while (it.next()) |component| {
|
||||
if (mem.eql(u8, component, ".")) {
|
||||
continue;
|
||||
} else if (mem.eql(u8, component, "..")) {
|
||||
while (true) {
|
||||
if (result_index == 0)
|
||||
break;
|
||||
result_index -= 1;
|
||||
if (result[result_index] == '/')
|
||||
break;
|
||||
if (result.items.len == 0) {
|
||||
negative_count += @boolToInt(!is_abs);
|
||||
continue :component;
|
||||
}
|
||||
const ends_with_slash = result.items[result.items.len - 1] == '/';
|
||||
result.items.len -= 1;
|
||||
if (ends_with_slash) break;
|
||||
}
|
||||
} else if (result.items.len > 0 or is_abs) {
|
||||
try result.ensureUnusedCapacity(1 + component.len);
|
||||
result.appendAssumeCapacity('/');
|
||||
result.appendSliceAssumeCapacity(component);
|
||||
} else {
|
||||
result[result_index] = '/';
|
||||
result_index += 1;
|
||||
mem.copy(u8, result[result_index..], component);
|
||||
result_index += component.len;
|
||||
try result.appendSlice(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result_index == 0) {
|
||||
result[0] = '/';
|
||||
result_index += 1;
|
||||
if (result.items.len == 0) {
|
||||
if (is_abs) {
|
||||
return allocator.dupe(u8, "/");
|
||||
}
|
||||
if (negative_count == 0) {
|
||||
return allocator.dupe(u8, ".");
|
||||
} else {
|
||||
const real_result = try allocator.alloc(u8, 3 * negative_count - 1);
|
||||
var count = negative_count - 1;
|
||||
var i: usize = 0;
|
||||
while (count > 0) : (count -= 1) {
|
||||
real_result[i..][0..3].* = "../".*;
|
||||
i += 3;
|
||||
}
|
||||
real_result[i..][0..2].* = "..".*;
|
||||
return real_result;
|
||||
}
|
||||
}
|
||||
|
||||
return allocator.shrink(result, result_index);
|
||||
if (negative_count == 0) {
|
||||
return result.toOwnedSlice();
|
||||
} else {
|
||||
const real_result = try allocator.alloc(u8, 3 * negative_count + result.items.len);
|
||||
var count = negative_count;
|
||||
var i: usize = 0;
|
||||
while (count > 0) : (count -= 1) {
|
||||
real_result[i..][0..3].* = "../".*;
|
||||
i += 3;
|
||||
}
|
||||
mem.copy(u8, real_result[i..], result.items);
|
||||
return real_result;
|
||||
}
|
||||
}
|
||||
|
||||
test "resolve" {
|
||||
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
||||
try testResolveWindows(&[_][]const u8{ "a\\b\\c\\", "..\\..\\.." }, "..");
|
||||
try testResolveWindows(&[_][]const u8{"."}, ".");
|
||||
|
||||
const cwd = try process.getCwdAlloc(testing.allocator);
|
||||
defer testing.allocator.free(cwd);
|
||||
if (native_os == .windows) {
|
||||
if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
|
||||
cwd[0] = ascii.toUpper(cwd[0]);
|
||||
}
|
||||
try testResolveWindows(&[_][]const u8{"."}, cwd);
|
||||
} else {
|
||||
try testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }, cwd);
|
||||
try testResolvePosix(&[_][]const u8{"."}, cwd);
|
||||
}
|
||||
try testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }, "..");
|
||||
try testResolvePosix(&[_][]const u8{"."}, ".");
|
||||
}
|
||||
|
||||
test "resolveWindows" {
|
||||
if (builtin.target.cpu.arch == .aarch64) {
|
||||
// TODO https://github.com/ziglang/zig/issues/3288
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
||||
if (native_os == .windows) {
|
||||
const cwd = try process.getCwdAlloc(testing.allocator);
|
||||
defer testing.allocator.free(cwd);
|
||||
const parsed_cwd = windowsParsePath(cwd);
|
||||
{
|
||||
const expected = try join(testing.allocator, &[_][]const u8{
|
||||
parsed_cwd.disk_designator,
|
||||
"usr\\local\\lib\\zig\\std\\array_list.zig",
|
||||
});
|
||||
defer testing.allocator.free(expected);
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
expected[0] = ascii.toUpper(parsed_cwd.disk_designator[0]);
|
||||
}
|
||||
try testResolveWindows(&[_][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }, expected);
|
||||
}
|
||||
{
|
||||
const expected = try join(testing.allocator, &[_][]const u8{
|
||||
cwd,
|
||||
"usr\\local\\lib\\zig",
|
||||
});
|
||||
defer testing.allocator.free(expected);
|
||||
if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
|
||||
expected[0] = ascii.toUpper(parsed_cwd.disk_designator[0]);
|
||||
}
|
||||
try testResolveWindows(&[_][]const u8{ "usr/local", "lib\\zig" }, expected);
|
||||
}
|
||||
}
|
||||
try testResolveWindows(
|
||||
&[_][]const u8{ "Z:\\", "/usr/local", "lib\\zig\\std\\array_list.zig" },
|
||||
"Z:\\usr\\local\\lib\\zig\\std\\array_list.zig",
|
||||
);
|
||||
try testResolveWindows(
|
||||
&[_][]const u8{ "z:\\", "usr/local", "lib\\zig" },
|
||||
"Z:\\usr\\local\\lib\\zig",
|
||||
);
|
||||
|
||||
try testResolveWindows(&[_][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }, "C:\\hi\\ok");
|
||||
try testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }, "C:\\blah\\a");
|
||||
@ -781,12 +747,12 @@ test "resolveWindows" {
|
||||
try testResolveWindows(&[_][]const u8{ "c:/", "//server//share" }, "\\\\server\\share\\");
|
||||
try testResolveWindows(&[_][]const u8{ "c:/", "///some//dir" }, "C:\\some\\dir");
|
||||
try testResolveWindows(&[_][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }, "C:\\foo\\tmp.3\\cycles\\root.js");
|
||||
|
||||
// Keep relative paths relative.
|
||||
try testResolveWindows(&[_][]const u8{"a/b"}, "a\\b");
|
||||
}
|
||||
|
||||
test "resolvePosix" {
|
||||
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
||||
|
||||
try testResolvePosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c");
|
||||
try testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }, "/d/e");
|
||||
try testResolvePosix(&[_][]const u8{ "/a/b/c", "..", "../" }, "/a");
|
||||
@ -797,18 +763,21 @@ test "resolvePosix" {
|
||||
try testResolvePosix(&[_][]const u8{ "/var/lib", "/../", "file/" }, "/file");
|
||||
try testResolvePosix(&[_][]const u8{ "/some/dir", ".", "/absolute/" }, "/absolute");
|
||||
try testResolvePosix(&[_][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }, "/foo/tmp.3/cycles/root.js");
|
||||
|
||||
// Keep relative paths relative.
|
||||
try testResolvePosix(&[_][]const u8{"a/b"}, "a/b");
|
||||
}
|
||||
|
||||
fn testResolveWindows(paths: []const []const u8, expected: []const u8) !void {
|
||||
const actual = try resolveWindows(testing.allocator, paths);
|
||||
defer testing.allocator.free(actual);
|
||||
try testing.expect(mem.eql(u8, actual, expected));
|
||||
try testing.expectEqualStrings(expected, actual);
|
||||
}
|
||||
|
||||
fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {
|
||||
const actual = try resolvePosix(testing.allocator, paths);
|
||||
defer testing.allocator.free(actual);
|
||||
try testing.expect(mem.eql(u8, actual, expected));
|
||||
try testing.expectEqualStrings(expected, actual);
|
||||
}
|
||||
|
||||
/// Strip the last component from a file path.
|
||||
@ -1089,13 +1058,15 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !
|
||||
if (parsed_from.kind != parsed_to.kind) {
|
||||
break :x true;
|
||||
} else switch (parsed_from.kind) {
|
||||
WindowsPath.Kind.NetworkShare => {
|
||||
.NetworkShare => {
|
||||
break :x !networkShareServersEql(parsed_to.disk_designator, parsed_from.disk_designator);
|
||||
},
|
||||
WindowsPath.Kind.Drive => {
|
||||
.Drive => {
|
||||
break :x ascii.toUpper(parsed_from.disk_designator[0]) != ascii.toUpper(parsed_to.disk_designator[0]);
|
||||
},
|
||||
else => unreachable,
|
||||
.None => {
|
||||
break :x false;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -1194,13 +1165,6 @@ pub fn relativePosix(allocator: Allocator, from: []const u8, to: []const u8) ![]
|
||||
}
|
||||
|
||||
test "relative" {
|
||||
if (builtin.target.cpu.arch == .aarch64) {
|
||||
// TODO https://github.com/ziglang/zig/issues/3288
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/");
|
||||
|
||||
try testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games");
|
||||
try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", "..");
|
||||
try testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc");
|
||||
@ -1226,6 +1190,10 @@ test "relative" {
|
||||
try testRelativeWindows("C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz");
|
||||
try testRelativeWindows("\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz");
|
||||
|
||||
try testRelativeWindows("a/b/c", "a\\b", "..");
|
||||
try testRelativeWindows("a/b/c", "a", "..\\..");
|
||||
try testRelativeWindows("a/b/c", "a\\b\\c\\d", "d");
|
||||
|
||||
try testRelativePosix("/var/lib", "/var", "..");
|
||||
try testRelativePosix("/var/lib", "/bin", "../../bin");
|
||||
try testRelativePosix("/var/lib", "/var/lib", "");
|
||||
@ -1243,13 +1211,13 @@ test "relative" {
|
||||
fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) !void {
|
||||
const result = try relativePosix(testing.allocator, from, to);
|
||||
defer testing.allocator.free(result);
|
||||
try testing.expectEqualSlices(u8, expected_output, result);
|
||||
try testing.expectEqualStrings(expected_output, result);
|
||||
}
|
||||
|
||||
fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) !void {
|
||||
const result = try relativeWindows(testing.allocator, from, to);
|
||||
defer testing.allocator.free(result);
|
||||
try testing.expectEqualSlices(u8, expected_output, result);
|
||||
try testing.expectEqualStrings(expected_output, result);
|
||||
}
|
||||
|
||||
/// Returns the extension of the file name (if any).
|
||||
|
||||
@ -1095,7 +1095,9 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
||||
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"};
|
||||
const cwd = try std.process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
const file_paths: [2][]const u8 = .{ cwd, "zig-test-absolute-paths.txt" };
|
||||
const filename = try fs.path.resolve(allocator, &file_paths);
|
||||
defer allocator.free(filename);
|
||||
|
||||
|
||||
@ -202,10 +202,7 @@ pub const PreopenList = struct {
|
||||
// POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "."
|
||||
const path = if (cwd_root) |cwd| blk: {
|
||||
const resolve_paths: []const []const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path };
|
||||
break :blk fs.path.resolve(self.buffer.allocator, resolve_paths) catch |err| switch (err) {
|
||||
error.CurrentWorkingDirectoryUnlinked => unreachable, // root is absolute, so CWD not queried
|
||||
else => |e| return e,
|
||||
};
|
||||
break :blk try fs.path.resolve(self.buffer.allocator, resolve_paths);
|
||||
} else blk: {
|
||||
// If we were provided no CWD root, we preserve the preopen dir without resolving
|
||||
break :blk try self.buffer.allocator.dupe(u8, raw_path);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user