mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
windows: workaround kernel race condition in more places
This commit is contained in:
parent
595cd8935a
commit
cc3c4d1069
@ -71,19 +71,7 @@ pub fn main() anyerror!void {
|
|||||||
try testExec(allocator, "heLLo", "hello from exe\n");
|
try testExec(allocator, "heLLo", "hello from exe\n");
|
||||||
|
|
||||||
// now rename the exe to not have an extension
|
// now rename the exe to not have an extension
|
||||||
{
|
try renameExe(tmp.dir, "hello.exe", "hello");
|
||||||
var attempt: u5 = 0;
|
|
||||||
while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
|
|
||||||
error.AccessDenied => {
|
|
||||||
if (attempt == 13) return error.AccessDenied;
|
|
||||||
// give the kernel a chance to finish closing the executable handle
|
|
||||||
std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
|
|
||||||
attempt += 1;
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
else => |e| return e,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// with extension should now fail
|
// with extension should now fail
|
||||||
try testExecError(error.FileNotFound, allocator, "hello.exe");
|
try testExecError(error.FileNotFound, allocator, "hello.exe");
|
||||||
@ -91,7 +79,7 @@ pub fn main() anyerror!void {
|
|||||||
try testExec(allocator, "heLLo", "hello from exe\n");
|
try testExec(allocator, "heLLo", "hello from exe\n");
|
||||||
|
|
||||||
try tmp.dir.makeDir("something");
|
try tmp.dir.makeDir("something");
|
||||||
try tmp.dir.rename("hello", "something/hello.exe");
|
try renameExe(tmp.dir, "hello", "something/hello.exe");
|
||||||
|
|
||||||
const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });
|
const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });
|
||||||
defer allocator.free(relative_path_no_ext);
|
defer allocator.free(relative_path_no_ext);
|
||||||
@ -118,14 +106,14 @@ pub fn main() anyerror!void {
|
|||||||
try testExecError(error.InvalidExe, allocator, "hello");
|
try testExecError(error.InvalidExe, allocator, "hello");
|
||||||
|
|
||||||
// If we now rename hello.exe to have no extension, it will behave differently
|
// If we now rename hello.exe to have no extension, it will behave differently
|
||||||
try tmp.dir.rename("hello.exe", "hello");
|
try renameExe(tmp.dir, "hello.exe", "hello");
|
||||||
|
|
||||||
// Now, trying to execute it without an extension should treat InvalidExe as recoverable
|
// Now, trying to execute it without an extension should treat InvalidExe as recoverable
|
||||||
// and skip over it and find hello.bat and execute that
|
// and skip over it and find hello.bat and execute that
|
||||||
try testExec(allocator, "hello", "hello from bat\r\n");
|
try testExec(allocator, "hello", "hello from bat\r\n");
|
||||||
|
|
||||||
// If we rename the invalid exe to something else
|
// If we rename the invalid exe to something else
|
||||||
try tmp.dir.rename("hello", "goodbye");
|
try renameExe(tmp.dir, "hello", "goodbye");
|
||||||
// Then we should now get FileNotFound when trying to execute 'goodbye',
|
// Then we should now get FileNotFound when trying to execute 'goodbye',
|
||||||
// since that is what the original error will be after searching for 'goodbye'
|
// since that is what the original error will be after searching for 'goodbye'
|
||||||
// in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error
|
// 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 {
|
|||||||
try testExec(allocator, "hello", "hello from bat\r\n");
|
try testExec(allocator, "hello", "hello from bat\r\n");
|
||||||
|
|
||||||
// If we rename something/hello.exe to something/goodbye.exe
|
// If we rename something/hello.exe to something/goodbye.exe
|
||||||
try tmp.dir.rename("something/hello.exe", "something/goodbye.exe");
|
try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");
|
||||||
// And try to execute goodbye, then the one in something should be found
|
// And try to execute goodbye, then the one in something should be found
|
||||||
// since the one in cwd is an invalid executable
|
// since the one in cwd is an invalid executable
|
||||||
try testExec(allocator, "goodbye", "hello from exe\n");
|
try testExec(allocator, "goodbye", "hello from exe\n");
|
||||||
@ -196,7 +184,7 @@ pub fn main() anyerror!void {
|
|||||||
var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
|
var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
|
||||||
defer subdir_cwd.close();
|
defer subdir_cwd.close();
|
||||||
|
|
||||||
try tmp.dir.rename("something/goodbye.exe", "hello.exe");
|
try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");
|
||||||
try subdir_cwd.setAsCwd();
|
try subdir_cwd.setAsCwd();
|
||||||
|
|
||||||
// clear the PATH again
|
// clear the PATH again
|
||||||
@ -229,3 +217,17 @@ fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]co
|
|||||||
try std.testing.expectEqualStrings("", result.stderr);
|
try std.testing.expectEqualStrings("", result.stderr);
|
||||||
try std.testing.expectEqualStrings(expected_stdout, result.stdout);
|
try std.testing.expectEqualStrings(expected_stdout, result.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renameExe(dir: std.fs.Dir, old_sub_path: []const u8, new_sub_path: []const u8) !void {
|
||||||
|
var attempt: u5 = 0;
|
||||||
|
while (true) break dir.rename(old_sub_path, new_sub_path) catch |err| switch (err) {
|
||||||
|
error.AccessDenied => {
|
||||||
|
if (attempt == 13) return error.AccessDenied;
|
||||||
|
// give the kernel a chance to finish closing the executable handle
|
||||||
|
std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
|
||||||
|
attempt += 1;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user