| ... | ... | @@ -71,19 +71,7 @@ pub fn main() anyerror!void { |
| 71 | 71 | try testExec(allocator, "heLLo", "hello from exe\n"); |
| 72 | 72 | |
| 73 | 73 | // now rename the exe to not have an extension |
| 74 | | { |
| 75 | | var attempt: u5 = 0; |
| 76 | | while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) { |
| 77 | | error.AccessDenied => { |
| 78 | | if (attempt == 13) return error.AccessDenied; |
| 79 | | // give the kernel a chance to finish closing the executable handle |
| 80 | | std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1); |
| 81 | | attempt += 1; |
| 82 | | continue; |
| 83 | | }, |
| 84 | | else => |e| return e, |
| 85 | | }; |
| 86 | | } |
| 74 | try renameExe(tmp.dir, "hello.exe", "hello"); |
| 87 | 75 | |
| 88 | 76 | // with extension should now fail |
| 89 | 77 | try testExecError(error.FileNotFound, allocator, "hello.exe"); |
| ... | ... | @@ -91,7 +79,7 @@ pub fn main() anyerror!void { |
| 91 | 79 | try testExec(allocator, "heLLo", "hello from exe\n"); |
| 92 | 80 | |
| 93 | 81 | try tmp.dir.makeDir("something"); |
| 94 | | try tmp.dir.rename("hello", "something/hello.exe"); |
| 82 | try renameExe(tmp.dir, "hello", "something/hello.exe"); |
| 95 | 83 | |
| 96 | 84 | const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" }); |
| 97 | 85 | defer allocator.free(relative_path_no_ext); |
| ... | ... | @@ -118,14 +106,14 @@ pub fn main() anyerror!void { |
| 118 | 106 | try testExecError(error.InvalidExe, allocator, "hello"); |
| 119 | 107 | |
| 120 | 108 | // If we now rename hello.exe to have no extension, it will behave differently |
| 121 | | try tmp.dir.rename("hello.exe", "hello"); |
| 109 | try renameExe(tmp.dir, "hello.exe", "hello"); |
| 122 | 110 | |
| 123 | 111 | // Now, trying to execute it without an extension should treat InvalidExe as recoverable |
| 124 | 112 | // and skip over it and find hello.bat and execute that |
| 125 | 113 | try testExec(allocator, "hello", "hello from bat\r\n"); |
| 126 | 114 | |
| 127 | 115 | // If we rename the invalid exe to something else |
| 128 | | try tmp.dir.rename("hello", "goodbye"); |
| 116 | try renameExe(tmp.dir, "hello", "goodbye"); |
| 129 | 117 | // Then we should now get FileNotFound when trying to execute 'goodbye', |
| 130 | 118 | // since that is what the original error will be after searching for 'goodbye' |
| 131 | 119 | // in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error |
| ... | ... | @@ -151,7 +139,7 @@ pub fn main() anyerror!void { |
| 151 | 139 | try testExec(allocator, "hello", "hello from bat\r\n"); |
| 152 | 140 | |
| 153 | 141 | // If we rename something/hello.exe to something/goodbye.exe |
| 154 | | try tmp.dir.rename("something/hello.exe", "something/goodbye.exe"); |
| 142 | try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe"); |
| 155 | 143 | // And try to execute goodbye, then the one in something should be found |
| 156 | 144 | // since the one in cwd is an invalid executable |
| 157 | 145 | try testExec(allocator, "goodbye", "hello from exe\n"); |
| ... | ... | @@ -196,7 +184,7 @@ pub fn main() anyerror!void { |
| 196 | 184 | var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{}); |
| 197 | 185 | defer subdir_cwd.close(); |
| 198 | 186 | |
| 199 | | try tmp.dir.rename("something/goodbye.exe", "hello.exe"); |
| 187 | try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe"); |
| 200 | 188 | try subdir_cwd.setAsCwd(); |
| 201 | 189 | |
| 202 | 190 | // clear the PATH again |
| ... | ... | @@ -229,3 +217,17 @@ fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]co |
| 229 | 217 | try std.testing.expectEqualStrings("", result.stderr); |
| 230 | 218 | try std.testing.expectEqualStrings(expected_stdout, result.stdout); |
| 231 | 219 | } |
| 220 | |
| 221 | fn renameExe(dir: std.fs.Dir, old_sub_path: []const u8, new_sub_path: []const u8) !void { |
| 222 | var attempt: u5 = 0; |
| 223 | while (true) break dir.rename(old_sub_path, new_sub_path) catch |err| switch (err) { |
| 224 | error.AccessDenied => { |
| 225 | if (attempt == 13) return error.AccessDenied; |
| 226 | // give the kernel a chance to finish closing the executable handle |
| 227 | std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1); |
| 228 | attempt += 1; |
| 229 | continue; |
| 230 | }, |
| 231 | else => |e| return e, |
| 232 | }; |
| 233 | } |