Skip to content

Commit 822f412

Browse files
committed
fs.path: Fix on big-endian architectures, make PathType.isSep assume WTF-16 is LE
This commit flips usage of PathType.isSep from requiring the caller to convert to native to assuming the input is LE encoded, which is a breaking change. This makes usage a bit nicer, though, and moves the endian conversion work from runtime to comptime.
1 parent 59b8bed commit 822f412

File tree

2 files changed

+18
-21
lines changed

2 files changed

+18
-21
lines changed

lib/std/fs/path.zig

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ pub const PathType = enum {
5757
posix,
5858

5959
/// Returns true if `c` is a valid path separator for the `path_type`.
60+
/// If `T` is `u16`, `c` is assumed to be little-endian.
6061
pub inline fn isSep(comptime path_type: PathType, comptime T: type, c: T) bool {
6162
return switch (path_type) {
62-
.windows => c == '/' or c == '\\',
63-
.posix => c == '/',
64-
.uefi => c == '\\',
63+
.windows => c == mem.nativeToLittle(T, '/') or c == mem.nativeToLittle(T, '\\'),
64+
.posix => c == mem.nativeToLittle(T, '/'),
65+
.uefi => c == mem.nativeToLittle(T, '\\'),
6566
};
6667
}
6768
};
@@ -2439,11 +2440,6 @@ test "ComponentIterator windows" {
24392440
}
24402441

24412442
test "ComponentIterator windows WTF-16" {
2442-
// TODO: Fix on big endian architectures
2443-
if (builtin.cpu.arch.endian() != .little) {
2444-
return error.SkipZigTest;
2445-
}
2446-
24472443
const WindowsComponentIterator = ComponentIterator(.windows, u16);
24482444
const L = std.unicode.utf8ToUtf16LeStringLiteral;
24492445

lib/std/os/windows.zig

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2491,15 +2491,15 @@ pub fn getWin32PathType(comptime T: type, path: []const T) Win32PathType {
24912491
if (path.len < 1) return .relative;
24922492

24932493
const windows_path = std.fs.path.PathType.windows;
2494-
if (windows_path.isSep(T, mem.littleToNative(T, path[0]))) {
2494+
if (windows_path.isSep(T, path[0])) {
24952495
// \x
2496-
if (path.len < 2 or !windows_path.isSep(T, mem.littleToNative(T, path[1]))) return .rooted;
2496+
if (path.len < 2 or !windows_path.isSep(T, path[1])) return .rooted;
24972497
// \\. or \\?
2498-
if (path.len > 2 and (mem.littleToNative(T, path[2]) == '.' or mem.littleToNative(T, path[2]) == '?')) {
2498+
if (path.len > 2 and (path[2] == mem.nativeToLittle(T, '.') or path[2] == mem.nativeToLittle(T, '?'))) {
24992499
// exactly \\. or \\? with nothing trailing
25002500
if (path.len == 3) return .root_local_device;
25012501
// \\.\x or \\?\x
2502-
if (windows_path.isSep(T, mem.littleToNative(T, path[3]))) return .local_device;
2502+
if (windows_path.isSep(T, path[3])) return .local_device;
25032503
}
25042504
// \\x
25052505
return .unc_absolute;
@@ -2538,9 +2538,9 @@ pub fn getWin32PathType(comptime T: type, path: []const T) Win32PathType {
25382538
else => @compileError("unsupported type: " ++ @typeName(T)),
25392539
};
25402540
// x
2541-
if (path.len < colon_i + 1 or mem.littleToNative(T, path[colon_i]) != ':') return .relative;
2541+
if (path.len < colon_i + 1 or path[colon_i] != mem.nativeToLittle(T, ':')) return .relative;
25422542
// x:\
2543-
if (path.len > colon_i + 1 and windows_path.isSep(T, mem.littleToNative(T, path[colon_i + 1]))) return .drive_absolute;
2543+
if (path.len > colon_i + 1 and windows_path.isSep(T, path[colon_i + 1])) return .drive_absolute;
25442544
// x:
25452545
return .drive_relative;
25462546
}
@@ -2632,12 +2632,13 @@ fn getLocalDevicePathType(comptime T: type, path: []const T) LocalDevicePathType
26322632
std.debug.assert(getWin32PathType(T, path) == .local_device);
26332633
}
26342634

2635-
const all_backslash = mem.littleToNative(T, path[0]) == '\\' and
2636-
mem.littleToNative(T, path[1]) == '\\' and
2637-
mem.littleToNative(T, path[3]) == '\\';
2638-
return switch (mem.littleToNative(T, path[2])) {
2639-
'?' => if (all_backslash) .verbatim else .fake_verbatim,
2640-
'.' => .local_device,
2635+
const backslash = mem.nativeToLittle(T, '\\');
2636+
const all_backslash = path[0] == backslash and
2637+
path[1] == backslash and
2638+
path[3] == backslash;
2639+
return switch (path[2]) {
2640+
mem.nativeToLittle(T, '?') => if (all_backslash) .verbatim else .fake_verbatim,
2641+
mem.nativeToLittle(T, '.') => .local_device,
26412642
else => unreachable,
26422643
};
26432644
}
@@ -2664,7 +2665,7 @@ pub fn ntToWin32Namespace(path: []const u16, out: []u16) error{ NameTooLong, Not
26642665
// `\??\UNC\` should be replaced by `\\` (two backslashes)
26652666
const is_unc = after_prefix.len >= 4 and
26662667
eqlIgnoreCaseWtf16(after_prefix[0..3], std.unicode.utf8ToUtf16LeStringLiteral("UNC")) and
2667-
std.fs.path.PathType.windows.isSep(u16, std.mem.littleToNative(u16, after_prefix[3]));
2668+
std.fs.path.PathType.windows.isSep(u16, after_prefix[3]);
26682669
const win32_len = path.len - @as(usize, if (is_unc) 6 else 4);
26692670
if (out.len < win32_len) return error.NameTooLong;
26702671
if (is_unc) {

0 commit comments

Comments
 (0)