authorgravatar for ybham6@gmail.comfifty-six <ybham6@gmail.com> 2022-01-11 01:05:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-11 10:49:40-07:00
log41fd343508880ffdfbc83c7b053237da09199f02
tree2bbc476dbc114f7c762430d95d1470ad0dfcd8a9
parentf4b3f1d6022265992f87cea1d9591ffa8ec226d6

std: fix path joining on UEFI

UEFI uses `\` for paths exclusively. This changes std.fs.path to use `\` for UEFI path joining. Also adds a few tests regarding it, specifically in making sure double-separators do not result from path joining, as the UEFI spec says to convert any that result from joining into single separators (UEFI Spec Version 2.7, pg. 448).

1 files changed, 28 insertions(+), 12 deletions(-)

lib/std/fs/path.zig+28-12
...@@ -12,13 +12,13 @@ const fs = std.fs;...@@ -12,13 +12,13 @@ const fs = std.fs;
12const process = std.process;12const process = std.process;
13const native_os = builtin.target.os.tag;13const native_os = builtin.target.os.tag;
1414
15pub const sep_windows = '\\';15pub const sep_windows_uefi = '\\';
16pub const sep_posix = '/';16pub const sep_posix = '/';
17pub const sep = if (native_os == .windows) sep_windows else sep_posix;17pub const sep = if (native_os == .windows or native_os == .uefi) sep_windows_uefi else sep_posix;
1818
19pub const sep_str_windows = "\\";19pub const sep_str_windows_uefi = "\\";
20pub const sep_str_posix = "/";20pub const sep_str_posix = "/";
21pub const sep_str = if (native_os == .windows) sep_str_windows else sep_str_posix;21pub const sep_str = if (native_os == .windows or native_os == .uefi) sep_str_windows_uefi else sep_str_posix;
2222
23pub const delimiter_windows = ';';23pub const delimiter_windows = ';';
24pub const delimiter_posix = ':';24pub const delimiter_posix = ':';
...@@ -26,11 +26,11 @@ pub const delimiter = if (native_os == .windows) delimiter_windows else delimite...@@ -26,11 +26,11 @@ pub const delimiter = if (native_os == .windows) delimiter_windows else delimite
2626
27/// Returns if the given byte is a valid path separator27/// Returns if the given byte is a valid path separator
28pub fn isSep(byte: u8) bool {28pub fn isSep(byte: u8) bool {
29 if (native_os == .windows) {29 return switch (native_os) {
30 return byte == '/' or byte == '\\';30 .windows => byte == '/' or byte == '\\',
31 } else {31 .uefi => byte == '\\',
32 return byte == '/';32 else => byte == '/',
33 }33 };
34}34}
3535
36/// This is different from mem.join in that the separator will not be repeated if36/// This is different from mem.join in that the separator will not be repeated if
...@@ -110,13 +110,24 @@ pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 {...@@ -110,13 +110,24 @@ pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 {
110 return out[0 .. out.len - 1 :0];110 return out[0 .. out.len - 1 :0];
111}111}
112112
113fn testJoinMaybeZUefi(paths: []const []const u8, expected: []const u8, zero: bool) !void {
114 const uefiIsSep = struct {
115 fn isSep(byte: u8) bool {
116 return byte == '\\';
117 }
118 }.isSep;
119 const actual = try joinSepMaybeZ(testing.allocator, sep_windows_uefi, uefiIsSep, paths, zero);
120 defer testing.allocator.free(actual);
121 try testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
122}
123
113fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) !void {124fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) !void {
114 const windowsIsSep = struct {125 const windowsIsSep = struct {
115 fn isSep(byte: u8) bool {126 fn isSep(byte: u8) bool {
116 return byte == '/' or byte == '\\';127 return byte == '/' or byte == '\\';
117 }128 }
118 }.isSep;129 }.isSep;
119 const actual = try joinSepMaybeZ(testing.allocator, sep_windows, windowsIsSep, paths, zero);130 const actual = try joinSepMaybeZ(testing.allocator, sep_windows_uefi, windowsIsSep, paths, zero);
120 defer testing.allocator.free(actual);131 defer testing.allocator.free(actual);
121 try testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);132 try testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
122}133}
...@@ -158,6 +169,11 @@ test "join" {...@@ -158,6 +169,11 @@ test "join" {
158 zero,169 zero,
159 );170 );
160171
172 try testJoinMaybeZUefi(&[_][]const u8{ "EFI", "Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero);
173 try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero);
174 try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\", "\\Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero);
175 try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\", "\\Boot\\", "\\bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero);
176
161 try testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero);177 try testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero);
162 try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero);178 try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero);
163179
...@@ -588,7 +604,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {...@@ -588,7 +604,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
588 result[0] = asciiUpper(result[0]);604 result[0] = asciiUpper(result[0]);
589 // Remove the trailing slash if present, eg. if the cwd is a root605 // Remove the trailing slash if present, eg. if the cwd is a root
590 // directory.606 // directory.
591 if (cwd.len > 0 and cwd[cwd.len - 1] == sep_windows) {607 if (cwd.len > 0 and cwd[cwd.len - 1] == sep_windows_uefi) {
592 result_index -= 1;608 result_index -= 1;
593 }609 }
594 }610 }
...@@ -625,7 +641,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {...@@ -625,7 +641,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
625 break;641 break;
626 }642 }
627 } else {643 } else {
628 result[result_index] = sep_windows;644 result[result_index] = sep_windows_uefi;
629 result_index += 1;645 result_index += 1;
630 mem.copy(u8, result[result_index..], component);646 mem.copy(u8, result[result_index..], component);
631 result_index += component.len;647 result_index += component.len;