authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-08 20:03:50-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:08-08:00
log4a53e5b0b4131c6b8e18bb551e8215e425f8ac71
tree4af8d360db353e40c74db394a9d03de1fdce9282
parentebdbbd20ace6e93b581b90075f52946b3832da93

fix a handful of compilation errors related to std.fs migration


24 files changed, 148 insertions(+), 133 deletions(-)

lib/compiler/resinator/cli.zig+1-1
...@@ -2010,7 +2010,7 @@ test "maybeAppendRC" {...@@ -2010,7 +2010,7 @@ test "maybeAppendRC" {
20102010
2011 // Now delete the file and try again. But this time change the input format2011 // Now delete the file and try again. But this time change the input format
2012 // to non-rc.2012 // to non-rc.
2013 try tmp.dir.deleteFile("foo");2013 try tmp.dir.deleteFile(io, "foo");
2014 options.input_format = .res;2014 options.input_format = .res;
2015 try options.maybeAppendRC(io, tmp.dir);2015 try options.maybeAppendRC(io, tmp.dir);
2016 try std.testing.expectEqualStrings("foo", options.input_source.filename);2016 try std.testing.expectEqualStrings("foo", options.input_source.filename);
lib/compiler/resinator/main.zig+1-1
...@@ -440,7 +440,7 @@ const IoStream = struct {...@@ -440,7 +440,7 @@ const IoStream = struct {
440 // Delete the output file on error440 // Delete the output file on error
441 file.close(io);441 file.close(io);
442 // Failing to delete is not really a big deal, so swallow any errors442 // Failing to delete is not really a big deal, so swallow any errors
443 Io.Dir.cwd().deleteFile(self.name) catch {};443 Io.Dir.cwd().deleteFile(io, self.name) catch {};
444 },444 },
445 .stdio, .memory, .closed => return,445 .stdio, .memory, .closed => return,
446 }446 }
lib/compiler/std-docs.zig+9-9
...@@ -72,8 +72,8 @@ pub fn main() !void {...@@ -72,8 +72,8 @@ pub fn main() !void {
72 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});72 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
73 std.Io.File.stdout().writeAll(url_with_newline) catch {};73 std.Io.File.stdout().writeAll(url_with_newline) catch {};
74 if (should_open_browser) {74 if (should_open_browser) {
75 openBrowserTab(gpa, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {75 openBrowserTab(gpa, io, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {
76 std.log.err("unable to open browser: {s}", .{@errorName(err)});76 std.log.err("unable to open browser: {t}", .{err});
77 };77 };
78 }78 }
7979
...@@ -89,7 +89,7 @@ pub fn main() !void {...@@ -89,7 +89,7 @@ pub fn main() !void {
89 while (true) {89 while (true) {
90 const connection = try http_server.accept();90 const connection = try http_server.accept();
91 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {91 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {
92 std.log.err("unable to accept connection: {s}", .{@errorName(err)});92 std.log.err("unable to accept connection: {t}", .{err});
93 connection.stream.close(io);93 connection.stream.close(io);
94 continue;94 continue;
95 };95 };
...@@ -328,7 +328,7 @@ fn buildWasmBinary(...@@ -328,7 +328,7 @@ fn buildWasmBinary(
328 child.stdin_behavior = .Pipe;328 child.stdin_behavior = .Pipe;
329 child.stdout_behavior = .Pipe;329 child.stdout_behavior = .Pipe;
330 child.stderr_behavior = .Pipe;330 child.stderr_behavior = .Pipe;
331 try child.spawn();331 try child.spawn(io);
332332
333 var poller = std.Io.poll(gpa, enum { stdout, stderr }, .{333 var poller = std.Io.poll(gpa, enum { stdout, stderr }, .{
334 .stdout = child.stdout.?,334 .stdout = child.stdout.?,
...@@ -434,13 +434,13 @@ fn sendMessage(io: Io, file: std.Io.File, tag: std.zig.Client.Message.Tag) !void...@@ -434,13 +434,13 @@ fn sendMessage(io: Io, file: std.Io.File, tag: std.zig.Client.Message.Tag) !void
434 };434 };
435}435}
436436
437fn openBrowserTab(gpa: Allocator, url: []const u8) !void {437fn openBrowserTab(gpa: Allocator, io: Io, url: []const u8) !void {
438 // Until https://github.com/ziglang/zig/issues/19205 is implemented, we438 // Until https://github.com/ziglang/zig/issues/19205 is implemented, we
439 // spawn a thread for this child process.439 // spawn a thread for this child process.
440 _ = try std.Thread.spawn(.{}, openBrowserTabThread, .{ gpa, url });440 _ = try std.Thread.spawn(.{}, openBrowserTabThread, .{ gpa, io, url });
441}441}
442442
443fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {443fn openBrowserTabThread(gpa: Allocator, io: Io, url: []const u8) !void {
444 const main_exe = switch (builtin.os.tag) {444 const main_exe = switch (builtin.os.tag) {
445 .windows => "explorer",445 .windows => "explorer",
446 .macos => "open",446 .macos => "open",
...@@ -450,6 +450,6 @@ fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {...@@ -450,6 +450,6 @@ fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {
450 child.stdin_behavior = .Ignore;450 child.stdin_behavior = .Ignore;
451 child.stdout_behavior = .Ignore;451 child.stdout_behavior = .Ignore;
452 child.stderr_behavior = .Ignore;452 child.stderr_behavior = .Ignore;
453 try child.spawn();453 try child.spawn(io);
454 _ = try child.wait();454 _ = try child.wait(io);
455}455}
lib/std/Build.zig+1-1
...@@ -1838,7 +1838,7 @@ pub fn runAllowFail(...@@ -1838,7 +1838,7 @@ pub fn runAllowFail(
1838 child.env_map = &b.graph.env_map;1838 child.env_map = &b.graph.env_map;
18391839
1840 try Step.handleVerbose2(b, null, child.env_map, argv);1840 try Step.handleVerbose2(b, null, child.env_map, argv);
1841 try child.spawn();1841 try child.spawn(io);
18421842
1843 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});1843 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
1844 const stdout = stdout_reader.interface.allocRemaining(b.allocator, .limited(max_output_size)) catch {1844 const stdout = stdout_reader.interface.allocRemaining(b.allocator, .limited(max_output_size)) catch {
lib/std/Build/Cache.zig+1-1
...@@ -1300,7 +1300,7 @@ fn testGetCurrentFileTimestamp(io: Io, dir: Io.Dir) !Io.Timestamp {...@@ -1300,7 +1300,7 @@ fn testGetCurrentFileTimestamp(io: Io, dir: Io.Dir) !Io.Timestamp {
1300 });1300 });
1301 defer {1301 defer {
1302 file.close(io);1302 file.close(io);
1303 dir.deleteFile(test_out_file) catch {};1303 dir.deleteFile(io, test_out_file) catch {};
1304 }1304 }
13051305
1306 return (try file.stat(io)).mtime;1306 return (try file.stat(io)).mtime;
lib/std/Build/Step.zig+1-1
...@@ -455,7 +455,7 @@ pub fn evalZigProcess(...@@ -455,7 +455,7 @@ pub fn evalZigProcess(
455 child.request_resource_usage_statistics = true;455 child.request_resource_usage_statistics = true;
456 child.progress_node = prog_node;456 child.progress_node = prog_node;
457457
458 child.spawn() catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });458 child.spawn(io) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
459459
460 const zp = try gpa.create(ZigProcess);460 const zp = try gpa.create(ZigProcess);
461 zp.* = .{461 zp.* = .{
lib/std/Build/Step/Run.zig+2-2
...@@ -1689,7 +1689,7 @@ fn evalZigTest(...@@ -1689,7 +1689,7 @@ fn evalZigTest(
1689 };1689 };
16901690
1691 while (true) {1691 while (true) {
1692 try child.spawn();1692 try child.spawn(io);
1693 var poller = std.Io.poll(gpa, StdioPollEnum, .{1693 var poller = std.Io.poll(gpa, StdioPollEnum, .{
1694 .stdout = child.stdout.?,1694 .stdout = child.stdout.?,
1695 .stderr = child.stderr.?,1695 .stderr = child.stderr.?,
...@@ -2168,7 +2168,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {...@@ -2168,7 +2168,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
2168 const io = b.graph.io;2168 const io = b.graph.io;
2169 const arena = b.allocator;2169 const arena = b.allocator;
21702170
2171 try child.spawn();2171 try child.spawn(io);
2172 errdefer _ = child.kill(io) catch {};2172 errdefer _ = child.kill(io) catch {};
21732173
2174 try child.waitForSpawn();2174 try child.waitForSpawn();
lib/std/Build/WebServer.zig+1-1
...@@ -580,7 +580,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim...@@ -580,7 +580,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
580 child.stdin_behavior = .Pipe;580 child.stdin_behavior = .Pipe;
581 child.stdout_behavior = .Pipe;581 child.stdout_behavior = .Pipe;
582 child.stderr_behavior = .Pipe;582 child.stderr_behavior = .Pipe;
583 try child.spawn();583 try child.spawn(io);
584584
585 var poller = Io.poll(gpa, enum { stdout, stderr }, .{585 var poller = Io.poll(gpa, enum { stdout, stderr }, .{
586 .stdout = child.stdout.?,586 .stdout = child.stdout.?,
lib/std/Io/Dir.zig+4-3
...@@ -1366,7 +1366,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {...@@ -1366,7 +1366,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void {
1366 => |e| return e,1366 => |e| return e,
1367 };1367 };
1368 } else {1368 } else {
1369 if (parent_dir.deleteFile(name)) {1369 if (parent_dir.deleteFile(io, name)) {
1370 continue :process_stack;1370 continue :process_stack;
1371 } else |err| switch (err) {1371 } else |err| switch (err) {
1372 error.FileNotFound => continue :process_stack,1372 error.FileNotFound => continue :process_stack,
...@@ -1477,7 +1477,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,...@@ -1477,7 +1477,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
1477 dir_name = result;1477 dir_name = result;
1478 continue :scan_dir;1478 continue :scan_dir;
1479 } else {1479 } else {
1480 if (dir.deleteFile(entry.name)) {1480 if (dir.deleteFile(io, entry.name)) {
1481 continue :dir_it;1481 continue :dir_it;
1482 } else |err| switch (err) {1482 } else |err| switch (err) {
1483 error.FileNotFound => continue :dir_it,1483 error.FileNotFound => continue :dir_it,
...@@ -1567,7 +1567,7 @@ fn deleteTreeOpenInitialSubpath(dir: Dir, io: Io, sub_path: []const u8, kind_hin...@@ -1567,7 +1567,7 @@ fn deleteTreeOpenInitialSubpath(dir: Dir, io: Io, sub_path: []const u8, kind_hin
1567 => |e| return e,1567 => |e| return e,
1568 };1568 };
1569 } else {1569 } else {
1570 if (dir.deleteFile(sub_path)) {1570 if (dir.deleteFile(io, sub_path)) {
1571 return null;1571 return null;
1572 } else |err| switch (err) {1572 } else |err| switch (err) {
1573 error.FileNotFound => return null,1573 error.FileNotFound => return null,
...@@ -1588,6 +1588,7 @@ fn deleteTreeOpenInitialSubpath(dir: Dir, io: Io, sub_path: []const u8, kind_hin...@@ -1588,6 +1588,7 @@ fn deleteTreeOpenInitialSubpath(dir: Dir, io: Io, sub_path: []const u8, kind_hin
1588 error.FileBusy,1588 error.FileBusy,
1589 error.BadPathName,1589 error.BadPathName,
1590 error.NetworkNotFound,1590 error.NetworkNotFound,
1591 error.Canceled,
1591 error.Unexpected,1592 error.Unexpected,
1592 => |e| return e,1593 => |e| return e,
1593 }1594 }
lib/std/Io/File.zig+4
...@@ -407,6 +407,10 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(...@@ -407,6 +407,10 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
407 return @intFromEnum(self);407 return @intFromEnum(self);
408 }408 }
409409
410 pub fn fromMode(mode: std.posix.mode_t) @This() {
411 return @enumFromInt(mode);
412 }
413
410 /// Returns `true` if and only if no class has write permissions.414 /// Returns `true` if and only if no class has write permissions.
411 pub fn readOnly(self: @This()) bool {415 pub fn readOnly(self: @This()) bool {
412 const mode = toMode(self);416 const mode = toMode(self);
lib/std/Io/File/Atomic.zig+5-2
...@@ -20,7 +20,7 @@ pub const InitError = File.OpenError;...@@ -20,7 +20,7 @@ pub const InitError = File.OpenError;
20pub fn init(20pub fn init(
21 io: Io,21 io: Io,
22 dest_basename: []const u8,22 dest_basename: []const u8,
23 mode: File.Mode,23 permissions: File.Permissions,
24 dir: Dir,24 dir: Dir,
25 close_dir_on_deinit: bool,25 close_dir_on_deinit: bool,
26 write_buffer: []u8,26 write_buffer: []u8,
...@@ -28,7 +28,10 @@ pub fn init(...@@ -28,7 +28,10 @@ pub fn init(
28 while (true) {28 while (true) {
29 const random_integer = std.crypto.random.int(u64);29 const random_integer = std.crypto.random.int(u64);
30 const tmp_sub_path = std.fmt.hex(random_integer);30 const tmp_sub_path = std.fmt.hex(random_integer);
31 const file = dir.createFile(io, &tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) {31 const file = dir.createFile(io, &tmp_sub_path, .{
32 .permissions = permissions,
33 .exclusive = true,
34 }) catch |err| switch (err) {
32 error.PathAlreadyExists => continue,35 error.PathAlreadyExists => continue,
33 else => |e| return e,36 else => |e| return e,
34 };37 };
lib/std/Io/net/test.zig+1-1
...@@ -278,7 +278,7 @@ test "listen on a unix socket, send bytes, receive bytes" {...@@ -278,7 +278,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
278 defer testing.allocator.free(socket_path);278 defer testing.allocator.free(socket_path);
279279
280 const socket_addr = try net.UnixAddress.init(socket_path);280 const socket_addr = try net.UnixAddress.init(socket_path);
281 defer Io.Dir.cwd().deleteFile(socket_path) catch {};281 defer Io.Dir.cwd().deleteFile(io, socket_path) catch {};
282282
283 var server = try socket_addr.listen(io, .{});283 var server = try socket_addr.listen(io, .{});
284 defer server.socket.close(io);284 defer server.socket.close(io);
lib/std/Io/test.zig+1-1
...@@ -60,7 +60,7 @@ test "write a file, read it, then delete it" {...@@ -60,7 +60,7 @@ test "write a file, read it, then delete it" {
60 try expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));60 try expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));
61 try expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));61 try expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
62 }62 }
63 try tmp.dir.deleteFile(tmp_file_name);63 try tmp.dir.deleteFile(io, tmp_file_name);
64}64}
6565
66test "File seek ops" {66test "File seek ops" {
lib/std/fs/test.zig+13-13
...@@ -873,7 +873,7 @@ test "file operations on directories" {...@@ -873,7 +873,7 @@ test "file operations on directories" {
873 try ctx.dir.makeDir(io, test_dir_name, .default_dir);873 try ctx.dir.makeDir(io, test_dir_name, .default_dir);
874874
875 try testing.expectError(error.IsDir, ctx.dir.createFile(io, test_dir_name, .{}));875 try testing.expectError(error.IsDir, ctx.dir.createFile(io, test_dir_name, .{}));
876 try testing.expectError(error.IsDir, ctx.dir.deleteFile(test_dir_name));876 try testing.expectError(error.IsDir, ctx.dir.deleteFile(io, test_dir_name));
877 switch (native_os) {877 switch (native_os) {
878 .dragonfly, .netbsd => {878 .dragonfly, .netbsd => {
879 // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732879 // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732
...@@ -942,7 +942,7 @@ test "deleteDir" {...@@ -942,7 +942,7 @@ test "deleteDir" {
942 try testing.expectError(error.DirNotEmpty, ctx.dir.deleteDir(test_dir_path));942 try testing.expectError(error.DirNotEmpty, ctx.dir.deleteDir(test_dir_path));
943943
944 // deleting an empty directory944 // deleting an empty directory
945 try ctx.dir.deleteFile(test_file_path);945 try ctx.dir.deleteFile(io, test_file_path);
946 try ctx.dir.deleteDir(test_dir_path);946 try ctx.dir.deleteDir(test_dir_path);
947 }947 }
948 }.impl);948 }.impl);
...@@ -1671,13 +1671,13 @@ test "copyFile" {...@@ -1671,13 +1671,13 @@ test "copyFile" {
1671 const dest_file2 = try ctx.transformPath("tmp_test_copy_file3.txt");1671 const dest_file2 = try ctx.transformPath("tmp_test_copy_file3.txt");
16721672
1673 try ctx.dir.writeFile(io, .{ .sub_path = src_file, .data = data });1673 try ctx.dir.writeFile(io, .{ .sub_path = src_file, .data = data });
1674 defer ctx.dir.deleteFile(src_file) catch {};1674 defer ctx.dir.deleteFile(io, src_file) catch {};
16751675
1676 try ctx.dir.copyFile(src_file, ctx.dir, dest_file, .{});1676 try ctx.dir.copyFile(src_file, ctx.dir, dest_file, .{});
1677 defer ctx.dir.deleteFile(dest_file) catch {};1677 defer ctx.dir.deleteFile(io, dest_file) catch {};
16781678
1679 try ctx.dir.copyFile(src_file, ctx.dir, dest_file2, .{ .override_mode = File.default_mode });1679 try ctx.dir.copyFile(src_file, ctx.dir, dest_file2, .{ .override_mode = File.default_mode });
1680 defer ctx.dir.deleteFile(dest_file2) catch {};1680 defer ctx.dir.deleteFile(io, dest_file2) catch {};
16811681
1682 try expectFileContents(io, ctx.dir, dest_file, data);1682 try expectFileContents(io, ctx.dir, dest_file, data);
1683 try expectFileContents(io, ctx.dir, dest_file2, data);1683 try expectFileContents(io, ctx.dir, dest_file2, data);
...@@ -1713,7 +1713,7 @@ test "AtomicFile" {...@@ -1713,7 +1713,7 @@ test "AtomicFile" {
1713 const content = try ctx.dir.readFileAlloc(io, test_out_file, allocator, .limited(9999));1713 const content = try ctx.dir.readFileAlloc(io, test_out_file, allocator, .limited(9999));
1714 try testing.expectEqualStrings(test_content, content);1714 try testing.expectEqualStrings(test_content, content);
17151715
1716 try ctx.dir.deleteFile(test_out_file);1716 try ctx.dir.deleteFile(io, test_out_file);
1717 }1717 }
1718 }.impl);1718 }.impl);
1719}1719}
...@@ -2055,7 +2055,7 @@ test "'.' and '..' in Io.Dir functions" {...@@ -2055,7 +2055,7 @@ test "'.' and '..' in Io.Dir functions" {
2055 try ctx.dir.rename(copy_path, ctx.dir, rename_path, io);2055 try ctx.dir.rename(copy_path, ctx.dir, rename_path, io);
2056 const renamed_file = try ctx.dir.openFile(io, rename_path, .{});2056 const renamed_file = try ctx.dir.openFile(io, rename_path, .{});
2057 renamed_file.close(io);2057 renamed_file.close(io);
2058 try ctx.dir.deleteFile(rename_path);2058 try ctx.dir.deleteFile(io, rename_path);
20592059
2060 try ctx.dir.writeFile(io, .{ .sub_path = update_path, .data = "something" });2060 try ctx.dir.writeFile(io, .{ .sub_path = update_path, .data = "something" });
2061 var dir = ctx.dir;2061 var dir = ctx.dir;
...@@ -2113,19 +2113,19 @@ test "chmod" {...@@ -2113,19 +2113,19 @@ test "chmod" {
2113 var tmp = tmpDir(.{});2113 var tmp = tmpDir(.{});
2114 defer tmp.cleanup();2114 defer tmp.cleanup();
21152115
2116 const file = try tmp.dir.createFile(io, "test_file", .{ .mode = 0o600 });2116 const file = try tmp.dir.createFile(io, "test_file", .{ .permissions = .fromMode(0o600) });
2117 defer file.close(io);2117 defer file.close(io);
2118 try testing.expectEqual(@as(File.Mode, 0o600), (try file.stat(io)).mode & 0o7777);2118 try testing.expectEqual(@as(posix.mode_t, 0o600), (try file.stat(io)).permissions.toMode() & 0o7777);
21192119
2120 try file.chmod(0o644);2120 try file.setPermissions(io, .fromMode(0o644));
2121 try testing.expectEqual(@as(File.Mode, 0o644), (try file.stat(io)).mode & 0o7777);2121 try testing.expectEqual(@as(posix.mode_t, 0o644), (try file.stat(io)).permissions.toMode() & 0o7777);
21222122
2123 try tmp.dir.makeDir(io, "test_dir", .default_dir);2123 try tmp.dir.makeDir(io, "test_dir", .default_dir);
2124 var dir = try tmp.dir.openDir(io, "test_dir", .{ .iterate = true });2124 var dir = try tmp.dir.openDir(io, "test_dir", .{ .iterate = true });
2125 defer dir.close(io);2125 defer dir.close(io);
21262126
2127 try dir.chmod(0o700);2127 try dir.setPermissions(io, .fromMode(0o700));
2128 try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat(io)).mode & 0o7777);2128 try testing.expectEqual(@as(posix.mode_t, 0o700), (try dir.stat(io)).permissions.toMode() & 0o7777);
2129}2129}
21302130
2131test "chown" {2131test "chown" {
lib/std/posix/test.zig+1-1
...@@ -144,7 +144,7 @@ test "linkat with different directories" {...@@ -144,7 +144,7 @@ test "linkat with different directories" {
144144
145 const subdir = try tmp.dir.makeOpenPath("subdir", .{});145 const subdir = try tmp.dir.makeOpenPath("subdir", .{});
146146
147 defer tmp.dir.deleteFile(target_name) catch {};147 defer tmp.dir.deleteFile(io, target_name) catch {};
148 try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });148 try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
149149
150 // Test 1: link from file in subdir back up to target in parent directory150 // Test 1: link from file in subdir back up to target in parent directory
lib/std/process/Child.zig+47-47
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const ChildProcess = @This();1const Child = @This();
22
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const native_os = builtin.os.tag;4const native_os = builtin.os.tag;
...@@ -31,7 +31,7 @@ pub const Id = switch (native_os) {...@@ -31,7 +31,7 @@ pub const Id = switch (native_os) {
31id: Id,31id: Id,
32thread_handle: if (native_os == .windows) windows.HANDLE else void,32thread_handle: if (native_os == .windows) windows.HANDLE else void,
3333
34allocator: mem.Allocator,34allocator: Allocator,
3535
36/// The writing end of the child process's standard input pipe.36/// The writing end of the child process's standard input pipe.
37/// Usage requires `stdin_behavior == StdIo.Pipe`.37/// Usage requires `stdin_behavior == StdIo.Pipe`.
...@@ -229,7 +229,7 @@ pub const StdIo = enum {...@@ -229,7 +229,7 @@ pub const StdIo = enum {
229};229};
230230
231/// First argument in argv is the executable.231/// First argument in argv is the executable.
232pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess {232pub fn init(argv: []const []const u8, allocator: Allocator) Child {
233 return .{233 return .{
234 .allocator = allocator,234 .allocator = allocator,
235 .argv = argv,235 .argv = argv,
...@@ -252,7 +252,7 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess {...@@ -252,7 +252,7 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess {
252 };252 };
253}253}
254254
255pub fn setUserName(self: *ChildProcess, name: []const u8) !void {255pub fn setUserName(self: *Child, name: []const u8) !void {
256 const user_info = try process.getUserInfo(name);256 const user_info = try process.getUserInfo(name);
257 self.uid = user_info.uid;257 self.uid = user_info.uid;
258 self.gid = user_info.gid;258 self.gid = user_info.gid;
...@@ -260,7 +260,7 @@ pub fn setUserName(self: *ChildProcess, name: []const u8) !void {...@@ -260,7 +260,7 @@ pub fn setUserName(self: *ChildProcess, name: []const u8) !void {
260260
261/// On success must call `kill` or `wait`.261/// On success must call `kill` or `wait`.
262/// After spawning the `id` is available.262/// After spawning the `id` is available.
263pub fn spawn(self: *ChildProcess) SpawnError!void {263pub fn spawn(self: *Child, io: Io) SpawnError!void {
264 if (!process.can_spawn) {264 if (!process.can_spawn) {
265 @compileError("the target operating system cannot spawn processes");265 @compileError("the target operating system cannot spawn processes");
266 }266 }
...@@ -268,17 +268,17 @@ pub fn spawn(self: *ChildProcess) SpawnError!void {...@@ -268,17 +268,17 @@ pub fn spawn(self: *ChildProcess) SpawnError!void {
268 if (native_os == .windows) {268 if (native_os == .windows) {
269 return self.spawnWindows();269 return self.spawnWindows();
270 } else {270 } else {
271 return self.spawnPosix();271 return self.spawnPosix(io);
272 }272 }
273}273}
274274
275pub fn spawnAndWait(self: *ChildProcess) SpawnError!Term {275pub fn spawnAndWait(child: *Child, io: Io) SpawnError!Term {
276 try self.spawn();276 try child.spawn(io);
277 return self.wait();277 return child.wait(io);
278}278}
279279
280/// Forcibly terminates child process and then cleans up all resources.280/// Forcibly terminates child process and then cleans up all resources.
281pub fn kill(self: *ChildProcess, io: Io) !Term {281pub fn kill(self: *Child, io: Io) !Term {
282 if (native_os == .windows) {282 if (native_os == .windows) {
283 return self.killWindows(io, 1);283 return self.killWindows(io, 1);
284 } else {284 } else {
...@@ -286,7 +286,7 @@ pub fn kill(self: *ChildProcess, io: Io) !Term {...@@ -286,7 +286,7 @@ pub fn kill(self: *ChildProcess, io: Io) !Term {
286 }286 }
287}287}
288288
289pub fn killWindows(self: *ChildProcess, io: Io, exit_code: windows.UINT) !Term {289pub fn killWindows(self: *Child, io: Io, exit_code: windows.UINT) !Term {
290 if (self.term) |term| {290 if (self.term) |term| {
291 self.cleanupStreams(io);291 self.cleanupStreams(io);
292 return term;292 return term;
...@@ -308,7 +308,7 @@ pub fn killWindows(self: *ChildProcess, io: Io, exit_code: windows.UINT) !Term {...@@ -308,7 +308,7 @@ pub fn killWindows(self: *ChildProcess, io: Io, exit_code: windows.UINT) !Term {
308 return self.term.?;308 return self.term.?;
309}309}
310310
311pub fn killPosix(self: *ChildProcess, io: Io) !Term {311pub fn killPosix(self: *Child, io: Io) !Term {
312 if (self.term) |term| {312 if (self.term) |term| {
313 self.cleanupStreams(io);313 self.cleanupStreams(io);
314 return term;314 return term;
...@@ -325,7 +325,7 @@ pub const WaitError = SpawnError || std.os.windows.GetProcessMemoryInfoError;...@@ -325,7 +325,7 @@ pub const WaitError = SpawnError || std.os.windows.GetProcessMemoryInfoError;
325325
326/// On some targets, `spawn` may not report all spawn errors, such as `error.InvalidExe`.326/// On some targets, `spawn` may not report all spawn errors, such as `error.InvalidExe`.
327/// This function will block until any spawn errors can be reported, and return them.327/// This function will block until any spawn errors can be reported, and return them.
328pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {328pub fn waitForSpawn(self: *Child) SpawnError!void {
329 if (native_os == .windows) return; // `spawn` reports everything329 if (native_os == .windows) return; // `spawn` reports everything
330 if (self.term) |term| {330 if (self.term) |term| {
331 _ = term catch |spawn_err| return spawn_err;331 _ = term catch |spawn_err| return spawn_err;
...@@ -355,7 +355,7 @@ pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {...@@ -355,7 +355,7 @@ pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {
355}355}
356356
357/// Blocks until child process terminates and then cleans up all resources.357/// Blocks until child process terminates and then cleans up all resources.
358pub fn wait(self: *ChildProcess, io: Io) WaitError!Term {358pub fn wait(self: *Child, io: Io) WaitError!Term {
359 try self.waitForSpawn(); // report spawn errors359 try self.waitForSpawn(); // report spawn errors
360 if (self.term) |term| {360 if (self.term) |term| {
361 self.cleanupStreams(io);361 self.cleanupStreams(io);
...@@ -381,7 +381,7 @@ pub const RunResult = struct {...@@ -381,7 +381,7 @@ pub const RunResult = struct {
381///381///
382/// The process must be started with stdout_behavior and stderr_behavior == .Pipe382/// The process must be started with stdout_behavior and stderr_behavior == .Pipe
383pub fn collectOutput(383pub fn collectOutput(
384 child: ChildProcess,384 child: Child,
385 /// Used for `stdout` and `stderr`.385 /// Used for `stdout` and `stderr`.
386 allocator: Allocator,386 allocator: Allocator,
387 stdout: *ArrayList(u8),387 stdout: *ArrayList(u8),
...@@ -446,7 +446,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {...@@ -446,7 +446,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {
446 expand_arg0: Arg0Expand = .no_expand,446 expand_arg0: Arg0Expand = .no_expand,
447 progress_node: std.Progress.Node = std.Progress.Node.none,447 progress_node: std.Progress.Node = std.Progress.Node.none,
448}) RunError!RunResult {448}) RunError!RunResult {
449 var child = ChildProcess.init(args.argv, allocator);449 var child = Child.init(args.argv, allocator);
450 child.stdin_behavior = .Ignore;450 child.stdin_behavior = .Ignore;
451 child.stdout_behavior = .Pipe;451 child.stdout_behavior = .Pipe;
452 child.stderr_behavior = .Pipe;452 child.stderr_behavior = .Pipe;
...@@ -461,7 +461,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {...@@ -461,7 +461,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {
461 var stderr: ArrayList(u8) = .empty;461 var stderr: ArrayList(u8) = .empty;
462 defer stderr.deinit(allocator);462 defer stderr.deinit(allocator);
463463
464 try child.spawn();464 try child.spawn(io);
465 errdefer {465 errdefer {
466 _ = child.kill(io) catch {};466 _ = child.kill(io) catch {};
467 }467 }
...@@ -474,7 +474,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {...@@ -474,7 +474,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct {
474 };474 };
475}475}
476476
477fn waitUnwrappedWindows(self: *ChildProcess, io: Io) WaitError!void {477fn waitUnwrappedWindows(self: *Child, io: Io) WaitError!void {
478 const result = windows.WaitForSingleObjectEx(self.id, windows.INFINITE, false);478 const result = windows.WaitForSingleObjectEx(self.id, windows.INFINITE, false);
479479
480 self.term = @as(SpawnError!Term, x: {480 self.term = @as(SpawnError!Term, x: {
...@@ -496,7 +496,7 @@ fn waitUnwrappedWindows(self: *ChildProcess, io: Io) WaitError!void {...@@ -496,7 +496,7 @@ fn waitUnwrappedWindows(self: *ChildProcess, io: Io) WaitError!void {
496 return result;496 return result;
497}497}
498498
499fn waitUnwrappedPosix(self: *ChildProcess, io: Io) void {499fn waitUnwrappedPosix(self: *Child, io: Io) void {
500 const res: posix.WaitPidResult = res: {500 const res: posix.WaitPidResult = res: {
501 if (self.request_resource_usage_statistics) {501 if (self.request_resource_usage_statistics) {
502 switch (native_os) {502 switch (native_os) {
...@@ -531,11 +531,11 @@ fn waitUnwrappedPosix(self: *ChildProcess, io: Io) void {...@@ -531,11 +531,11 @@ fn waitUnwrappedPosix(self: *ChildProcess, io: Io) void {
531 self.handleWaitResult(status);531 self.handleWaitResult(status);
532}532}
533533
534fn handleWaitResult(self: *ChildProcess, status: u32) void {534fn handleWaitResult(self: *Child, status: u32) void {
535 self.term = statusToTerm(status);535 self.term = statusToTerm(status);
536}536}
537537
538fn cleanupStreams(self: *ChildProcess, io: Io) void {538fn cleanupStreams(self: *Child, io: Io) void {
539 if (self.stdin) |*stdin| {539 if (self.stdin) |*stdin| {
540 stdin.close(io);540 stdin.close(io);
541 self.stdin = null;541 self.stdin = null;
...@@ -561,7 +561,7 @@ fn statusToTerm(status: u32) Term {...@@ -561,7 +561,7 @@ fn statusToTerm(status: u32) Term {
561 Term{ .Unknown = status };561 Term{ .Unknown = status };
562}562}
563563
564fn spawnPosix(self: *ChildProcess) SpawnError!void {564fn spawnPosix(self: *Child, io: Io) SpawnError!void {
565 // The child process does need to access (one end of) these pipes. However,565 // The child process does need to access (one end of) these pipes. However,
566 // we must initially set CLOEXEC to avoid a race condition. If another thread566 // we must initially set CLOEXEC to avoid a race condition. If another thread
567 // is racing to spawn a different child process, we don't want it to inherit567 // is racing to spawn a different child process, we don't want it to inherit
...@@ -659,7 +659,7 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {...@@ -659,7 +659,7 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
659 })).ptr;659 })).ptr;
660 } else {660 } else {
661 // TODO come up with a solution for this.661 // TODO come up with a solution for this.
662 @panic("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process");662 @panic("missing std lib enhancement: std.process.Child implementation has no way to collect the environment variables to forward to the child process");
663 }663 }
664 };664 };
665665
...@@ -671,41 +671,41 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {...@@ -671,41 +671,41 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
671 const pid_result = try posix.fork();671 const pid_result = try posix.fork();
672 if (pid_result == 0) {672 if (pid_result == 0) {
673 // we are the child673 // we are the child
674 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);674 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(io, err_pipe[1], err);
675 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);675 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(io, err_pipe[1], err);
676 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);676 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(io, err_pipe[1], err);
677677
678 if (self.cwd_dir) |cwd| {678 if (self.cwd_dir) |cwd| {
679 posix.fchdir(cwd.handle) catch |err| forkChildErrReport(err_pipe[1], err);679 posix.fchdir(cwd.handle) catch |err| forkChildErrReport(io, err_pipe[1], err);
680 } else if (self.cwd) |cwd| {680 } else if (self.cwd) |cwd| {
681 posix.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);681 posix.chdir(cwd) catch |err| forkChildErrReport(io, err_pipe[1], err);
682 }682 }
683683
684 // Must happen after fchdir above, the cwd file descriptor might be684 // Must happen after fchdir above, the cwd file descriptor might be
685 // equal to prog_fileno and be clobbered by this dup2 call.685 // equal to prog_fileno and be clobbered by this dup2 call.
686 if (prog_pipe[1] != -1) posix.dup2(prog_pipe[1], prog_fileno) catch |err| forkChildErrReport(err_pipe[1], err);686 if (prog_pipe[1] != -1) posix.dup2(prog_pipe[1], prog_fileno) catch |err| forkChildErrReport(io, err_pipe[1], err);
687687
688 if (self.gid) |gid| {688 if (self.gid) |gid| {
689 posix.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);689 posix.setregid(gid, gid) catch |err| forkChildErrReport(io, err_pipe[1], err);
690 }690 }
691691
692 if (self.uid) |uid| {692 if (self.uid) |uid| {
693 posix.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);693 posix.setreuid(uid, uid) catch |err| forkChildErrReport(io, err_pipe[1], err);
694 }694 }
695695
696 if (self.pgid) |pid| {696 if (self.pgid) |pid| {
697 posix.setpgid(0, pid) catch |err| forkChildErrReport(err_pipe[1], err);697 posix.setpgid(0, pid) catch |err| forkChildErrReport(io, err_pipe[1], err);
698 }698 }
699699
700 if (self.start_suspended) {700 if (self.start_suspended) {
701 posix.kill(posix.getpid(), .STOP) catch |err| forkChildErrReport(err_pipe[1], err);701 posix.kill(posix.getpid(), .STOP) catch |err| forkChildErrReport(io, err_pipe[1], err);
702 }702 }
703703
704 const err = switch (self.expand_arg0) {704 const err = switch (self.expand_arg0) {
705 .expand => posix.execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),705 .expand => posix.execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
706 .no_expand => posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),706 .no_expand => posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
707 };707 };
708 forkChildErrReport(err_pipe[1], err);708 forkChildErrReport(io, err_pipe[1], err);
709 }709 }
710710
711 // we are the parent711 // we are the parent
...@@ -750,7 +750,7 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {...@@ -750,7 +750,7 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
750 self.progress_node.setIpcFd(prog_pipe[0]);750 self.progress_node.setIpcFd(prog_pipe[0]);
751}751}
752752
753fn spawnWindows(self: *ChildProcess) SpawnError!void {753fn spawnWindows(self: *Child) SpawnError!void {
754 var saAttr = windows.SECURITY_ATTRIBUTES{754 var saAttr = windows.SECURITY_ATTRIBUTES{
755 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),755 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
756 .bInheritHandle = windows.TRUE,756 .bInheritHandle = windows.TRUE,
...@@ -880,7 +880,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {...@@ -880,7 +880,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
880 const app_name_wtf8 = self.argv[0];880 const app_name_wtf8 = self.argv[0];
881 const app_name_is_absolute = fs.path.isAbsolute(app_name_wtf8);881 const app_name_is_absolute = fs.path.isAbsolute(app_name_wtf8);
882882
883 // the cwd set in ChildProcess is in effect when choosing the executable path883 // the cwd set in Child is in effect when choosing the executable path
884 // to match posix semantics884 // to match posix semantics
885 var cwd_path_w_needs_free = false;885 var cwd_path_w_needs_free = false;
886 const cwd_path_w = x: {886 const cwd_path_w = x: {
...@@ -965,7 +965,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {...@@ -965,7 +965,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
965 // If the app name had path separators, that disallows PATH searching,965 // If the app name had path separators, that disallows PATH searching,
966 // and there's no need to search the PATH if the app name is absolute.966 // and there's no need to search the PATH if the app name is absolute.
967 // We still search the path if the cwd is absolute because of the967 // We still search the path if the cwd is absolute because of the
968 // "cwd set in ChildProcess is in effect when choosing the executable path968 // "cwd set in Child is in effect when choosing the executable path
969 // to match posix semantics" behavior--we don't want to skip searching969 // to match posix semantics" behavior--we don't want to skip searching
970 // the PATH just because we were trying to set the cwd of the child process.970 // the PATH just because we were trying to set the cwd of the child process.
971 if (app_dirname_w != null or app_name_is_absolute) {971 if (app_dirname_w != null or app_name_is_absolute) {
...@@ -1039,8 +1039,8 @@ fn destroyPipe(pipe: [2]posix.fd_t) void {...@@ -1039,8 +1039,8 @@ fn destroyPipe(pipe: [2]posix.fd_t) void {
10391039
1040// Child of fork calls this to report an error to the fork parent.1040// Child of fork calls this to report an error to the fork parent.
1041// Then the child exits.1041// Then the child exits.
1042fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {1042fn forkChildErrReport(io: Io, fd: i32, err: Child.SpawnError) noreturn {
1043 writeIntFd(fd, @as(ErrInt, @intFromError(err))) catch {};1043 writeIntFd(io, fd, @as(ErrInt, @intFromError(err))) catch {};
1044 // If we're linking libc, some naughty applications may have registered atexit handlers1044 // If we're linking libc, some naughty applications may have registered atexit handlers
1045 // which we really do not want to run in the fork child. I caught LLVM doing this and1045 // which we really do not want to run in the fork child. I caught LLVM doing this and
1046 // it caused a deadlock instead of doing an exit syscall. In the words of Avril Lavigne,1046 // it caused a deadlock instead of doing an exit syscall. In the words of Avril Lavigne,
...@@ -1052,9 +1052,9 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {...@@ -1052,9 +1052,9 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
1052 posix.system.exit(1);1052 posix.system.exit(1);
1053}1053}
10541054
1055fn writeIntFd(fd: i32, value: ErrInt) !void {1055fn writeIntFd(io: Io, fd: i32, value: ErrInt) !void {
1056 var buffer: [8]u8 = undefined;1056 var buffer: [8]u8 = undefined;
1057 var fw: File.Writer = .initStreaming(.{ .handle = fd }, &buffer);1057 var fw: File.Writer = .initStreaming(.{ .handle = fd }, io, &buffer);
1058 fw.interface.writeInt(u64, value, .little) catch unreachable;1058 fw.interface.writeInt(u64, value, .little) catch unreachable;
1059 fw.interface.flush() catch return error.SystemResources;1059 fw.interface.flush() catch return error.SystemResources;
1060}1060}
...@@ -1078,7 +1078,7 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);...@@ -1078,7 +1078,7 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
1078/// Note: `app_buf` should not contain any leading path separators.1078/// Note: `app_buf` should not contain any leading path separators.
1079/// Note: If the dir is the cwd, dir_buf should be empty (len = 0).1079/// Note: If the dir is the cwd, dir_buf should be empty (len = 0).
1080fn windowsCreateProcessPathExt(1080fn windowsCreateProcessPathExt(
1081 allocator: mem.Allocator,1081 allocator: Allocator,
1082 dir_buf: *ArrayList(u16),1082 dir_buf: *ArrayList(u16),
1083 app_buf: *ArrayList(u16),1083 app_buf: *ArrayList(u16),
1084 pathext: [:0]const u16,1084 pathext: [:0]const u16,
...@@ -1525,9 +1525,9 @@ const WindowsCommandLineCache = struct {...@@ -1525,9 +1525,9 @@ const WindowsCommandLineCache = struct {
1525 script_cmd_line: ?[:0]u16 = null,1525 script_cmd_line: ?[:0]u16 = null,
1526 cmd_exe_path: ?[:0]u16 = null,1526 cmd_exe_path: ?[:0]u16 = null,
1527 argv: []const []const u8,1527 argv: []const []const u8,
1528 allocator: mem.Allocator,1528 allocator: Allocator,
15291529
1530 fn init(allocator: mem.Allocator, argv: []const []const u8) WindowsCommandLineCache {1530 fn init(allocator: Allocator, argv: []const []const u8) WindowsCommandLineCache {
1531 return .{1531 return .{
1532 .allocator = allocator,1532 .allocator = allocator,
1533 .argv = argv,1533 .argv = argv,
...@@ -1571,7 +1571,7 @@ const WindowsCommandLineCache = struct {...@@ -1571,7 +1571,7 @@ const WindowsCommandLineCache = struct {
15711571
1572/// Returns the absolute path of `cmd.exe` within the Windows system directory.1572/// Returns the absolute path of `cmd.exe` within the Windows system directory.
1573/// The caller owns the returned slice.1573/// The caller owns the returned slice.
1574fn windowsCmdExePath(allocator: mem.Allocator) error{ OutOfMemory, Unexpected }![:0]u16 {1574fn windowsCmdExePath(allocator: Allocator) error{ OutOfMemory, Unexpected }![:0]u16 {
1575 var buf = try ArrayList(u16).initCapacity(allocator, 128);1575 var buf = try ArrayList(u16).initCapacity(allocator, 128);
1576 errdefer buf.deinit(allocator);1576 errdefer buf.deinit(allocator);
1577 while (true) {1577 while (true) {
...@@ -1608,7 +1608,7 @@ const ArgvToCommandLineError = error{ OutOfMemory, InvalidWtf8, InvalidArg0 };...@@ -1608,7 +1608,7 @@ const ArgvToCommandLineError = error{ OutOfMemory, InvalidWtf8, InvalidArg0 };
1608///1608///
1609/// When executing `.bat`/`.cmd` scripts, use `argvToScriptCommandLineWindows` instead.1609/// When executing `.bat`/`.cmd` scripts, use `argvToScriptCommandLineWindows` instead.
1610fn argvToCommandLineWindows(1610fn argvToCommandLineWindows(
1611 allocator: mem.Allocator,1611 allocator: Allocator,
1612 argv: []const []const u8,1612 argv: []const []const u8,
1613) ArgvToCommandLineError![:0]u16 {1613) ArgvToCommandLineError![:0]u16 {
1614 var buf = std.array_list.Managed(u8).init(allocator);1614 var buf = std.array_list.Managed(u8).init(allocator);
...@@ -1784,7 +1784,7 @@ const ArgvToScriptCommandLineError = error{...@@ -1784,7 +1784,7 @@ const ArgvToScriptCommandLineError = error{
1784/// Should only be used when spawning `.bat`/`.cmd` scripts, see `argvToCommandLineWindows` otherwise.1784/// Should only be used when spawning `.bat`/`.cmd` scripts, see `argvToCommandLineWindows` otherwise.
1785/// The `.bat`/`.cmd` file must be known to both have the `.bat`/`.cmd` extension and exist on the filesystem.1785/// The `.bat`/`.cmd` file must be known to both have the `.bat`/`.cmd` extension and exist on the filesystem.
1786fn argvToScriptCommandLineWindows(1786fn argvToScriptCommandLineWindows(
1787 allocator: mem.Allocator,1787 allocator: Allocator,
1788 /// Path to the `.bat`/`.cmd` script. If this path is relative, it is assumed to be relative to the CWD.1788 /// Path to the `.bat`/`.cmd` script. If this path is relative, it is assumed to be relative to the CWD.
1789 /// The script must have been verified to exist at this path before calling this function.1789 /// The script must have been verified to exist at this path before calling this function.
1790 script_path: []const u16,1790 script_path: []const u16,
lib/std/tar.zig+18-18
...@@ -610,7 +610,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp...@@ -610,7 +610,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp
610 }610 }
611 },611 },
612 .file => {612 .file => {
613 if (createDirAndFile(io, dir, file_name, fileMode(file.mode, options))) |fs_file| {613 if (createDirAndFile(io, dir, file_name, filePermissions(file.mode, options))) |fs_file| {
614 defer fs_file.close(io);614 defer fs_file.close(io);
615 var file_writer = fs_file.writer(io, &file_contents_buffer);615 var file_writer = fs_file.writer(io, &file_contents_buffer);
616 try it.streamRemaining(file, &file_writer.interface);616 try it.streamRemaining(file, &file_writer.interface);
...@@ -638,12 +638,12 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp...@@ -638,12 +638,12 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp
638 }638 }
639}639}
640640
641fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, mode: Io.File.Mode) !Io.File {641fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, permissions: Io.File.Permissions) !Io.File {
642 const fs_file = dir.createFile(io, file_name, .{ .exclusive = true, .mode = mode }) catch |err| {642 const fs_file = dir.createFile(io, file_name, .{ .exclusive = true, .permissions = permissions }) catch |err| {
643 if (err == error.FileNotFound) {643 if (err == error.FileNotFound) {
644 if (std.fs.path.dirname(file_name)) |dir_name| {644 if (std.fs.path.dirname(file_name)) |dir_name| {
645 try dir.makePath(io, dir_name);645 try dir.makePath(io, dir_name);
646 return try dir.createFile(io, file_name, .{ .exclusive = true, .mode = mode });646 return try dir.createFile(io, file_name, .{ .exclusive = true, .permissions = permissions });
647 }647 }
648 }648 }
649 return err;649 return err;
...@@ -880,9 +880,9 @@ test "create file and symlink" {...@@ -880,9 +880,9 @@ test "create file and symlink" {
880 var root = testing.tmpDir(.{});880 var root = testing.tmpDir(.{});
881 defer root.cleanup();881 defer root.cleanup();
882882
883 var file = try createDirAndFile(io, root.dir, "file1", default_mode);883 var file = try createDirAndFile(io, root.dir, "file1", .default_file);
884 file.close(io);884 file.close(io);
885 file = try createDirAndFile(io, root.dir, "a/b/c/file2", default_mode);885 file = try createDirAndFile(io, root.dir, "a/b/c/file2", .default_file);
886 file.close(io);886 file.close(io);
887887
888 createDirAndSymlink(io, root.dir, "a/b/c/file2", "symlink1") catch |err| {888 createDirAndSymlink(io, root.dir, "a/b/c/file2", "symlink1") catch |err| {
...@@ -894,7 +894,7 @@ test "create file and symlink" {...@@ -894,7 +894,7 @@ test "create file and symlink" {
894894
895 // Danglink symlnik, file created later895 // Danglink symlnik, file created later
896 try createDirAndSymlink(io, root.dir, "../../../g/h/i/file4", "j/k/l/symlink3");896 try createDirAndSymlink(io, root.dir, "../../../g/h/i/file4", "j/k/l/symlink3");
897 file = try createDirAndFile(io, root.dir, "g/h/i/file4", default_mode);897 file = try createDirAndFile(io, root.dir, "g/h/i/file4", .default_file);
898 file.close(io);898 file.close(io);
899}899}
900900
...@@ -1118,30 +1118,30 @@ fn normalizePath(bytes: []u8) []u8 {...@@ -1118,30 +1118,30 @@ fn normalizePath(bytes: []u8) []u8 {
1118 return bytes;1118 return bytes;
1119}1119}
11201120
1121const default_mode = Io.File.default_mode;
1122
1123// File system mode based on tar header mode and mode_mode options.1121// File system mode based on tar header mode and mode_mode options.
1124fn fileMode(mode: u32, options: PipeOptions) Io.File.Mode {1122fn filePermissions(mode: u32, options: PipeOptions) Io.File.Permissions {
1123 const default_mode = 0o666;
1124
1125 if (!std.fs.has_executable_bit or options.mode_mode == .ignore)1125 if (!std.fs.has_executable_bit or options.mode_mode == .ignore)
1126 return default_mode;1126 return .fromMode(default_mode);
11271127
1128 const S = std.posix.S;1128 const S = std.posix.S;
11291129
1130 // The mode from the tar file is inspected for the owner executable bit.1130 // The mode from the tar file is inspected for the owner executable bit.
1131 if (mode & S.IXUSR == 0)1131 if (mode & S.IXUSR == 0)
1132 return default_mode;1132 return .fromMode(default_mode);
11331133
1134 // This bit is copied to the group and other executable bits.1134 // This bit is copied to the group and other executable bits.
1135 // Other bits of the mode are left as the default when creating files.1135 // Other bits of the mode are left as the default when creating files.
1136 return default_mode | S.IXUSR | S.IXGRP | S.IXOTH;1136 return .fromMode(default_mode | S.IXUSR | S.IXGRP | S.IXOTH);
1137}1137}
11381138
1139test fileMode {1139test filePermissions {
1140 if (!std.fs.has_executable_bit) return error.SkipZigTest;1140 if (!std.fs.has_executable_bit) return error.SkipZigTest;
1141 try testing.expectEqual(default_mode, fileMode(0o744, PipeOptions{ .mode_mode = .ignore }));1141 try testing.expectEqual(0o666, filePermissions(0o744, PipeOptions{ .mode_mode = .ignore }));
1142 try testing.expectEqual(0o777, fileMode(0o744, PipeOptions{}));1142 try testing.expectEqual(0o777, filePermissions(0o744, PipeOptions{}));
1143 try testing.expectEqual(0o666, fileMode(0o644, PipeOptions{}));1143 try testing.expectEqual(0o666, filePermissions(0o644, PipeOptions{}));
1144 try testing.expectEqual(0o666, fileMode(0o655, PipeOptions{}));1144 try testing.expectEqual(0o666, filePermissions(0o655, PipeOptions{}));
1145}1145}
11461146
1147test "executable bit" {1147test "executable bit" {
src/Compilation.zig+8-7
...@@ -5782,7 +5782,7 @@ pub fn translateC(...@@ -5782,7 +5782,7 @@ pub fn translateC(
5782 }5782 }
57835783
5784 // Just to save disk space, we delete the file because it is never needed again.5784 // Just to save disk space, we delete the file because it is never needed again.
5785 cache_tmp_dir.deleteFile(dep_basename) catch |err| {5785 cache_tmp_dir.deleteFile(io, dep_basename) catch |err| {
5786 log.warn("failed to delete '{s}': {t}", .{ dep_file_path, err });5786 log.warn("failed to delete '{s}': {t}", .{ dep_file_path, err });
5787 };5787 };
5788 }5788 }
...@@ -6314,11 +6314,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -6314,11 +6314,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
6314 }6314 }
63156315
6316 // Just to save disk space, we delete the files that are never needed again.6316 // Just to save disk space, we delete the files that are never needed again.
6317 defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(fs.path.basename(diag_file_path)) catch |err| switch (err) {6317 defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(diag_file_path)) catch |err| switch (err) {
6318 error.FileNotFound => {}, // the file wasn't created due to an error we reported6318 error.FileNotFound => {}, // the file wasn't created due to an error we reported
6319 else => log.warn("failed to delete '{s}': {s}", .{ diag_file_path, @errorName(err) }),6319 else => log.warn("failed to delete '{s}': {s}", .{ diag_file_path, @errorName(err) }),
6320 };6320 };
6321 defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(fs.path.basename(dep_file_path)) catch |err| switch (err) {6321 defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(dep_file_path)) catch |err| switch (err) {
6322 error.FileNotFound => {}, // the file wasn't created due to an error we reported6322 error.FileNotFound => {}, // the file wasn't created due to an error we reported
6323 else => log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) }),6323 else => log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) }),
6324 };6324 };
...@@ -6329,7 +6329,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -6329,7 +6329,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
6329 child.stdout_behavior = .Inherit;6329 child.stdout_behavior = .Inherit;
6330 child.stderr_behavior = .Inherit;6330 child.stderr_behavior = .Inherit;
63316331
6332 const term = child.spawnAndWait() catch |err| {6332 const term = child.spawnAndWait(io) catch |err| {
6333 return comp.failCObj(c_object, "failed to spawn zig clang (passthrough mode) {s}: {s}", .{ argv.items[0], @errorName(err) });6333 return comp.failCObj(c_object, "failed to spawn zig clang (passthrough mode) {s}: {s}", .{ argv.items[0], @errorName(err) });
6334 };6334 };
6335 switch (term) {6335 switch (term) {
...@@ -6347,7 +6347,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -6347,7 +6347,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
6347 child.stdout_behavior = .Ignore;6347 child.stdout_behavior = .Ignore;
6348 child.stderr_behavior = .Pipe;6348 child.stderr_behavior = .Pipe;
63496349
6350 try child.spawn();6350 try child.spawn(io);
63516351
6352 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});6352 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});
6353 const stderr = try stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32)));6353 const stderr = try stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32)));
...@@ -6723,6 +6723,7 @@ fn spawnZigRc(...@@ -6723,6 +6723,7 @@ fn spawnZigRc(
6723 argv: []const []const u8,6723 argv: []const []const u8,
6724 child_progress_node: std.Progress.Node,6724 child_progress_node: std.Progress.Node,
6725) !void {6725) !void {
6726 const io = comp.io;
6726 var node_name: std.ArrayList(u8) = .empty;6727 var node_name: std.ArrayList(u8) = .empty;
6727 defer node_name.deinit(arena);6728 defer node_name.deinit(arena);
67286729
...@@ -6732,8 +6733,8 @@ fn spawnZigRc(...@@ -6732,8 +6733,8 @@ fn spawnZigRc(
6732 child.stderr_behavior = .Pipe;6733 child.stderr_behavior = .Pipe;
6733 child.progress_node = child_progress_node;6734 child.progress_node = child_progress_node;
67346735
6735 child.spawn() catch |err| {6736 child.spawn(io) catch |err| {
6736 return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });6737 return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {t}", .{ argv[0], err });
6737 };6738 };
67386739
6739 var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{6740 var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{
src/Package/Fetch.zig+6-6
...@@ -1347,7 +1347,7 @@ fn unzip(...@@ -1347,7 +1347,7 @@ fn unzip(
1347 .diagnostics = &diagnostics,1347 .diagnostics = &diagnostics,
1348 }) catch |err| return f.fail(f.location_tok, try eb.printString("zip extract failed: {t}", .{err}));1348 }) catch |err| return f.fail(f.location_tok, try eb.printString("zip extract failed: {t}", .{err}));
13491349
1350 cache_root.handle.deleteFile(&zip_path) catch |err|1350 cache_root.handle.deleteFile(io, &zip_path) catch |err|
1351 return f.fail(f.location_tok, try eb.printString("delete temporary zip failed: {t}", .{err}));1351 return f.fail(f.location_tok, try eb.printString("delete temporary zip failed: {t}", .{err}));
13521352
1353 return .{ .root_dir = diagnostics.root_dir };1353 return .{ .root_dir = diagnostics.root_dir };
...@@ -1547,7 +1547,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute...@@ -1547,7 +1547,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute
1547 .fs_path = fs_path,1547 .fs_path = fs_path,
1548 .failure = undefined, // to be populated by the worker1548 .failure = undefined, // to be populated by the worker
1549 };1549 };
1550 group.async(io, workerDeleteFile, .{ root_dir, deleted_file });1550 group.async(io, workerDeleteFile, .{ io, root_dir, deleted_file });
1551 try deleted_files.append(deleted_file);1551 try deleted_files.append(deleted_file);
1552 continue;1552 continue;
1553 }1553 }
...@@ -1669,8 +1669,8 @@ fn workerHashFile(dir: Io.Dir, hashed_file: *HashedFile) void {...@@ -1669,8 +1669,8 @@ fn workerHashFile(dir: Io.Dir, hashed_file: *HashedFile) void {
1669 hashed_file.failure = hashFileFallible(dir, hashed_file);1669 hashed_file.failure = hashFileFallible(dir, hashed_file);
1670}1670}
16711671
1672fn workerDeleteFile(dir: Io.Dir, deleted_file: *DeletedFile) void {1672fn workerDeleteFile(io: Io, dir: Io.Dir, deleted_file: *DeletedFile) void {
1673 deleted_file.failure = deleteFileFallible(dir, deleted_file);1673 deleted_file.failure = deleteFileFallible(io, dir, deleted_file);
1674}1674}
16751675
1676fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Error!void {1676fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
...@@ -1712,8 +1712,8 @@ fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Er...@@ -1712,8 +1712,8 @@ fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Er
1712 hashed_file.size = file_size;1712 hashed_file.size = file_size;
1713}1713}
17141714
1715fn deleteFileFallible(dir: Io.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {1715fn deleteFileFallible(io: Io, dir: Io.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {
1716 try dir.deleteFile(deleted_file.fs_path);1716 try dir.deleteFile(io, deleted_file.fs_path);
1717}1717}
17181718
1719fn setExecutable(file: Io.File) !void {1719fn setExecutable(file: Io.File) !void {
src/link.zig+9-5
...@@ -1235,22 +1235,26 @@ pub const File = struct {...@@ -1235,22 +1235,26 @@ pub const File = struct {
1235 ty: InternPool.Index,1235 ty: InternPool.Index,
1236 };1236 };
12371237
1238 pub fn determineMode(1238 pub fn determinePermissions(
1239 output_mode: std.builtin.OutputMode,1239 output_mode: std.builtin.OutputMode,
1240 link_mode: std.builtin.LinkMode,1240 link_mode: std.builtin.LinkMode,
1241 ) Io.File.Mode {1241 ) Io.File.Permissions {
1242 // On common systems with a 0o022 umask, 0o777 will still result in a file created1242 // On common systems with a 0o022 umask, 0o777 will still result in a file created
1243 // with 0o755 permissions, but it works appropriately if the system is configured1243 // with 0o755 permissions, but it works appropriately if the system is configured
1244 // more leniently. As another data point, C's fopen seems to open files with the1244 // more leniently. As another data point, C's fopen seems to open files with the
1245 // 666 mode.1245 // 666 mode.
1246 const executable_mode = if (builtin.target.os.tag == .windows) 0 else 0o777;1246 const executable_mode: Io.FilePermissions = if (builtin.target.os.tag == .windows)
1247 .default_file
1248 else
1249 .fromMode(0o777);
1250
1247 switch (output_mode) {1251 switch (output_mode) {
1248 .Lib => return switch (link_mode) {1252 .Lib => return switch (link_mode) {
1249 .dynamic => executable_mode,1253 .dynamic => executable_mode,
1250 .static => Io.File.default_mode,1254 .static => .default_file,
1251 },1255 },
1252 .Exe => return executable_mode,1256 .Exe => return executable_mode,
1253 .Obj => return Io.File.default_mode,1257 .Obj => return .default_file,
1254 }1258 }
1255 }1259 }
12561260
src/link/Lld.zig+4-4
...@@ -1608,13 +1608,13 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi...@@ -1608,13 +1608,13 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
1608 child.stdout_behavior = .Inherit;1608 child.stdout_behavior = .Inherit;
1609 child.stderr_behavior = .Inherit;1609 child.stderr_behavior = .Inherit;
16101610
1611 break :term child.spawnAndWait();1611 break :term child.spawnAndWait(io);
1612 } else term: {1612 } else term: {
1613 child.stdin_behavior = .Ignore;1613 child.stdin_behavior = .Ignore;
1614 child.stdout_behavior = .Ignore;1614 child.stdout_behavior = .Ignore;
1615 child.stderr_behavior = .Pipe;1615 child.stderr_behavior = .Pipe;
16161616
1617 child.spawn() catch |err| break :term err;1617 child.spawn(io) catch |err| break :term err;
1618 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});1618 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});
1619 stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited);1619 stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited);
1620 break :term child.wait();1620 break :term child.wait();
...@@ -1658,13 +1658,13 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi...@@ -1658,13 +1658,13 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
1658 rsp_child.stdout_behavior = .Inherit;1658 rsp_child.stdout_behavior = .Inherit;
1659 rsp_child.stderr_behavior = .Inherit;1659 rsp_child.stderr_behavior = .Inherit;
16601660
1661 break :term rsp_child.spawnAndWait() catch |err| break :err err;1661 break :term rsp_child.spawnAndWait(io) catch |err| break :err err;
1662 } else {1662 } else {
1663 rsp_child.stdin_behavior = .Ignore;1663 rsp_child.stdin_behavior = .Ignore;
1664 rsp_child.stdout_behavior = .Ignore;1664 rsp_child.stdout_behavior = .Ignore;
1665 rsp_child.stderr_behavior = .Pipe;1665 rsp_child.stderr_behavior = .Pipe;
16661666
1667 rsp_child.spawn() catch |err| break :err err;1667 rsp_child.spawn(io) catch |err| break :err err;
1668 var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});1668 var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});
1669 stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited);1669 stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited);
1670 break :term rsp_child.wait() catch |err| break :err err;1670 break :term rsp_child.wait() catch |err| break :err err;
src/main.zig+7-6
...@@ -4457,7 +4457,7 @@ fn runOrTest(...@@ -4457,7 +4457,7 @@ fn runOrTest(
4457 const term_result = t: {4457 const term_result = t: {
4458 std.debug.lockStdErr();4458 std.debug.lockStdErr();
4459 defer std.debug.unlockStdErr();4459 defer std.debug.unlockStdErr();
4460 break :t child.spawnAndWait();4460 break :t child.spawnAndWait(io);
4461 };4461 };
4462 const term = term_result catch |err| {4462 const term = term_result catch |err| {
4463 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);4463 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
...@@ -4512,6 +4512,7 @@ fn runOrTestHotSwap(...@@ -4512,6 +4512,7 @@ fn runOrTestHotSwap(
4512 all_args: []const []const u8,4512 all_args: []const []const u8,
4513 runtime_args_start: ?usize,4513 runtime_args_start: ?usize,
4514) !std.process.Child.Id {4514) !std.process.Child.Id {
4515 const io = comp.io;
4515 const lf = comp.bin_file.?;4516 const lf = comp.bin_file.?;
45164517
4517 const exe_path = switch (builtin.target.os.tag) {4518 const exe_path = switch (builtin.target.os.tag) {
...@@ -4593,7 +4594,7 @@ fn runOrTestHotSwap(...@@ -4593,7 +4594,7 @@ fn runOrTestHotSwap(
4593 child.stdout_behavior = .Inherit;4594 child.stdout_behavior = .Inherit;
4594 child.stderr_behavior = .Inherit;4595 child.stderr_behavior = .Inherit;
45954596
4596 try child.spawn();4597 try child.spawn(io);
45974598
4598 return child.id;4599 return child.id;
4599 },4600 },
...@@ -5419,8 +5420,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)...@@ -5419,8 +5420,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
5419 const term = t: {5420 const term = t: {
5420 std.debug.lockStdErr();5421 std.debug.lockStdErr();
5421 defer std.debug.unlockStdErr();5422 defer std.debug.unlockStdErr();
5422 break :t child.spawnAndWait() catch |err| {5423 break :t child.spawnAndWait(io) catch |err| {
5423 fatal("failed to spawn build runner {s}: {s}", .{ child_argv.items[0], @errorName(err) });5424 fatal("failed to spawn build runner {s}: {t}", .{ child_argv.items[0], err });
5424 };5425 };
5425 };5426 };
54265427
...@@ -5444,7 +5445,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)...@@ -5444,7 +5445,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
5444 dirs.local_cache, tmp_sub_path, @errorName(err),5445 dirs.local_cache, tmp_sub_path, @errorName(err),
5445 });5446 });
5446 };5447 };
5447 dirs.local_cache.handle.deleteFile(tmp_sub_path) catch {};5448 dirs.local_cache.handle.deleteFile(io, tmp_sub_path) catch {};
54485449
5449 var it = mem.splitScalar(u8, stdout, '\n');5450 var it = mem.splitScalar(u8, stdout, '\n');
5450 var any_errors = false;5451 var any_errors = false;
...@@ -5685,7 +5686,7 @@ fn jitCmd(...@@ -5685,7 +5686,7 @@ fn jitCmd(
5685 child.stdout_behavior = if (options.capture == null) .Inherit else .Pipe;5686 child.stdout_behavior = if (options.capture == null) .Inherit else .Pipe;
5686 child.stderr_behavior = .Inherit;5687 child.stderr_behavior = .Inherit;
56875688
5688 try child.spawn();5689 try child.spawn(io);
56895690
5690 if (options.capture) |ptr| {5691 if (options.capture) |ptr| {
5691 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});5692 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
test/src/Cases.zig+2-1
...@@ -461,6 +461,7 @@ pub fn lowerToBuildSteps(...@@ -461,6 +461,7 @@ pub fn lowerToBuildSteps(
461 parent_step: *std.Build.Step,461 parent_step: *std.Build.Step,
462 options: CaseTestOptions,462 options: CaseTestOptions,
463) void {463) void {
464 const io = self.io;
464 const host = b.resolveTargetQuery(.{});465 const host = b.resolveTargetQuery(.{});
465 const cases_dir_path = b.build_root.join(b.allocator, &.{ "test", "cases" }) catch @panic("OOM");466 const cases_dir_path = b.build_root.join(b.allocator, &.{ "test", "cases" }) catch @panic("OOM");
466467
...@@ -595,7 +596,7 @@ pub fn lowerToBuildSteps(...@@ -595,7 +596,7 @@ pub fn lowerToBuildSteps(
595 },596 },
596 .Execution => |expected_stdout| no_exec: {597 .Execution => |expected_stdout| no_exec: {
597 const run = if (case.target.result.ofmt == .c) run_step: {598 const run = if (case.target.result.ofmt == .c) run_step: {
598 if (getExternalExecutor(&host.result, &case.target.result, .{ .link_libc = true }) != .native) {599 if (getExternalExecutor(io, &host.result, &case.target.result, .{ .link_libc = true }) != .native) {
599 // We wouldn't be able to run the compiled C code.600 // We wouldn't be able to run the compiled C code.
600 break :no_exec;601 break :no_exec;
601 }602 }
test/standalone/child_process/main.zig+1-1
...@@ -29,7 +29,7 @@ pub fn main() !void {...@@ -29,7 +29,7 @@ pub fn main() !void {
29 child.stdin_behavior = .Pipe;29 child.stdin_behavior = .Pipe;
30 child.stdout_behavior = .Pipe;30 child.stdout_behavior = .Pipe;
31 child.stderr_behavior = .Inherit;31 child.stderr_behavior = .Inherit;
32 try child.spawn();32 try child.spawn(io);
33 const child_stdin = child.stdin.?;33 const child_stdin = child.stdin.?;
34 try child_stdin.writeAll("hello from stdin"); // verified in child34 try child_stdin.writeAll("hello from stdin"); // verified in child
35 child_stdin.close(io);35 child_stdin.close(io);