| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | |
| 2 | const windows = std.os.windows; | 3 | const windows = std.os.windows; |
| 3 | const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral; | 4 | const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral; |
| 4 | | 5 | |
| ... | @@ -39,6 +40,9 @@ pub fn main() anyerror!void { | ... | @@ -39,6 +40,9 @@ pub fn main() anyerror!void { |
| 39 | // No PATH, so it should fail to find anything not in the cwd | 40 | // No PATH, so it should fail to find anything not in the cwd |
| 40 | try testExecError(error.FileNotFound, allocator, "something_missing"); | 41 | try testExecError(error.FileNotFound, allocator, "something_missing"); |
| 41 | | 42 | |
| | 43 | // make sure we don't get error.BadPath traversing out of cwd with a relative path |
| | 44 | try testExecError(error.FileNotFound, allocator, "..\\.\\.\\.\\\\..\\more_missing"); |
| | 45 | |
| 42 | std.debug.assert(windows.kernel32.SetEnvironmentVariableW( | 46 | std.debug.assert(windows.kernel32.SetEnvironmentVariableW( |
| 43 | utf16Literal("PATH"), | 47 | utf16Literal("PATH"), |
| 44 | tmp_absolute_path_w, | 48 | tmp_absolute_path_w, |
| ... | @@ -149,6 +153,48 @@ pub fn main() anyerror!void { | ... | @@ -149,6 +153,48 @@ pub fn main() anyerror!void { |
| 149 | // If we try to exec but provide a cwd that is an absolute path, the PATH | 153 | // If we try to exec but provide a cwd that is an absolute path, the PATH |
| 150 | // should still be searched and the goodbye.exe in something should be found. | 154 | // should still be searched and the goodbye.exe in something should be found. |
| 151 | try testExecWithCwd(allocator, "goodbye", tmp_absolute_path, "hello from exe\n"); | 155 | try testExecWithCwd(allocator, "goodbye", tmp_absolute_path, "hello from exe\n"); |
| | 156 | |
| | 157 | // introduce some extra path separators into the path which is dealt with inside the spawn call. |
| | 158 | const denormed_something_subdir_size = std.mem.replacementSize(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\")); |
| | 159 | |
| | 160 | const denormed_something_subdir_abs_path = try allocator.allocSentinel(u16, denormed_something_subdir_size, 0); |
| | 161 | defer allocator.free(denormed_something_subdir_abs_path); |
| | 162 | |
| | 163 | _ = std.mem.replace(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"), denormed_something_subdir_abs_path); |
| | 164 | |
| | 165 | const denormed_something_subdir_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, denormed_something_subdir_abs_path); |
| | 166 | defer allocator.free(denormed_something_subdir_wtf8); |
| | 167 | |
| | 168 | // clear the path to ensure that the match comes from the cwd |
| | 169 | std.debug.assert(windows.kernel32.SetEnvironmentVariableW( |
| | 170 | utf16Literal("PATH"), |
| | 171 | null, |
| | 172 | ) == windows.TRUE); |
| | 173 | |
| | 174 | try testExecWithCwd(allocator, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n"); |
| | 175 | |
| | 176 | // normalization should also work if the non-normalized path is found in the PATH var. |
| | 177 | std.debug.assert(windows.kernel32.SetEnvironmentVariableW( |
| | 178 | utf16Literal("PATH"), |
| | 179 | denormed_something_subdir_abs_path, |
| | 180 | ) == windows.TRUE); |
| | 181 | try testExec(allocator, "goodbye", "hello from exe\n"); |
| | 182 | |
| | 183 | // now make sure we can launch executables "outside" of the cwd |
| | 184 | var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{}); |
| | 185 | defer subdir_cwd.close(); |
| | 186 | |
| | 187 | try tmp.dir.rename("something/goodbye.exe", "hello.exe"); |
| | 188 | try subdir_cwd.setAsCwd(); |
| | 189 | |
| | 190 | // clear the PATH again |
| | 191 | std.debug.assert(windows.kernel32.SetEnvironmentVariableW( |
| | 192 | utf16Literal("PATH"), |
| | 193 | null, |
| | 194 | ) == windows.TRUE); |
| | 195 | |
| | 196 | // while we're at it make sure non-windows separators work fine |
| | 197 | try testExec(allocator, "../hello", "hello from exe\n"); |
| 152 | } | 198 | } |
| 153 | | 199 | |
| 154 | fn testExecError(err: anyerror, allocator: std.mem.Allocator, command: []const u8) !void { | 200 | fn testExecError(err: anyerror, allocator: std.mem.Allocator, command: []const u8) !void { |