authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-08 16:13:51-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:08-08:00
log9ccd68de0b79c3723bd11071fd836bc24ff25b33
tree3441f2a7030f40a6b625f4ff9fc7d719a60a32d3
parent7f5bb118d4d90e2b883ee66e17592ac8d7808ac8

std: move abort and exit from posix into process

and delete the unit tests that called fork() no forking allowed in the std lib, including unit tests, except to implement child process spawning.

21 files changed, 167 insertions(+), 248 deletions(-)

lib/compiler/translate-c/main.zig+1-1
...@@ -253,7 +253,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration...@@ -253,7 +253,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration
253 if (d.output_name) |path| blk: {253 if (d.output_name) |path| blk: {
254 if (std.mem.eql(u8, path, "-")) break :blk;254 if (std.mem.eql(u8, path, "-")) break :blk;
255 if (std.fs.path.dirname(path)) |dirname| {255 if (std.fs.path.dirname(path)) |dirname| {
256 Io.Dir.cwd().makePath(dirname) catch |err|256 Io.Dir.cwd().makePath(io, dirname) catch |err|
257 return d.fatal("failed to create path to '{s}': {s}", .{ path, aro.Driver.errorDescription(err) });257 return d.fatal("failed to create path to '{s}': {s}", .{ path, aro.Driver.errorDescription(err) });
258 }258 }
259 out_file = Io.Dir.cwd().createFile(io, path, .{}) catch |err| {259 out_file = Io.Dir.cwd().createFile(io, path, .{}) catch |err| {
lib/std/Build.zig+4-5
...@@ -1706,7 +1706,7 @@ pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.MakeError || Io.Di...@@ -1706,7 +1706,7 @@ pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.MakeError || Io.Di
1706 var src_file = cwd.createFile(io, dest_path, .{}) catch |err| switch (err) {1706 var src_file = cwd.createFile(io, dest_path, .{}) catch |err| switch (err) {
1707 error.FileNotFound => blk: {1707 error.FileNotFound => blk: {
1708 if (fs.path.dirname(dest_path)) |dirname| {1708 if (fs.path.dirname(dest_path)) |dirname| {
1709 try cwd.makePath(dirname);1709 try cwd.makePath(io, dirname);
1710 }1710 }
1711 break :blk try cwd.createFile(io, dest_path, .{});1711 break :blk try cwd.createFile(io, dest_path, .{});
1712 },1712 },
...@@ -2634,13 +2634,12 @@ pub const InstallDir = union(enum) {...@@ -2634,13 +2634,12 @@ pub const InstallDir = union(enum) {
2634/// source of API breakage in the future, so keep that in mind when using this2634/// source of API breakage in the future, so keep that in mind when using this
2635/// function.2635/// function.
2636pub fn makeTempPath(b: *Build) []const u8 {2636pub fn makeTempPath(b: *Build) []const u8 {
2637 const io = b.graph.io;
2637 const rand_int = std.crypto.random.int(u64);2638 const rand_int = std.crypto.random.int(u64);
2638 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);2639 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
2639 const result_path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM");2640 const result_path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM");
2640 b.cache_root.handle.makePath(tmp_dir_sub_path) catch |err| {2641 b.cache_root.handle.makePath(io, tmp_dir_sub_path) catch |err| {
2641 std.debug.print("unable to make tmp path '{s}': {s}\n", .{2642 std.debug.print("unable to make tmp path '{s}': {t}\n", .{ result_path, err });
2642 result_path, @errorName(err),
2643 });
2644 };2643 };
2645 return result_path;2644 return result_path;
2646}2645}
lib/std/Build/Cache/Path.zig+2-2
...@@ -128,14 +128,14 @@ pub fn access(p: Path, sub_path: []const u8, flags: Io.Dir.AccessOptions) !void...@@ -128,14 +128,14 @@ pub fn access(p: Path, sub_path: []const u8, flags: Io.Dir.AccessOptions) !void
128 return p.root_dir.handle.access(joined_path, flags);128 return p.root_dir.handle.access(joined_path, flags);
129}129}
130130
131pub fn makePath(p: Path, sub_path: []const u8) !void {131pub fn makePath(p: Path, io: Io, sub_path: []const u8) !void {
132 var buf: [fs.max_path_bytes]u8 = undefined;132 var buf: [fs.max_path_bytes]u8 = undefined;
133 const joined_path = if (p.sub_path.len == 0) sub_path else p: {133 const joined_path = if (p.sub_path.len == 0) sub_path else p: {
134 break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{134 break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
135 p.sub_path, sub_path,135 p.sub_path, sub_path,
136 }) catch return error.NameTooLong;136 }) catch return error.NameTooLong;
137 };137 };
138 return p.root_dir.handle.makePath(joined_path);138 return p.root_dir.handle.makePath(io, joined_path);
139}139}
140140
141pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {141pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
lib/std/Build/Step/ConfigHeader.zig+2-1
...@@ -184,6 +184,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -184,6 +184,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
184184
185 const gpa = b.allocator;185 const gpa = b.allocator;
186 const arena = b.allocator;186 const arena = b.allocator;
187 const io = b.graph.io;
187188
188 var man = b.graph.cache.obtain();189 var man = b.graph.cache.obtain();
189 defer man.deinit();190 defer man.deinit();
...@@ -257,7 +258,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -257,7 +258,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
257 const sub_path = b.pathJoin(&.{ "o", &digest, config_header.include_path });258 const sub_path = b.pathJoin(&.{ "o", &digest, config_header.include_path });
258 const sub_path_dirname = std.fs.path.dirname(sub_path).?;259 const sub_path_dirname = std.fs.path.dirname(sub_path).?;
259260
260 b.cache_root.handle.makePath(sub_path_dirname) catch |err| {261 b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {
261 return step.fail("unable to make path '{f}{s}': {s}", .{262 return step.fail("unable to make path '{f}{s}': {s}", .{
262 b.cache_root, sub_path_dirname, @errorName(err),263 b.cache_root, sub_path_dirname, @errorName(err),
263 });264 });
lib/std/Build/Step/ObjCopy.zig+2-1
...@@ -143,6 +143,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {...@@ -143,6 +143,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {
143fn make(step: *Step, options: Step.MakeOptions) !void {143fn make(step: *Step, options: Step.MakeOptions) !void {
144 const prog_node = options.progress_node;144 const prog_node = options.progress_node;
145 const b = step.owner;145 const b = step.owner;
146 const io = b.graph.io;
146 const objcopy: *ObjCopy = @fieldParentPtr("step", step);147 const objcopy: *ObjCopy = @fieldParentPtr("step", step);
147 try step.singleUnchangingWatchInput(objcopy.input_file);148 try step.singleUnchangingWatchInput(objcopy.input_file);
148149
...@@ -176,7 +177,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -176,7 +177,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
176 const cache_path = "o" ++ fs.path.sep_str ++ digest;177 const cache_path = "o" ++ fs.path.sep_str ++ digest;
177 const full_dest_path = try b.cache_root.join(b.allocator, &.{ cache_path, objcopy.basename });178 const full_dest_path = try b.cache_root.join(b.allocator, &.{ cache_path, objcopy.basename });
178 const full_dest_path_debug = try b.cache_root.join(b.allocator, &.{ cache_path, b.fmt("{s}.debug", .{objcopy.basename}) });179 const full_dest_path_debug = try b.cache_root.join(b.allocator, &.{ cache_path, b.fmt("{s}.debug", .{objcopy.basename}) });
179 b.cache_root.handle.makePath(cache_path) catch |err| {180 b.cache_root.handle.makePath(io, cache_path) catch |err| {
180 return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });181 return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });
181 };182 };
182183
lib/std/Build/Step/Run.zig+4-3
...@@ -973,7 +973,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -973,7 +973,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
973 .output_directory => output_sub_path,973 .output_directory => output_sub_path,
974 else => unreachable,974 else => unreachable,
975 };975 };
976 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {976 b.cache_root.handle.makePath(io, output_sub_dir_path) catch |err| {
977 return step.fail("unable to make path '{f}{s}': {s}", .{977 return step.fail("unable to make path '{f}{s}': {s}", .{
978 b.cache_root, output_sub_dir_path, @errorName(err),978 b.cache_root, output_sub_dir_path, @errorName(err),
979 });979 });
...@@ -1005,7 +1005,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1005,7 +1005,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
1005 .output_directory => output_sub_path,1005 .output_directory => output_sub_path,
1006 else => unreachable,1006 else => unreachable,
1007 };1007 };
1008 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {1008 b.cache_root.handle.makePath(io, output_sub_dir_path) catch |err| {
1009 return step.fail("unable to make path '{f}{s}': {s}", .{1009 return step.fail("unable to make path '{f}{s}': {s}", .{
1010 b.cache_root, output_sub_dir_path, @errorName(err),1010 b.cache_root, output_sub_dir_path, @errorName(err),
1011 });1011 });
...@@ -1241,6 +1241,7 @@ fn runCommand(...@@ -1241,6 +1241,7 @@ fn runCommand(
1241 const b = step.owner;1241 const b = step.owner;
1242 const arena = b.allocator;1242 const arena = b.allocator;
1243 const gpa = options.gpa;1243 const gpa = options.gpa;
1244 const io = b.graph.io;
12441245
1245 const cwd: ?[]const u8 = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, step) else null;1246 const cwd: ?[]const u8 = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, step) else null;
12461247
...@@ -1470,7 +1471,7 @@ fn runCommand(...@@ -1470,7 +1471,7 @@ fn runCommand(
14701471
1471 const sub_path = b.pathJoin(&output_components);1472 const sub_path = b.pathJoin(&output_components);
1472 const sub_path_dirname = fs.path.dirname(sub_path).?;1473 const sub_path_dirname = fs.path.dirname(sub_path).?;
1473 b.cache_root.handle.makePath(sub_path_dirname) catch |err| {1474 b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {
1474 return step.fail("unable to make path '{f}{s}': {s}", .{1475 return step.fail("unable to make path '{f}{s}': {s}", .{
1475 b.cache_root, sub_path_dirname, @errorName(err),1476 b.cache_root, sub_path_dirname, @errorName(err),
1476 });1477 });
lib/std/Build/Step/UpdateSourceFiles.zig+1-1
...@@ -78,7 +78,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -78,7 +78,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
78 var any_miss = false;78 var any_miss = false;
79 for (usf.output_source_files.items) |output_source_file| {79 for (usf.output_source_files.items) |output_source_file| {
80 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {80 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
81 b.build_root.handle.makePath(dirname) catch |err| {81 b.build_root.handle.makePath(io, dirname) catch |err| {
82 return step.fail("unable to make path '{f}{s}': {t}", .{ b.build_root, dirname, err });82 return step.fail("unable to make path '{f}{s}': {t}", .{ b.build_root, dirname, err });
83 };83 };
84 }84 }
lib/std/Build/Step/WriteFile.zig+3-3
...@@ -268,7 +268,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -268,7 +268,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
268268
269 for (write_file.files.items) |file| {269 for (write_file.files.items) |file| {
270 if (fs.path.dirname(file.sub_path)) |dirname| {270 if (fs.path.dirname(file.sub_path)) |dirname| {
271 cache_dir.makePath(dirname) catch |err| {271 cache_dir.makePath(io, dirname) catch |err| {
272 return step.fail("unable to make path '{f}{s}{c}{s}': {t}", .{272 return step.fail("unable to make path '{f}{s}{c}{s}': {t}", .{
273 b.cache_root, cache_path, fs.path.sep, dirname, err,273 b.cache_root, cache_path, fs.path.sep, dirname, err,
274 });274 });
...@@ -303,7 +303,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -303,7 +303,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
303 const dest_dirname = dir.sub_path;303 const dest_dirname = dir.sub_path;
304304
305 if (dest_dirname.len != 0) {305 if (dest_dirname.len != 0) {
306 cache_dir.makePath(dest_dirname) catch |err| {306 cache_dir.makePath(io, dest_dirname) catch |err| {
307 return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{307 return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{
308 b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err),308 b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err),
309 });309 });
...@@ -318,7 +318,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -318,7 +318,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
318 const src_entry_path = try src_dir_path.join(arena, entry.path);318 const src_entry_path = try src_dir_path.join(arena, entry.path);
319 const dest_path = b.pathJoin(&.{ dest_dirname, entry.path });319 const dest_path = b.pathJoin(&.{ dest_dirname, entry.path });
320 switch (entry.kind) {320 switch (entry.kind) {
321 .directory => try cache_dir.makePath(dest_path),321 .directory => try cache_dir.makePath(io, dest_path),
322 .file => {322 .file => {
323 const prev_status = Io.Dir.updateFile(323 const prev_status = Io.Dir.updateFile(
324 src_entry_path.root_dir.handle,324 src_entry_path.root_dir.handle,
lib/std/debug.zig+7-5
...@@ -522,7 +522,7 @@ pub fn defaultPanic(...@@ -522,7 +522,7 @@ pub fn defaultPanic(
522 }522 }
523 @trap();523 @trap();
524 },524 },
525 .cuda, .amdhsa => std.posix.abort(),525 .cuda, .amdhsa => std.process.abort(),
526 .plan9 => {526 .plan9 => {
527 var status: [std.os.plan9.ERRMAX]u8 = undefined;527 var status: [std.os.plan9.ERRMAX]u8 = undefined;
528 const len = @min(msg.len, status.len - 1);528 const len = @min(msg.len, status.len - 1);
...@@ -575,12 +575,13 @@ pub fn defaultPanic(...@@ -575,12 +575,13 @@ pub fn defaultPanic(
575 // A panic happened while trying to print a previous panic message.575 // A panic happened while trying to print a previous panic message.
576 // We're still holding the mutex but that's fine as we're going to576 // We're still holding the mutex but that's fine as we're going to
577 // call abort().577 // call abort().
578 File.stderr().writeStreamingAll("aborting due to recursive panic\n") catch {};578 const stderr, _ = lockStderrWriter(&.{});
579 stderr.writeAll("aborting due to recursive panic\n") catch {};
579 },580 },
580 else => {}, // Panicked while printing the recursive panic message.581 else => {}, // Panicked while printing the recursive panic message.
581 }582 }
582583
583 posix.abort();584 std.process.abort();
584}585}
585586
586/// Must be called only after adding 1 to `panicking`. There are three callsites.587/// Must be called only after adding 1 to `panicking`. There are three callsites.
...@@ -1596,7 +1597,8 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex...@@ -1596,7 +1597,8 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
1596 // A segfault happened while trying to print a previous panic message.1597 // A segfault happened while trying to print a previous panic message.
1597 // We're still holding the mutex but that's fine as we're going to1598 // We're still holding the mutex but that's fine as we're going to
1598 // call abort().1599 // call abort().
1599 File.stderr().writeAll("aborting due to recursive panic\n") catch {};1600 const stderr, _ = lockStderrWriter(&.{});
1601 stderr().writeAll("aborting due to recursive panic\n") catch {};
1600 },1602 },
1601 else => {}, // Panicked while printing the recursive panic message.1603 else => {}, // Panicked while printing the recursive panic message.
1602 }1604 }
...@@ -1604,7 +1606,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex...@@ -1604,7 +1606,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
1604 // We cannot allow the signal handler to return because when it runs the original instruction1606 // We cannot allow the signal handler to return because when it runs the original instruction
1605 // again, the memory may be mapped and undefined behavior would occur rather than repeating1607 // again, the memory may be mapped and undefined behavior would occur rather than repeating
1606 // the segfault. So we simply abort here.1608 // the segfault. So we simply abort here.
1607 posix.abort();1609 std.process.abort();
1608}1610}
16091611
1610pub fn dumpStackPointerAddr(prefix: []const u8) void {1612pub fn dumpStackPointerAddr(prefix: []const u8) void {
lib/std/fs/test.zig+27-18
...@@ -674,7 +674,7 @@ test "Dir.Iterator but dir is deleted during iteration" {...@@ -674,7 +674,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
674 var iterator = subdir.iterate();674 var iterator = subdir.iterate();
675675
676 // Create something to iterate over within the subdir676 // Create something to iterate over within the subdir
677 try tmp.dir.makePath("subdir" ++ fs.path.sep_str ++ "b");677 try tmp.dir.makePath(io, "subdir" ++ fs.path.sep_str ++ "b");
678678
679 // Then, before iterating, delete the directory that we're iterating.679 // Then, before iterating, delete the directory that we're iterating.
680 // This is a contrived reproduction, but this could happen outside of the program, in another thread, etc.680 // This is a contrived reproduction, but this could happen outside of the program, in another thread, etc.
...@@ -1196,7 +1196,7 @@ test "deleteTree does not follow symlinks" {...@@ -1196,7 +1196,7 @@ test "deleteTree does not follow symlinks" {
1196 var tmp = tmpDir(.{});1196 var tmp = tmpDir(.{});
1197 defer tmp.cleanup();1197 defer tmp.cleanup();
11981198
1199 try tmp.dir.makePath("b");1199 try tmp.dir.makePath(io, "b");
1200 {1200 {
1201 var a = try tmp.dir.makeOpenPath("a", .{});1201 var a = try tmp.dir.makeOpenPath("a", .{});
1202 defer a.close(io);1202 defer a.close(io);
...@@ -1211,6 +1211,8 @@ test "deleteTree does not follow symlinks" {...@@ -1211,6 +1211,8 @@ test "deleteTree does not follow symlinks" {
1211}1211}
12121212
1213test "deleteTree on a symlink" {1213test "deleteTree on a symlink" {
1214 const io = testing.io;
1215
1214 var tmp = tmpDir(.{});1216 var tmp = tmpDir(.{});
1215 defer tmp.cleanup();1217 defer tmp.cleanup();
12161218
...@@ -1223,7 +1225,7 @@ test "deleteTree on a symlink" {...@@ -1223,7 +1225,7 @@ test "deleteTree on a symlink" {
1223 try tmp.dir.access("file", .{});1225 try tmp.dir.access("file", .{});
12241226
1225 // Symlink to a directory1227 // Symlink to a directory
1226 try tmp.dir.makePath("dir");1228 try tmp.dir.makePath(io, "dir");
1227 try setupSymlink(tmp.dir, "dir", "dirlink", .{ .is_directory = true });1229 try setupSymlink(tmp.dir, "dir", "dirlink", .{ .is_directory = true });
12281230
1229 try tmp.dir.deleteTree("dirlink");1231 try tmp.dir.deleteTree("dirlink");
...@@ -1238,7 +1240,7 @@ test "makePath, put some files in it, deleteTree" {...@@ -1238,7 +1240,7 @@ test "makePath, put some files in it, deleteTree" {
1238 const allocator = ctx.arena.allocator();1240 const allocator = ctx.arena.allocator();
1239 const dir_path = try ctx.transformPath("os_test_tmp");1241 const dir_path = try ctx.transformPath("os_test_tmp");
12401242
1241 try ctx.dir.makePath(try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));1243 try ctx.dir.makePath(io, try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
1242 try ctx.dir.writeFile(.{1244 try ctx.dir.writeFile(.{
1243 .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),1245 .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
1244 .data = "nonsense",1246 .data = "nonsense",
...@@ -1261,7 +1263,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {...@@ -1261,7 +1263,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
1261 const allocator = ctx.arena.allocator();1263 const allocator = ctx.arena.allocator();
1262 const dir_path = try ctx.transformPath("os_test_tmp");1264 const dir_path = try ctx.transformPath("os_test_tmp");
12631265
1264 try ctx.dir.makePath(try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));1266 try ctx.dir.makePath(io, try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
1265 try ctx.dir.writeFile(.{1267 try ctx.dir.writeFile(.{
1266 .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),1268 .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
1267 .data = "nonsense",1269 .data = "nonsense",
...@@ -1280,21 +1282,25 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {...@@ -1280,21 +1282,25 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
1280test "makePath in a directory that no longer exists" {1282test "makePath in a directory that no longer exists" {
1281 if (native_os == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir1283 if (native_os == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir
12821284
1285 const io = testing.io;
1286
1283 var tmp = tmpDir(.{});1287 var tmp = tmpDir(.{});
1284 defer tmp.cleanup();1288 defer tmp.cleanup();
1285 try tmp.parent_dir.deleteTree(&tmp.sub_path);1289 try tmp.parent_dir.deleteTree(&tmp.sub_path);
12861290
1287 try testing.expectError(error.FileNotFound, tmp.dir.makePath("sub-path"));1291 try testing.expectError(error.FileNotFound, tmp.dir.makePath(io, "sub-path"));
1288}1292}
12891293
1290test "makePath but sub_path contains pre-existing file" {1294test "makePath but sub_path contains pre-existing file" {
1295 const io = testing.io;
1296
1291 var tmp = tmpDir(.{});1297 var tmp = tmpDir(.{});
1292 defer tmp.cleanup();1298 defer tmp.cleanup();
12931299
1294 try tmp.dir.makeDir("foo");1300 try tmp.dir.makeDir("foo");
1295 try tmp.dir.writeFile(.{ .sub_path = "foo/bar", .data = "" });1301 try tmp.dir.writeFile(.{ .sub_path = "foo/bar", .data = "" });
12961302
1297 try testing.expectError(error.NotDir, tmp.dir.makePath("foo/bar/baz"));1303 try testing.expectError(error.NotDir, tmp.dir.makePath(io, "foo/bar/baz"));
1298}1304}
12991305
1300fn expectDir(io: Io, dir: Dir, path: []const u8) !void {1306fn expectDir(io: Io, dir: Dir, path: []const u8) !void {
...@@ -1314,7 +1320,7 @@ test "makepath existing directories" {...@@ -1314,7 +1320,7 @@ test "makepath existing directories" {
1314 try tmpA.makeDir("B");1320 try tmpA.makeDir("B");
13151321
1316 const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";1322 const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";
1317 try tmp.dir.makePath(testPath);1323 try tmp.dir.makePath(io, testPath);
13181324
1319 try expectDir(io, tmp.dir, testPath);1325 try expectDir(io, tmp.dir, testPath);
1320}1326}
...@@ -1328,7 +1334,7 @@ test "makepath through existing valid symlink" {...@@ -1328,7 +1334,7 @@ test "makepath through existing valid symlink" {
1328 try tmp.dir.makeDir("realfolder");1334 try tmp.dir.makeDir("realfolder");
1329 try setupSymlink(tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});1335 try setupSymlink(tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
13301336
1331 try tmp.dir.makePath("working-symlink" ++ fs.path.sep_str ++ "in-realfolder");1337 try tmp.dir.makePath(io, "working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
13321338
1333 try expectDir(io, tmp.dir, "realfolder" ++ fs.path.sep_str ++ "in-realfolder");1339 try expectDir(io, tmp.dir, "realfolder" ++ fs.path.sep_str ++ "in-realfolder");
1334}1340}
...@@ -1344,7 +1350,7 @@ test "makepath relative walks" {...@@ -1344,7 +1350,7 @@ test "makepath relative walks" {
1344 });1350 });
1345 defer testing.allocator.free(relPath);1351 defer testing.allocator.free(relPath);
13461352
1347 try tmp.dir.makePath(relPath);1353 try tmp.dir.makePath(io, relPath);
13481354
1349 // How .. is handled is different on Windows than non-Windows1355 // How .. is handled is different on Windows than non-Windows
1350 switch (native_os) {1356 switch (native_os) {
...@@ -1383,7 +1389,7 @@ test "makepath ignores '.'" {...@@ -1383,7 +1389,7 @@ test "makepath ignores '.'" {
1383 });1389 });
1384 defer testing.allocator.free(expectedPath);1390 defer testing.allocator.free(expectedPath);
13851391
1386 try tmp.dir.makePath(dotPath);1392 try tmp.dir.makePath(io, dotPath);
13871393
1388 try expectDir(io, tmp.dir, expectedPath);1394 try expectDir(io, tmp.dir, expectedPath);
1389}1395}
...@@ -1550,10 +1556,11 @@ test "setEndPos" {...@@ -1550,10 +1556,11 @@ test "setEndPos" {
1550test "access file" {1556test "access file" {
1551 try testWithAllSupportedPathTypes(struct {1557 try testWithAllSupportedPathTypes(struct {
1552 fn impl(ctx: *TestContext) !void {1558 fn impl(ctx: *TestContext) !void {
1559 const io = ctx.io;
1553 const dir_path = try ctx.transformPath("os_test_tmp");1560 const dir_path = try ctx.transformPath("os_test_tmp");
1554 const file_path = try ctx.transformPath("os_test_tmp" ++ fs.path.sep_str ++ "file.txt");1561 const file_path = try ctx.transformPath("os_test_tmp" ++ fs.path.sep_str ++ "file.txt");
15551562
1556 try ctx.dir.makePath(dir_path);1563 try ctx.dir.makePath(io, dir_path);
1557 try testing.expectError(error.FileNotFound, ctx.dir.access(file_path, .{}));1564 try testing.expectError(error.FileNotFound, ctx.dir.access(file_path, .{}));
15581565
1559 try ctx.dir.writeFile(.{ .sub_path = file_path, .data = "" });1566 try ctx.dir.writeFile(.{ .sub_path = file_path, .data = "" });
...@@ -1569,7 +1576,7 @@ test "sendfile" {...@@ -1569,7 +1576,7 @@ test "sendfile" {
1569 var tmp = tmpDir(.{});1576 var tmp = tmpDir(.{});
1570 defer tmp.cleanup();1577 defer tmp.cleanup();
15711578
1572 try tmp.dir.makePath("os_test_tmp");1579 try tmp.dir.makePath(io, "os_test_tmp");
15731580
1574 var dir = try tmp.dir.openDir(io, "os_test_tmp", .{});1581 var dir = try tmp.dir.openDir(io, "os_test_tmp", .{});
1575 defer dir.close(io);1582 defer dir.close(io);
...@@ -1616,7 +1623,7 @@ test "sendfile with buffered data" {...@@ -1616,7 +1623,7 @@ test "sendfile with buffered data" {
1616 var tmp = tmpDir(.{});1623 var tmp = tmpDir(.{});
1617 defer tmp.cleanup();1624 defer tmp.cleanup();
16181625
1619 try tmp.dir.makePath("os_test_tmp");1626 try tmp.dir.makePath(io, "os_test_tmp");
16201627
1621 var dir = try tmp.dir.openDir(io, "os_test_tmp", .{});1628 var dir = try tmp.dir.openDir(io, "os_test_tmp", .{});
1622 defer dir.close(io);1629 defer dir.close(io);
...@@ -1894,7 +1901,7 @@ test "walker" {...@@ -1894,7 +1901,7 @@ test "walker" {
1894 });1901 });
18951902
1896 for (expected_paths.keys()) |key| {1903 for (expected_paths.keys()) |key| {
1897 try tmp.dir.makePath(key);1904 try tmp.dir.makePath(io, key);
1898 }1905 }
18991906
1900 var walker = try tmp.dir.walk(testing.allocator);1907 var walker = try tmp.dir.walk(testing.allocator);
...@@ -1956,7 +1963,7 @@ test "selective walker, skip entries that start with ." {...@@ -1956,7 +1963,7 @@ test "selective walker, skip entries that start with ." {
1956 });1963 });
19571964
1958 for (paths_to_create) |path| {1965 for (paths_to_create) |path| {
1959 try tmp.dir.makePath(path);1966 try tmp.dir.makePath(io, path);
1960 }1967 }
19611968
1962 var walker = try tmp.dir.walkSelectively(testing.allocator);1969 var walker = try tmp.dir.walkSelectively(testing.allocator);
...@@ -1991,6 +1998,8 @@ test "selective walker, skip entries that start with ." {...@@ -1991,6 +1998,8 @@ test "selective walker, skip entries that start with ." {
1991}1998}
19921999
1993test "walker without fully iterating" {2000test "walker without fully iterating" {
2001 const io = testing.io;
2002
1994 var tmp = tmpDir(.{ .iterate = true });2003 var tmp = tmpDir(.{ .iterate = true });
1995 defer tmp.cleanup();2004 defer tmp.cleanup();
19962005
...@@ -2000,8 +2009,8 @@ test "walker without fully iterating" {...@@ -2000,8 +2009,8 @@ test "walker without fully iterating" {
2000 // Create 2 directories inside the tmp directory, but then only iterate once before breaking.2009 // Create 2 directories inside the tmp directory, but then only iterate once before breaking.
2001 // This ensures that walker doesn't try to close the initial directory when not fully iterating.2010 // This ensures that walker doesn't try to close the initial directory when not fully iterating.
20022011
2003 try tmp.dir.makePath("a");2012 try tmp.dir.makePath(io, "a");
2004 try tmp.dir.makePath("b");2013 try tmp.dir.makePath(io, "b");
20052014
2006 var num_walked: usize = 0;2015 var num_walked: usize = 0;
2007 while (try walker.next()) |_| {2016 while (try walker.next()) |_| {
lib/std/os/linux/IoUring.zig-26
...@@ -4090,32 +4090,6 @@ test "openat_direct/close_direct" {...@@ -4090,32 +4090,6 @@ test "openat_direct/close_direct" {
4090 try ring.unregister_files();4090 try ring.unregister_files();
4091}4091}
40924092
4093test "waitid" {
4094 try skipKernelLessThan(.{ .major = 6, .minor = 7, .patch = 0 });
4095
4096 var ring = IoUring.init(16, 0) catch |err| switch (err) {
4097 error.SystemOutdated => return error.SkipZigTest,
4098 error.PermissionDenied => return error.SkipZigTest,
4099 else => return err,
4100 };
4101 defer ring.deinit();
4102
4103 const pid = try posix.fork();
4104 if (pid == 0) {
4105 posix.exit(7);
4106 }
4107
4108 var siginfo: posix.siginfo_t = undefined;
4109 _ = try ring.waitid(0, .PID, pid, &siginfo, posix.W.EXITED, 0);
4110
4111 try testing.expectEqual(1, try ring.submit());
4112
4113 const cqe_waitid = try ring.copy_cqe();
4114 try testing.expectEqual(0, cqe_waitid.res);
4115 try testing.expectEqual(pid, siginfo.fields.common.first.piduid.pid);
4116 try testing.expectEqual(7, siginfo.fields.common.second.sigchld.status);
4117}
4118
4119/// For use in tests. Returns SkipZigTest if kernel version is less than required.4093/// For use in tests. Returns SkipZigTest if kernel version is less than required.
4120inline fn skipKernelLessThan(required: std.SemanticVersion) !void {4094inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
4121 if (!is_linux) return error.SkipZigTest;4095 if (!is_linux) return error.SkipZigTest;
lib/std/posix.zig-87
...@@ -615,66 +615,6 @@ fn getRandomBytesDevURandom(buf: []u8) GetRandomError!void {...@@ -615,66 +615,6 @@ fn getRandomBytesDevURandom(buf: []u8) GetRandomError!void {
615 }615 }
616}616}
617617
618/// Causes abnormal process termination.
619/// If linking against libc, this calls the abort() libc function. Otherwise
620/// it raises SIGABRT followed by SIGKILL and finally lo
621/// Invokes the current signal handler for SIGABRT, if any.
622pub fn abort() noreturn {
623 @branchHint(.cold);
624 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
625 // even when linking libc on Windows we use our own abort implementation.
626 // See https://github.com/ziglang/zig/issues/2071 for more details.
627 if (native_os == .windows) {
628 if (builtin.mode == .Debug and windows.peb().BeingDebugged != 0) {
629 @breakpoint();
630 }
631 windows.ntdll.RtlExitUserProcess(3);
632 }
633 if (!builtin.link_libc and native_os == .linux) {
634 // The Linux man page says that the libc abort() function
635 // "first unblocks the SIGABRT signal", but this is a footgun
636 // for user-defined signal handlers that want to restore some state in
637 // some program sections and crash in others.
638 // So, the user-installed SIGABRT handler is run, if present.
639 raise(.ABRT) catch {};
640
641 // Disable all signal handlers.
642 const filledset = linux.sigfillset();
643 sigprocmask(SIG.BLOCK, &filledset, null);
644
645 // Only one thread may proceed to the rest of abort().
646 if (!builtin.single_threaded) {
647 const global = struct {
648 var abort_entered: bool = false;
649 };
650 while (@cmpxchgWeak(bool, &global.abort_entered, false, true, .seq_cst, .seq_cst)) |_| {}
651 }
652
653 // Install default handler so that the tkill below will terminate.
654 const sigact = Sigaction{
655 .handler = .{ .handler = SIG.DFL },
656 .mask = sigemptyset(),
657 .flags = 0,
658 };
659 sigaction(.ABRT, &sigact, null);
660
661 _ = linux.tkill(linux.gettid(), .ABRT);
662
663 var sigabrtmask = sigemptyset();
664 sigaddset(&sigabrtmask, .ABRT);
665 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
666
667 // Beyond this point should be unreachable.
668 @as(*allowzero volatile u8, @ptrFromInt(0)).* = 0;
669 raise(.KILL) catch {};
670 exit(127); // Pid 1 might not be signalled in some containers.
671 }
672 switch (native_os) {
673 .uefi, .wasi, .emscripten, .cuda, .amdhsa => @trap(),
674 else => system.abort(),
675 }
676}
677
678pub const RaiseError = UnexpectedError;618pub const RaiseError = UnexpectedError;
679619
680pub fn raise(sig: SIG) RaiseError!void {620pub fn raise(sig: SIG) RaiseError!void {
...@@ -715,33 +655,6 @@ pub fn kill(pid: pid_t, sig: SIG) KillError!void {...@@ -715,33 +655,6 @@ pub fn kill(pid: pid_t, sig: SIG) KillError!void {
715 }655 }
716}656}
717657
718/// Exits all threads of the program with the specified status code.
719pub fn exit(status: u8) noreturn {
720 if (builtin.link_libc) {
721 std.c.exit(status);
722 }
723 if (native_os == .windows) {
724 windows.ntdll.RtlExitUserProcess(status);
725 }
726 if (native_os == .wasi) {
727 wasi.proc_exit(status);
728 }
729 if (native_os == .linux and !builtin.single_threaded) {
730 linux.exit_group(status);
731 }
732 if (native_os == .uefi) {
733 const uefi = std.os.uefi;
734 // exit() is only available if exitBootServices() has not been called yet.
735 // This call to exit should not fail, so we catch-ignore errors.
736 if (uefi.system_table.boot_services) |bs| {
737 bs.exit(uefi.handle, @enumFromInt(status), null) catch {};
738 }
739 // If we can't exit, reboot the system instead.
740 uefi.system_table.runtime_services.resetSystem(.cold, @enumFromInt(status), null);
741 }
742 system.exit(status);
743}
744
745pub const ReadError = std.Io.File.Reader.Error;658pub const ReadError = std.Io.File.Reader.Error;
746659
747/// Returns the number of bytes that were read, which can be less than660/// Returns the number of bytes that were read, which can be less than
lib/std/posix/test.zig-67
...@@ -667,73 +667,6 @@ test "writev longer than IOV_MAX" {...@@ -667,73 +667,6 @@ test "writev longer than IOV_MAX" {
667 try testing.expectEqual(@as(usize, posix.IOV_MAX), amt);667 try testing.expectEqual(@as(usize, posix.IOV_MAX), amt);
668}668}
669669
670test "POSIX file locking with fcntl" {
671 if (native_os == .windows or native_os == .wasi) {
672 // Not POSIX.
673 return error.SkipZigTest;
674 }
675
676 if (true) {
677 // https://github.com/ziglang/zig/issues/11074
678 return error.SkipZigTest;
679 }
680
681 const io = testing.io;
682
683 var tmp = tmpDir(.{});
684 defer tmp.cleanup();
685
686 // Create a temporary lock file
687 var file = try tmp.dir.createFile(io, "lock", .{ .read = true });
688 defer file.close(io);
689 try file.setEndPos(2);
690 const fd = file.handle;
691
692 // Place an exclusive lock on the first byte, and a shared lock on the second byte:
693 var struct_flock = std.mem.zeroInit(posix.Flock, .{ .type = posix.F.WRLCK });
694 _ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
695 struct_flock.start = 1;
696 struct_flock.type = posix.F.RDLCK;
697 _ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
698
699 // Check the locks in a child process:
700 const pid = try posix.fork();
701 if (pid == 0) {
702 // child expects be denied the exclusive lock:
703 struct_flock.start = 0;
704 struct_flock.type = posix.F.WRLCK;
705 try expectError(error.Locked, posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock)));
706 // child expects to get the shared lock:
707 struct_flock.start = 1;
708 struct_flock.type = posix.F.RDLCK;
709 _ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
710 // child waits for the exclusive lock in order to test deadlock:
711 struct_flock.start = 0;
712 struct_flock.type = posix.F.WRLCK;
713 _ = try posix.fcntl(fd, posix.F.SETLKW, @intFromPtr(&struct_flock));
714 // child exits without continuing:
715 posix.exit(0);
716 } else {
717 // parent waits for child to get shared lock:
718 std.Thread.sleep(1 * std.time.ns_per_ms);
719 // parent expects deadlock when attempting to upgrade the shared lock to exclusive:
720 struct_flock.start = 1;
721 struct_flock.type = posix.F.WRLCK;
722 try expectError(error.DeadLock, posix.fcntl(fd, posix.F.SETLKW, @intFromPtr(&struct_flock)));
723 // parent releases exclusive lock:
724 struct_flock.start = 0;
725 struct_flock.type = posix.F.UNLCK;
726 _ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
727 // parent releases shared lock:
728 struct_flock.start = 1;
729 struct_flock.type = posix.F.UNLCK;
730 _ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
731 // parent waits for child:
732 const result = posix.waitpid(pid, 0);
733 try expect(result.status == 0 * 256);
734 }
735}
736
737test "rename smoke test" {670test "rename smoke test" {
738 if (native_os == .wasi) return error.SkipZigTest;671 if (native_os == .wasi) return error.SkipZigTest;
739 if (native_os == .windows) return error.SkipZigTest;672 if (native_os == .windows) return error.SkipZigTest;
lib/std/process.zig+84-2
...@@ -16,8 +16,6 @@ const unicode = std.unicode;...@@ -16,8 +16,6 @@ const unicode = std.unicode;
16const max_path_bytes = std.fs.max_path_bytes;16const max_path_bytes = std.fs.max_path_bytes;
1717
18pub const Child = @import("process/Child.zig");18pub const Child = @import("process/Child.zig");
19pub const abort = posix.abort;
20pub const exit = posix.exit;
21pub const changeCurDir = posix.chdir;19pub const changeCurDir = posix.chdir;
22pub const changeCurDirZ = posix.chdirZ;20pub const changeCurDirZ = posix.chdirZ;
2321
...@@ -2208,3 +2206,87 @@ pub const OpenExecutableError = File.OpenError || ExecutablePathError || File.Lo...@@ -2208,3 +2206,87 @@ pub const OpenExecutableError = File.OpenError || ExecutablePathError || File.Lo
2208pub fn openExecutable(io: Io, flags: File.OpenFlags) OpenExecutableError!File {2206pub fn openExecutable(io: Io, flags: File.OpenFlags) OpenExecutableError!File {
2209 return io.vtable.processExecutableOpen(io.userdata, flags);2207 return io.vtable.processExecutableOpen(io.userdata, flags);
2210}2208}
2209
2210/// Causes abnormal process termination.
2211///
2212/// If linking against libc, this calls `std.c.abort`. Otherwise it raises
2213/// SIGABRT followed by SIGKILL.
2214///
2215/// Invokes the current signal handler for SIGABRT, if any.
2216pub fn abort() noreturn {
2217 @branchHint(.cold);
2218 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
2219 // even when linking libc on Windows we use our own abort implementation.
2220 // See https://github.com/ziglang/zig/issues/2071 for more details.
2221 if (native_os == .windows) {
2222 if (builtin.mode == .Debug and windows.peb().BeingDebugged != 0) {
2223 @breakpoint();
2224 }
2225 windows.ntdll.RtlExitUserProcess(3);
2226 }
2227 if (!builtin.link_libc and native_os == .linux) {
2228 // The Linux man page says that the libc abort() function
2229 // "first unblocks the SIGABRT signal", but this is a footgun
2230 // for user-defined signal handlers that want to restore some state in
2231 // some program sections and crash in others.
2232 // So, the user-installed SIGABRT handler is run, if present.
2233 posix.raise(.ABRT) catch {};
2234
2235 // Disable all signal handlers.
2236 const filledset = std.os.linux.sigfillset();
2237 posix.sigprocmask(posix.SIG.BLOCK, &filledset, null);
2238
2239 // Only one thread may proceed to the rest of abort().
2240 if (!builtin.single_threaded) {
2241 const global = struct {
2242 var abort_entered: bool = false;
2243 };
2244 while (@cmpxchgWeak(bool, &global.abort_entered, false, true, .seq_cst, .seq_cst)) |_| {}
2245 }
2246
2247 // Install default handler so that the tkill below will terminate.
2248 const sigact: posix.Sigaction = .{
2249 .handler = .{ .handler = posix.SIG.DFL },
2250 .mask = posix.sigemptyset(),
2251 .flags = 0,
2252 };
2253 posix.sigaction(.ABRT, &sigact, null);
2254
2255 _ = std.os.linux.tkill(std.os.linux.gettid(), .ABRT);
2256
2257 var sigabrtmask = posix.sigemptyset();
2258 posix.sigaddset(&sigabrtmask, .ABRT);
2259 posix.sigprocmask(posix.SIG.UNBLOCK, &sigabrtmask, null);
2260
2261 // Beyond this point should be unreachable.
2262 @as(*allowzero volatile u8, @ptrFromInt(0)).* = 0;
2263 posix.raise(.KILL) catch {};
2264 exit(127); // Pid 1 might not be signalled in some containers.
2265 }
2266 switch (native_os) {
2267 .uefi, .wasi, .emscripten, .cuda, .amdhsa => @trap(),
2268 else => posix.system.abort(),
2269 }
2270}
2271
2272/// Exits all threads of the program with the specified status code.
2273pub fn exit(status: u8) noreturn {
2274 if (builtin.link_libc) {
2275 std.c.exit(status);
2276 } else switch (native_os) {
2277 .windows => windows.ntdll.RtlExitUserProcess(status),
2278 .wasi => std.os.wasi.proc_exit(status),
2279 .linux => if (!builtin.single_threaded) std.os.linux.exit_group(status),
2280 .uefi => {
2281 const uefi = std.os.uefi;
2282 // exit() is only available if exitBootServices() has not been called yet.
2283 // This call to exit should not fail, so we catch-ignore errors.
2284 if (uefi.system_table.boot_services) |bs| {
2285 bs.exit(uefi.handle, @enumFromInt(status), null) catch {};
2286 }
2287 // If we can't exit, reboot the system instead.
2288 uefi.system_table.runtime_services.resetSystem(.cold, @enumFromInt(status), null);
2289 },
2290 else => posix.system.exit(status),
2291 }
2292}
lib/std/process/Child.zig+1-1
...@@ -1050,7 +1050,7 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {...@@ -1050,7 +1050,7 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
1050 // The _exit(2) function does nothing but make the exit syscall, unlike exit(3)1050 // The _exit(2) function does nothing but make the exit syscall, unlike exit(3)
1051 std.c._exit(1);1051 std.c._exit(1);
1052 }1052 }
1053 posix.exit(1);1053 posix.system.exit(1);
1054}1054}
10551055
1056fn writeIntFd(fd: i32, value: ErrInt) !void {1056fn writeIntFd(fd: i32, value: ErrInt) !void {
lib/std/start.zig+3-3
...@@ -110,7 +110,7 @@ fn main2() callconv(.c) c_int {...@@ -110,7 +110,7 @@ fn main2() callconv(.c) c_int {
110}110}
111111
112fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {112fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {
113 std.posix.exit(callMain());113 std.process.exit(callMain());
114}114}
115115
116fn spirvMain2() callconv(.kernel) void {116fn spirvMain2() callconv(.kernel) void {
...@@ -118,7 +118,7 @@ fn spirvMain2() callconv(.kernel) void {...@@ -118,7 +118,7 @@ fn spirvMain2() callconv(.kernel) void {
118}118}
119119
120fn wWinMainCRTStartup2() callconv(.c) noreturn {120fn wWinMainCRTStartup2() callconv(.c) noreturn {
121 std.posix.exit(callMain());121 std.process.exit(callMain());
122}122}
123123
124////////////////////////////////////////////////////////////////////////////////124////////////////////////////////////////////////////////////////////////////////
...@@ -627,7 +627,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -627,7 +627,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
627 for (slice) |func| func();627 for (slice) |func| func();
628 }628 }
629629
630 std.posix.exit(callMainWithArgs(argc, argv, envp));630 std.process.exit(callMainWithArgs(argc, argv, envp));
631}631}
632632
633fn expandStackSize(phdrs: []elf.Phdr) void {633fn expandStackSize(phdrs: []elf.Phdr) void {
lib/std/tar.zig+8-8
...@@ -606,7 +606,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp...@@ -606,7 +606,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp
606 switch (file.kind) {606 switch (file.kind) {
607 .directory => {607 .directory => {
608 if (file_name.len > 0 and !options.exclude_empty_directories) {608 if (file_name.len > 0 and !options.exclude_empty_directories) {
609 try dir.makePath(file_name);609 try dir.makePath(io, file_name);
610 }610 }
611 },611 },
612 .file => {612 .file => {
...@@ -625,7 +625,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp...@@ -625,7 +625,7 @@ pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOp
625 },625 },
626 .sym_link => {626 .sym_link => {
627 const link_name = file.link_name;627 const link_name = file.link_name;
628 createDirAndSymlink(dir, link_name, file_name) catch |err| {628 createDirAndSymlink(io, dir, link_name, file_name) catch |err| {
629 const d = options.diagnostics orelse return error.UnableToCreateSymLink;629 const d = options.diagnostics orelse return error.UnableToCreateSymLink;
630 try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{630 try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
631 .code = err,631 .code = err,
...@@ -642,7 +642,7 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, mode: Io.File.Mo...@@ -642,7 +642,7 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, mode: Io.File.Mo
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, .mode = mode }) 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(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, .mode = mode });
647 }647 }
648 }648 }
...@@ -652,11 +652,11 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, mode: Io.File.Mo...@@ -652,11 +652,11 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, mode: Io.File.Mo
652}652}
653653
654// Creates a symbolic link at path `file_name` which points to `link_name`.654// Creates a symbolic link at path `file_name` which points to `link_name`.
655fn createDirAndSymlink(dir: Io.Dir, link_name: []const u8, file_name: []const u8) !void {655fn createDirAndSymlink(io: Io, dir: Io.Dir, link_name: []const u8, file_name: []const u8) !void {
656 dir.symLink(link_name, file_name, .{}) catch |err| {656 dir.symLink(link_name, file_name, .{}) catch |err| {
657 if (err == error.FileNotFound) {657 if (err == error.FileNotFound) {
658 if (std.fs.path.dirname(file_name)) |dir_name| {658 if (std.fs.path.dirname(file_name)) |dir_name| {
659 try dir.makePath(dir_name);659 try dir.makePath(io, dir_name);
660 return try dir.symLink(link_name, file_name, .{});660 return try dir.symLink(link_name, file_name, .{});
661 }661 }
662 }662 }
...@@ -885,15 +885,15 @@ test "create file and symlink" {...@@ -885,15 +885,15 @@ test "create file and symlink" {
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_mode);
886 file.close(io);886 file.close(io);
887887
888 createDirAndSymlink(root.dir, "a/b/c/file2", "symlink1") catch |err| {888 createDirAndSymlink(io, root.dir, "a/b/c/file2", "symlink1") catch |err| {
889 // On Windows when developer mode is not enabled889 // On Windows when developer mode is not enabled
890 if (err == error.AccessDenied) return error.SkipZigTest;890 if (err == error.AccessDenied) return error.SkipZigTest;
891 return err;891 return err;
892 };892 };
893 try createDirAndSymlink(root.dir, "../../../file1", "d/e/f/symlink2");893 try createDirAndSymlink(io, root.dir, "../../../file1", "d/e/f/symlink2");
894894
895 // Danglink symlnik, file created later895 // Danglink symlnik, file created later
896 try createDirAndSymlink(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_mode);
898 file.close(io);898 file.close(io);
899}899}
lib/std/zip.zig+3-3
...@@ -464,6 +464,8 @@ pub const Iterator = struct {...@@ -464,6 +464,8 @@ pub const Iterator = struct {
464 filename_buf: []u8,464 filename_buf: []u8,
465 dest: Io.Dir,465 dest: Io.Dir,
466 ) !void {466 ) !void {
467 const io = stream.io;
468
467 if (filename_buf.len < self.filename_len)469 if (filename_buf.len < self.filename_len)
468 return error.ZipInsufficientBuffer;470 return error.ZipInsufficientBuffer;
469 switch (self.compression_method) {471 switch (self.compression_method) {
...@@ -552,12 +554,10 @@ pub const Iterator = struct {...@@ -552,12 +554,10 @@ pub const Iterator = struct {
552 if (filename[filename.len - 1] == '/') {554 if (filename[filename.len - 1] == '/') {
553 if (self.uncompressed_size != 0)555 if (self.uncompressed_size != 0)
554 return error.ZipBadDirectorySize;556 return error.ZipBadDirectorySize;
555 try dest.makePath(filename[0 .. filename.len - 1]);557 try dest.makePath(io, filename[0 .. filename.len - 1]);
556 return;558 return;
557 }559 }
558560
559 const io = stream.io;
560
561 const out_file = blk: {561 const out_file = blk: {
562 if (std.fs.path.dirname(filename)) |dirname| {562 if (std.fs.path.dirname(filename)) |dirname| {
563 var parent_dir = try dest.makeOpenPath(dirname, .{});563 var parent_dir = try dest.makeOpenPath(dirname, .{});
src/Compilation.zig+6-4
...@@ -3180,7 +3180,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3180,7 +3180,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3180 const s = fs.path.sep_str;3180 const s = fs.path.sep_str;
3181 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);3181 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
3182 const o_sub_path = "o" ++ s ++ hex_digest;3182 const o_sub_path = "o" ++ s ++ hex_digest;
3183 renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| {3183 renameTmpIntoCache(io, comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| {
3184 return comp.setMiscFailure(3184 return comp.setMiscFailure(
3185 .rename_results,3185 .rename_results,
3186 "failed to rename compilation results ('{f}{s}') into local cache ('{f}{s}'): {t}",3186 "failed to rename compilation results ('{f}{s}') into local cache ('{f}{s}'): {t}",
...@@ -3399,17 +3399,19 @@ fn flush(...@@ -3399,17 +3399,19 @@ fn flush(
3399/// implementation at the bottom of this function.3399/// implementation at the bottom of this function.
3400/// This function is only called when CacheMode is `whole`.3400/// This function is only called when CacheMode is `whole`.
3401fn renameTmpIntoCache(3401fn renameTmpIntoCache(
3402 io: Io,
3402 cache_directory: Cache.Directory,3403 cache_directory: Cache.Directory,
3403 tmp_dir_sub_path: []const u8,3404 tmp_dir_sub_path: []const u8,
3404 o_sub_path: []const u8,3405 o_sub_path: []const u8,
3405) !void {3406) !void {
3406 var seen_eaccess = false;3407 var seen_eaccess = false;
3407 while (true) {3408 while (true) {
3408 fs.rename(3409 Io.Dir.rename(
3409 cache_directory.handle,3410 cache_directory.handle,
3410 tmp_dir_sub_path,3411 tmp_dir_sub_path,
3411 cache_directory.handle,3412 cache_directory.handle,
3412 o_sub_path,3413 o_sub_path,
3414 io,
3413 ) catch |err| switch (err) {3415 ) catch |err| switch (err) {
3414 // On Windows, rename fails with `AccessDenied` rather than `PathAlreadyExists`.3416 // On Windows, rename fails with `AccessDenied` rather than `PathAlreadyExists`.
3415 // See https://github.com/ziglang/zig/issues/83623417 // See https://github.com/ziglang/zig/issues/8362
...@@ -3427,7 +3429,7 @@ fn renameTmpIntoCache(...@@ -3427,7 +3429,7 @@ fn renameTmpIntoCache(
3427 continue;3429 continue;
3428 },3430 },
3429 error.FileNotFound => {3431 error.FileNotFound => {
3430 try cache_directory.handle.makePath("o");3432 try cache_directory.handle.makePath(io, "o");
3431 continue;3433 continue;
3432 },3434 },
3433 else => |e| return e,3435 else => |e| return e,
...@@ -5816,7 +5818,7 @@ pub fn translateC(...@@ -5816,7 +5818,7 @@ pub fn translateC(
5816 const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;5818 const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
58175819
5818 if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path });5820 if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path });
5819 try renameTmpIntoCache(comp.dirs.local_cache, tmp_sub_path, o_sub_path);5821 try renameTmpIntoCache(io, comp.dirs.local_cache, tmp_sub_path, o_sub_path);
58205822
5821 return .{5823 return .{
5822 .digest = bin_digest,5824 .digest = bin_digest,
src/Package/Fetch.zig+3-2
...@@ -1414,6 +1414,7 @@ fn unpackGitPack(f: *Fetch, out_dir: Io.Dir, resource: *Resource.Git) anyerror!U...@@ -1414,6 +1414,7 @@ fn unpackGitPack(f: *Fetch, out_dir: Io.Dir, resource: *Resource.Git) anyerror!U
14141414
1415fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void {1415fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void {
1416 const gpa = f.arena.child_allocator;1416 const gpa = f.arena.child_allocator;
1417 const io = f.job_queue.io;
1417 // Recursive directory copy.1418 // Recursive directory copy.
1418 var it = try dir.walk(gpa);1419 var it = try dir.walk(gpa);
1419 defer it.deinit();1420 defer it.deinit();
...@@ -1428,7 +1429,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void...@@ -1428,7 +1429,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void
1428 .{},1429 .{},
1429 ) catch |err| switch (err) {1430 ) catch |err| switch (err) {
1430 error.FileNotFound => {1431 error.FileNotFound => {
1431 if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(dirname);1432 if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(io, dirname);
1432 try dir.copyFile(entry.path, tmp_dir, entry.path, .{});1433 try dir.copyFile(entry.path, tmp_dir, entry.path, .{});
1433 },1434 },
1434 else => |e| return e,1435 else => |e| return e,
...@@ -1441,7 +1442,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void...@@ -1441,7 +1442,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void
1441 // the destination directory, fail with an error instead.1442 // the destination directory, fail with an error instead.
1442 tmp_dir.symLink(link_name, entry.path, .{}) catch |err| switch (err) {1443 tmp_dir.symLink(link_name, entry.path, .{}) catch |err| switch (err) {
1443 error.FileNotFound => {1444 error.FileNotFound => {
1444 if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(dirname);1445 if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(io, dirname);
1445 try tmp_dir.symLink(link_name, entry.path, .{});1446 try tmp_dir.symLink(link_name, entry.path, .{});
1446 },1447 },
1447 else => |e| return e,1448 else => |e| return e,
src/main.zig+6-5
...@@ -3382,7 +3382,7 @@ fn buildOutputType(...@@ -3382,7 +3382,7 @@ fn buildOutputType(
3382 const dump_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-dump-stdin{s}", .{3382 const dump_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-dump-stdin{s}", .{
3383 std.crypto.random.int(u64), ext.canonicalName(target),3383 std.crypto.random.int(u64), ext.canonicalName(target),
3384 });3384 });
3385 try dirs.local_cache.handle.makePath("tmp");3385 try dirs.local_cache.handle.makePath(io, "tmp");
33863386
3387 // Note that in one of the happy paths, execve() is used to switch to3387 // Note that in one of the happy paths, execve() is used to switch to
3388 // clang in which case any cleanup logic that exists for this temporary3388 // clang in which case any cleanup logic that exists for this temporary
...@@ -4773,7 +4773,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !...@@ -4773,7 +4773,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
4773 var ok_count: usize = 0;4773 var ok_count: usize = 0;
47744774
4775 for (template_paths) |template_path| {4775 for (template_paths) |template_path| {
4776 if (templates.write(arena, Io.Dir.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {4776 if (templates.write(arena, io, Io.Dir.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4777 std.log.info("created {s}", .{template_path});4777 std.log.info("created {s}", .{template_path});
4778 ok_count += 1;4778 ok_count += 1;
4779 } else |err| switch (err) {4779 } else |err| switch (err) {
...@@ -7394,20 +7394,21 @@ const Templates = struct {...@@ -7394,20 +7394,21 @@ const Templates = struct {
7394 fn write(7394 fn write(
7395 templates: *Templates,7395 templates: *Templates,
7396 arena: Allocator,7396 arena: Allocator,
7397 io: Io,
7397 out_dir: Io.Dir,7398 out_dir: Io.Dir,
7398 root_name: []const u8,7399 root_name: []const u8,
7399 template_path: []const u8,7400 template_path: []const u8,
7400 fingerprint: Package.Fingerprint,7401 fingerprint: Package.Fingerprint,
7401 ) !void {7402 ) !void {
7402 if (fs.path.dirname(template_path)) |dirname| {7403 if (fs.path.dirname(template_path)) |dirname| {
7403 out_dir.makePath(dirname) catch |err| {7404 out_dir.makePath(io, dirname) catch |err| {
7404 fatal("unable to make path '{s}': {s}", .{ dirname, @errorName(err) });7405 fatal("unable to make path '{s}': {t}", .{ dirname, err });
7405 };7406 };
7406 }7407 }
74077408
7408 const max_bytes = 10 * 1024 * 1024;7409 const max_bytes = 10 * 1024 * 1024;
7409 const contents = templates.dir.readFileAlloc(template_path, arena, .limited(max_bytes)) catch |err| {7410 const contents = templates.dir.readFileAlloc(template_path, arena, .limited(max_bytes)) catch |err| {
7410 fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });7411 fatal("unable to read template file '{s}': {t}", .{ template_path, err });
7411 };7412 };
7412 templates.buffer.clearRetainingCapacity();7413 templates.buffer.clearRetainingCapacity();
7413 try templates.buffer.ensureUnusedCapacity(contents.len);7414 try templates.buffer.ensureUnusedCapacity(contents.len);