authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-05 19:08:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:07-08:00
logaafddc2ea13e40a8262d9378aeca2e097a37ac03
tree46770e51147a635a43c2e7356e62064466b51c34
parenteab354b2f5d7242c036523394023e9824be7eca9

update all occurrences of close() to close(io)


75 files changed, 1014 insertions(+), 707 deletions(-)

build.zig+2-2
......@@ -1604,12 +1604,12 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
16041604 b.build_root, @errorName(err),
16051605 });
16061606 };
1607 defer dir.close();
1607 defer dir.close(io);
16081608
16091609 var wf = b.addWriteFiles();
16101610
16111611 var it = dir.iterateAssumeFirstIteration();
1612 while (it.next() catch @panic("failed to read dir")) |entry| {
1612 while (it.next(io) catch @panic("failed to read dir")) |entry| {
16131613 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)
16141614 continue;
16151615
lib/compiler/aro/aro/Compilation.zig+6-2
......@@ -1639,8 +1639,10 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin
16391639 return error.FileNotFound;
16401640 }
16411641
1642 const io = comp.io;
1643
16421644 const file = try comp.cwd.openFile(path, .{});
1643 defer file.close();
1645 defer file.close(io);
16441646 return comp.addSourceFromFile(file, path, kind);
16451647}
16461648
......@@ -1971,8 +1973,10 @@ fn getPathContents(comp: *Compilation, path: []const u8, limit: Io.Limit) ![]u8
19711973 return error.FileNotFound;
19721974 }
19731975
1976 const io = comp.io;
1977
19741978 const file = try comp.cwd.openFile(path, .{});
1975 defer file.close();
1979 defer file.close(io);
19761980 return comp.getFileContents(file, limit);
19771981}
19781982
lib/compiler/aro/aro/Driver.zig+7-5
......@@ -1286,6 +1286,8 @@ fn processSource(
12861286 d.comp.generated_buf.items.len = 0;
12871287 const prev_total = d.diagnostics.errors;
12881288
1289 const io = d.comp.io;
1290
12891291 var pp = try Preprocessor.initDefault(d.comp);
12901292 defer pp.deinit();
12911293
......@@ -1328,7 +1330,7 @@ fn processSource(
13281330 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, errorDescription(er) })
13291331 else
13301332 std.fs.File.stdout();
1331 defer if (dep_file_name != null) file.close();
1333 defer if (dep_file_name != null) file.close(io);
13321334
13331335 var file_writer = file.writer(&writer_buf);
13341336 dep_file.write(&file_writer.interface) catch
......@@ -1353,7 +1355,7 @@ fn processSource(
13531355 return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })
13541356 else
13551357 std.fs.File.stdout();
1356 defer if (d.output_name != null) file.close();
1358 defer if (d.output_name != null) file.close(io);
13571359
13581360 var file_writer = file.writer(&writer_buf);
13591361 pp.prettyPrintTokens(&file_writer.interface, dump_mode) catch
......@@ -1404,7 +1406,7 @@ fn processSource(
14041406 if (d.only_preprocess_and_compile) {
14051407 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|
14061408 return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
1407 defer out_file.close();
1409 defer out_file.close(io);
14081410
14091411 assembly.writeToFile(out_file) catch |er|
14101412 return d.fatal("unable to write to output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
......@@ -1418,7 +1420,7 @@ fn processSource(
14181420 const assembly_out_file_name = try d.getRandomFilename(&assembly_name_buf, ".s");
14191421 const out_file = d.comp.cwd.createFile(assembly_out_file_name, .{}) catch |er|
14201422 return d.fatal("unable to create output file '{s}': {s}", .{ assembly_out_file_name, errorDescription(er) });
1421 defer out_file.close();
1423 defer out_file.close(io);
14221424 assembly.writeToFile(out_file) catch |er|
14231425 return d.fatal("unable to write to output file '{s}': {s}", .{ assembly_out_file_name, errorDescription(er) });
14241426 try d.invokeAssembler(tc, assembly_out_file_name, out_file_name);
......@@ -1454,7 +1456,7 @@ fn processSource(
14541456
14551457 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|
14561458 return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
1457 defer out_file.close();
1459 defer out_file.close(io);
14581460
14591461 var file_writer = out_file.writer(&writer_buf);
14601462 obj.finish(&file_writer.interface) catch
lib/compiler/aro/aro/Driver/Filesystem.zig+15-13
......@@ -1,8 +1,10 @@
1const std = @import("std");
2const mem = std.mem;
31const builtin = @import("builtin");
42const is_windows = builtin.os.tag == .windows;
53
4const std = @import("std");
5const Io = std.Io;
6const mem = std.std.mem;
7
68fn readFileFake(entries: []const Filesystem.Entry, path: []const u8, buf: []u8) ?[]const u8 {
79 @branchHint(.cold);
810 for (entries) |entry| {
......@@ -96,7 +98,7 @@ fn findProgramByNamePosix(name: []const u8, path: ?[]const u8, buf: []u8) ?[]con
9698}
9799
98100pub const Filesystem = union(enum) {
99 real: std.fs.Dir,
101 real: std.Io.Dir,
100102 fake: []const Entry,
101103
102104 const Entry = struct {
......@@ -121,7 +123,7 @@ pub const Filesystem = union(enum) {
121123 base: []const u8,
122124 i: usize = 0,
123125
124 fn next(self: *@This()) !?std.fs.Dir.Entry {
126 fn next(self: *@This()) !?std.Io.Dir.Entry {
125127 while (self.i < self.entries.len) {
126128 const entry = self.entries[self.i];
127129 self.i += 1;
......@@ -130,7 +132,7 @@ pub const Filesystem = union(enum) {
130132 const remaining = entry.path[self.base.len + 1 ..];
131133 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;
132134 const extension = std.fs.path.extension(remaining);
133 const kind: std.fs.Dir.Entry.Kind = if (extension.len == 0) .directory else .file;
135 const kind: std.Io.Dir.Entry.Kind = if (extension.len == 0) .directory else .file;
134136 return .{ .name = remaining, .kind = kind };
135137 }
136138 }
......@@ -140,7 +142,7 @@ pub const Filesystem = union(enum) {
140142 };
141143
142144 const Dir = union(enum) {
143 dir: std.fs.Dir,
145 dir: std.Io.Dir,
144146 fake: FakeDir,
145147
146148 pub fn iterate(self: Dir) Iterator {
......@@ -150,19 +152,19 @@ pub const Filesystem = union(enum) {
150152 };
151153 }
152154
153 pub fn close(self: *Dir) void {
155 pub fn close(self: *Dir, io: Io) void {
154156 switch (self.*) {
155 .dir => |*d| d.close(),
157 .dir => |*d| d.close(io),
156158 .fake => {},
157159 }
158160 }
159161 };
160162
161163 const Iterator = union(enum) {
162 iterator: std.fs.Dir.Iterator,
164 iterator: std.Io.Dir.Iterator,
163165 fake: FakeDir.Iterator,
164166
165 pub fn next(self: *Iterator) std.fs.Dir.Iterator.Error!?std.fs.Dir.Entry {
167 pub fn next(self: *Iterator) std.Io.Dir.Iterator.Error!?std.Io.Dir.Entry {
166168 return switch (self.*) {
167169 .iterator => |*it| it.next(),
168170 .fake => |*it| it.next(),
......@@ -208,11 +210,11 @@ pub const Filesystem = union(enum) {
208210 /// Read the file at `path` into `buf`.
209211 /// Returns null if any errors are encountered
210212 /// Otherwise returns a slice of `buf`. If the file is larger than `buf` partial contents are returned
211 pub fn readFile(fs: Filesystem, path: []const u8, buf: []u8) ?[]const u8 {
213 pub fn readFile(fs: Filesystem, io: Io, path: []const u8, buf: []u8) ?[]const u8 {
212214 return switch (fs) {
213215 .real => |cwd| {
214216 const file = cwd.openFile(path, .{}) catch return null;
215 defer file.close();
217 defer file.close(io);
216218
217219 const bytes_read = file.readAll(buf) catch return null;
218220 return buf[0..bytes_read];
......@@ -221,7 +223,7 @@ pub const Filesystem = union(enum) {
221223 };
222224 }
223225
224 pub fn openDir(fs: Filesystem, dir_name: []const u8) std.fs.Dir.OpenError!Dir {
226 pub fn openDir(fs: Filesystem, dir_name: []const u8) std.Io.Dir.OpenError!Dir {
225227 return switch (fs) {
226228 .real => |cwd| .{ .dir = try cwd.openDir(dir_name, .{ .access_sub_paths = false, .iterate = true }) },
227229 .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } },
lib/compiler/aro/aro/Toolchain.zig+2-1
......@@ -497,6 +497,7 @@ pub fn addBuiltinIncludeDir(tc: *const Toolchain) !void {
497497 const comp = d.comp;
498498 const gpa = comp.gpa;
499499 const arena = comp.arena;
500 const io = comp.io;
500501 try d.includes.ensureUnusedCapacity(gpa, 1);
501502 if (d.resource_dir) |resource_dir| {
502503 const path = try std.fs.path.join(arena, &.{ resource_dir, "include" });
......@@ -509,7 +510,7 @@ pub fn addBuiltinIncludeDir(tc: *const Toolchain) !void {
509510 var search_path = d.aro_name;
510511 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
511512 var base_dir = d.comp.cwd.openDir(dirname, .{}) catch continue;
512 defer base_dir.close();
513 defer base_dir.close(io);
513514
514515 base_dir.access("include/stddef.h", .{}) catch continue;
515516 const path = try std.fs.path.join(arena, &.{ dirname, "include" });
lib/compiler/objcopy.zig+2-2
......@@ -152,7 +152,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
152152 const io = threaded.io();
153153
154154 const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });
155 defer input_file.close();
155 defer input_file.close(io);
156156
157157 const stat = input_file.stat() catch |err| fatal("failed to stat {s}: {t}", .{ input, err });
158158
......@@ -180,7 +180,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
180180 const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode;
181181
182182 var output_file = try fs.cwd().createFile(output, .{ .mode = mode });
183 defer output_file.close();
183 defer output_file.close(io);
184184
185185 var out = output_file.writer(&output_buffer);
186186
lib/compiler/resinator/cli.zig+3-1
......@@ -1991,6 +1991,8 @@ test "parse: input and output formats" {
19911991}
19921992
19931993test "maybeAppendRC" {
1994 const io = std.testing.io;
1995
19941996 var tmp = std.testing.tmpDir(.{});
19951997 defer tmp.cleanup();
19961998
......@@ -2001,7 +2003,7 @@ test "maybeAppendRC" {
20012003 // Create the file so that it's found. In this scenario, .rc should not get
20022004 // appended.
20032005 var file = try tmp.dir.createFile("foo", .{});
2004 file.close();
2006 file.close(io);
20052007 try options.maybeAppendRC(tmp.dir);
20062008 try std.testing.expectEqualStrings("foo", options.input_source.filename);
20072009
lib/compiler/resinator/compile.zig+18-16
......@@ -34,7 +34,7 @@ const code_pages = @import("code_pages.zig");
3434const errors = @import("errors.zig");
3535
3636pub const CompileOptions = struct {
37 cwd: std.fs.Dir,
37 cwd: std.Io.Dir,
3838 diagnostics: *Diagnostics,
3939 source_mappings: ?*SourceMappings = null,
4040 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.
......@@ -107,7 +107,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
107107 // the cwd so we don't need to add it as a distinct search path.
108108 if (std.fs.path.dirname(root_path)) |root_dir_path| {
109109 var root_dir = try options.cwd.openDir(root_dir_path, .{});
110 errdefer root_dir.close();
110 errdefer root_dir.close(io);
111111 try search_dirs.append(allocator, .{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });
112112 }
113113 }
......@@ -136,7 +136,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
136136 // TODO: maybe a warning that the search path is skipped?
137137 continue;
138138 };
139 errdefer dir.close();
139 errdefer dir.close(io);
140140 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });
141141 }
142142 for (options.system_include_paths) |system_include_path| {
......@@ -144,7 +144,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
144144 // TODO: maybe a warning that the search path is skipped?
145145 continue;
146146 };
147 errdefer dir.close();
147 errdefer dir.close(io);
148148 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });
149149 }
150150 if (!options.ignore_include_env_var) {
......@@ -160,7 +160,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
160160 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
161161 while (it.next()) |search_path| {
162162 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
163 errdefer dir.close();
163 errdefer dir.close(io);
164164 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, search_path) });
165165 }
166166 }
......@@ -196,7 +196,7 @@ pub const Compiler = struct {
196196 arena: Allocator,
197197 allocator: Allocator,
198198 io: Io,
199 cwd: std.fs.Dir,
199 cwd: std.Io.Dir,
200200 state: State = .{},
201201 diagnostics: *Diagnostics,
202202 dependencies: ?*Dependencies,
......@@ -388,7 +388,9 @@ pub const Compiler = struct {
388388 /// matching file is invalid. That is, it does not do the `cmd` PATH searching
389389 /// thing of continuing to look for matching files until it finds a valid
390390 /// one if a matching file is invalid.
391 fn searchForFile(self: *Compiler, path: []const u8) !std.fs.File {
391 fn searchForFile(self: *Compiler, path: []const u8) !std.Io.File {
392 const io = self.io;
393
392394 // If the path is absolute, then it is not resolved relative to any search
393395 // paths, so there's no point in checking them.
394396 //
......@@ -405,7 +407,7 @@ pub const Compiler = struct {
405407 // an absolute path.
406408 if (std.fs.path.isAbsolute(path)) {
407409 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});
408 errdefer file.close();
410 errdefer file.close(io);
409411
410412 if (self.dependencies) |dependencies| {
411413 const duped_path = try dependencies.allocator.dupe(u8, path);
......@@ -414,10 +416,10 @@ pub const Compiler = struct {
414416 }
415417 }
416418
417 var first_error: ?(std.fs.File.OpenError || std.fs.File.StatError) = null;
419 var first_error: ?(std.Io.File.OpenError || std.Io.File.StatError) = null;
418420 for (self.search_dirs) |search_dir| {
419421 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {
420 errdefer file.close();
422 errdefer file.close(io);
421423
422424 if (self.dependencies) |dependencies| {
423425 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{
......@@ -587,7 +589,7 @@ pub const Compiler = struct {
587589 });
588590 },
589591 };
590 defer file_handle.close();
592 defer file_handle.close(io);
591593 var file_buffer: [2048]u8 = undefined;
592594 var file_reader = file_handle.reader(io, &file_buffer);
593595
......@@ -2892,9 +2894,9 @@ pub const Compiler = struct {
28922894 }
28932895};
28942896
2895pub const OpenSearchPathError = std.fs.Dir.OpenError;
2897pub const OpenSearchPathError = std.Io.Dir.OpenError;
28962898
2897fn openSearchPathDir(dir: std.fs.Dir, path: []const u8) OpenSearchPathError!std.fs.Dir {
2899fn openSearchPathDir(dir: std.Io.Dir, path: []const u8) OpenSearchPathError!std.Io.Dir {
28982900 // Validate the search path to avoid possible unreachable on invalid paths,
28992901 // see https://github.com/ziglang/zig/issues/15607 for why this is currently necessary.
29002902 try validateSearchPath(path);
......@@ -2927,11 +2929,11 @@ fn validateSearchPath(path: []const u8) error{BadPathName}!void {
29272929}
29282930
29292931pub const SearchDir = struct {
2930 dir: std.fs.Dir,
2932 dir: std.Io.Dir,
29312933 path: ?[]const u8,
29322934
2933 pub fn deinit(self: *SearchDir, allocator: Allocator) void {
2934 self.dir.close();
2935 pub fn deinit(self: *SearchDir, allocator: Allocator, io: Io) void {
2936 self.dir.close(io);
29352937 if (self.path) |path| {
29362938 allocator.free(path);
29372939 }
lib/compiler/resinator/errors.zig+2-2
......@@ -1221,8 +1221,8 @@ const CorrespondingLines = struct {
12211221 };
12221222 }
12231223
1224 pub fn deinit(self: *CorrespondingLines) void {
1225 self.file.close();
1224 pub fn deinit(self: *CorrespondingLines, io: Io) void {
1225 self.file.close(io);
12261226 }
12271227};
12281228
lib/compiler/resinator/main.zig+7-7
......@@ -296,7 +296,7 @@ pub fn main() !void {
296296 error.ParseError, error.CompileError => {
297297 try error_handler.emitDiagnostics(gpa, std.fs.cwd(), final_input, &diagnostics, mapping_results.mappings);
298298 // Delete the output file on error
299 res_stream.cleanupAfterError();
299 res_stream.cleanupAfterError(io);
300300 std.process.exit(1);
301301 },
302302 else => |e| return e,
......@@ -315,7 +315,7 @@ pub fn main() !void {
315315 try error_handler.emitMessage(gpa, .err, "unable to create depfile '{s}': {s}", .{ depfile_path, @errorName(err) });
316316 std.process.exit(1);
317317 };
318 defer depfile.close();
318 defer depfile.close(io);
319319
320320 var depfile_buffer: [1024]u8 = undefined;
321321 var depfile_writer = depfile.writer(&depfile_buffer);
......@@ -402,7 +402,7 @@ pub fn main() !void {
402402 },
403403 }
404404 // Delete the output file on error
405 coff_stream.cleanupAfterError();
405 coff_stream.cleanupAfterError(io);
406406 std.process.exit(1);
407407 };
408408
......@@ -434,11 +434,11 @@ const IoStream = struct {
434434 self.source.deinit(allocator);
435435 }
436436
437 pub fn cleanupAfterError(self: *IoStream) void {
437 pub fn cleanupAfterError(self: *IoStream, io: Io) void {
438438 switch (self.source) {
439439 .file => |file| {
440440 // Delete the output file on error
441 file.close();
441 file.close(io);
442442 // Failing to delete is not really a big deal, so swallow any errors
443443 std.fs.cwd().deleteFile(self.name) catch {};
444444 },
......@@ -465,9 +465,9 @@ const IoStream = struct {
465465 }
466466 }
467467
468 pub fn deinit(self: *Source, allocator: Allocator) void {
468 pub fn deinit(self: *Source, allocator: Allocator, io: Io) void {
469469 switch (self.*) {
470 .file => |file| file.close(),
470 .file => |file| file.close(io),
471471 .stdio => {},
472472 .memory => |*list| list.deinit(allocator),
473473 .closed => {},
lib/compiler/resinator/utils.zig+6-3
......@@ -1,6 +1,8 @@
1const std = @import("std");
21const builtin = @import("builtin");
32
3const std = @import("std");
4const Io = std.Io;
5
46pub const UncheckedSliceWriter = struct {
57 const Self = @This();
68
......@@ -28,11 +30,12 @@ pub const UncheckedSliceWriter = struct {
2830/// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed.
2931pub fn openFileNotDir(
3032 cwd: std.fs.Dir,
33 io: Io,
3134 path: []const u8,
3235 flags: std.fs.File.OpenFlags,
3336) (std.fs.File.OpenError || std.fs.File.StatError)!std.fs.File {
34 const file = try cwd.openFile(path, flags);
35 errdefer file.close();
37 const file = try cwd.openFile(io, path, flags);
38 errdefer file.close(io);
3639 // https://github.com/ziglang/zig/issues/5732
3740 if (builtin.os.tag != .windows) {
3841 const stat = try file.stat();
lib/compiler/std-docs.zig+22-11
......@@ -1,12 +1,14 @@
11const builtin = @import("builtin");
2
23const std = @import("std");
4const Io = std.Io;
35const mem = std.mem;
46const Allocator = std.mem.Allocator;
57const assert = std.debug.assert;
68const Cache = std.Build.Cache;
79
810fn usage() noreturn {
9 std.fs.File.stdout().writeAll(
11 std.Io.File.stdout().writeAll(
1012 \\Usage: zig std [options]
1113 \\
1214 \\Options:
......@@ -27,6 +29,10 @@ pub fn main() !void {
2729 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .init;
2830 const gpa = general_purpose_allocator.allocator();
2931
32 var threaded: std.Io.Threaded = .init(gpa);
33 defer threaded.deinit();
34 const io = threaded.io();
35
3036 var argv = try std.process.argsWithAllocator(arena);
3137 defer argv.deinit();
3238 assert(argv.skip());
......@@ -35,7 +41,7 @@ pub fn main() !void {
3541 const global_cache_path = argv.next().?;
3642
3743 var lib_dir = try std.fs.cwd().openDir(zig_lib_directory, .{});
38 defer lib_dir.close();
44 defer lib_dir.close(io);
3945
4046 var listen_port: u16 = 0;
4147 var force_open_browser: ?bool = null;
......@@ -64,7 +70,7 @@ pub fn main() !void {
6470 });
6571 const port = http_server.listen_address.in.getPort();
6672 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
67 std.fs.File.stdout().writeAll(url_with_newline) catch {};
73 std.Io.File.stdout().writeAll(url_with_newline) catch {};
6874 if (should_open_browser) {
6975 openBrowserTab(gpa, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {
7076 std.log.err("unable to open browser: {s}", .{@errorName(err)});
......@@ -73,6 +79,7 @@ pub fn main() !void {
7379
7480 var context: Context = .{
7581 .gpa = gpa,
82 .io = io,
7683 .zig_exe_path = zig_exe_path,
7784 .global_cache_path = global_cache_path,
7885 .lib_dir = lib_dir,
......@@ -83,14 +90,15 @@ pub fn main() !void {
8390 const connection = try http_server.accept();
8491 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {
8592 std.log.err("unable to accept connection: {s}", .{@errorName(err)});
86 connection.stream.close();
93 connection.stream.close(io);
8794 continue;
8895 };
8996 }
9097}
9198
9299fn accept(context: *Context, connection: std.net.Server.Connection) void {
93 defer connection.stream.close();
100 const io = context.io;
101 defer connection.stream.close(io);
94102
95103 var recv_buffer: [4000]u8 = undefined;
96104 var send_buffer: [4000]u8 = undefined;
......@@ -124,6 +132,7 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {
124132
125133const Context = struct {
126134 gpa: Allocator,
135 io: Io,
127136 lib_dir: std.fs.Dir,
128137 zig_lib_directory: []const u8,
129138 zig_exe_path: []const u8,
......@@ -185,6 +194,7 @@ fn serveDocsFile(
185194
186195fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
187196 const gpa = context.gpa;
197 const io = context.io;
188198
189199 var send_buffer: [0x4000]u8 = undefined;
190200 var response = try request.respondStreaming(&send_buffer, .{
......@@ -197,7 +207,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
197207 });
198208
199209 var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });
200 defer std_dir.close();
210 defer std_dir.close(io);
201211
202212 var walker = try std_dir.walk(gpa);
203213 defer walker.deinit();
......@@ -216,11 +226,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
216226 else => continue,
217227 }
218228 var file = try entry.dir.openFile(entry.basename, .{});
219 defer file.close();
229 defer file.close(io);
220230 const stat = try file.stat();
221 var file_reader: std.fs.File.Reader = .{
231 var file_reader: std.Io.File.Reader = .{
222232 .file = file,
223 .interface = std.fs.File.Reader.initInterface(&.{}),
233 .interface = std.Io.File.Reader.initInterface(&.{}),
224234 .size = stat.size,
225235 };
226236 try archiver.writeFile(entry.path, &file_reader, stat.mtime);
......@@ -283,6 +293,7 @@ fn buildWasmBinary(
283293 optimize_mode: std.builtin.OptimizeMode,
284294) !Cache.Path {
285295 const gpa = context.gpa;
296 const io = context.io;
286297
287298 var argv: std.ArrayList([]const u8) = .empty;
288299
......@@ -371,7 +382,7 @@ fn buildWasmBinary(
371382 }
372383
373384 // Send EOF to stdin.
374 child.stdin.?.close();
385 child.stdin.?.close(io);
375386 child.stdin = null;
376387
377388 switch (try child.wait()) {
......@@ -410,7 +421,7 @@ fn buildWasmBinary(
410421 };
411422}
412423
413fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
424fn sendMessage(file: std.Io.File, tag: std.zig.Client.Message.Tag) !void {
414425 const header: std.zig.Client.Message.Header = .{
415426 .tag = tag,
416427 .bytes_len = 0,
lib/compiler/translate-c/main.zig+3-2
......@@ -121,6 +121,7 @@ pub const usage =
121121
122122fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration: bool) !void {
123123 const gpa = d.comp.gpa;
124 const io = d.comp.io;
124125
125126 const aro_args = args: {
126127 var i: usize = 0;
......@@ -228,7 +229,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration
228229 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, aro.Driver.errorDescription(er) })
229230 else
230231 std.fs.File.stdout();
231 defer if (dep_file_name != null) file.close();
232 defer if (dep_file_name != null) file.close(io);
232233
233234 var file_writer = file.writer(&out_buf);
234235 dep_file.write(&file_writer.interface) catch
......@@ -246,7 +247,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration
246247 var close_out_file = false;
247248 var out_file_path: []const u8 = "<stdout>";
248249 var out_file: std.fs.File = .stdout();
249 defer if (close_out_file) out_file.close();
250 defer if (close_out_file) out_file.close(io);
250251
251252 if (d.output_name) |path| blk: {
252253 if (std.mem.eql(u8, path, "-")) break :blk;
lib/std/Build/Cache/Directory.zig+2-2
......@@ -52,8 +52,8 @@ pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) !
5252/// Whether or not the handle should be closed, or the path should be freed
5353/// is determined by usage, however this function is provided for convenience
5454/// if it happens to be what the caller needs.
55pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
56 self.handle.close();
55pub fn closeAndFree(self: *Directory, gpa: Allocator, io: Io) void {
56 self.handle.close(io);
5757 if (self.path) |p| gpa.free(p);
5858 self.* = undefined;
5959}
lib/std/Build/Fuzz.zig+2-2
......@@ -411,7 +411,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
411411 });
412412 return error.AlreadyReported;
413413 };
414 defer coverage_file.close();
414 defer coverage_file.close(io);
415415
416416 const file_size = coverage_file.getEndPos() catch |err| {
417417 log.err("unable to check len of coverage file '{f}': {t}", .{ coverage_file_path, err });
......@@ -533,7 +533,7 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) void {
533533 cov.run.step.name, coverage_file_path, err,
534534 });
535535 };
536 defer coverage_file.close();
536 defer coverage_file.close(io);
537537
538538 const fuzz_abi = std.Build.abi.fuzz;
539539 var rbuf: [0x1000]u8 = undefined;
lib/std/Build/Step.zig+2-1
......@@ -441,6 +441,7 @@ pub fn evalZigProcess(
441441 assert(argv.len != 0);
442442 const b = s.owner;
443443 const arena = b.allocator;
444 const io = b.graph.io;
444445
445446 try handleChildProcUnsupported(s);
446447 try handleVerbose(s.owner, null, argv);
......@@ -474,7 +475,7 @@ pub fn evalZigProcess(
474475
475476 if (!watch) {
476477 // Send EOF to stdin.
477 zp.child.stdin.?.close();
478 zp.child.stdin.?.close(io);
478479 zp.child.stdin = null;
479480
480481 const term = zp.child.wait() catch |err| {
lib/std/Build/Step/InstallArtifact.zig+2-1
......@@ -119,6 +119,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
119119 _ = options;
120120 const install_artifact: *InstallArtifact = @fieldParentPtr("step", step);
121121 const b = step.owner;
122 const io = b.graph.io;
122123
123124 var all_cached = true;
124125
......@@ -168,7 +169,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
168169 src_dir_path, @errorName(err),
169170 });
170171 };
171 defer src_dir.close();
172 defer src_dir.close(io);
172173
173174 var it = try src_dir.walk(b.allocator);
174175 next_entry: while (try it.next()) |entry| {
lib/std/Build/Step/InstallDir.zig+1-1
......@@ -68,7 +68,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
6868 var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
6969 return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err });
7070 };
71 defer src_dir.close();
71 defer src_dir.close(io);
7272 var it = try src_dir.walk(arena);
7373 var all_cached = true;
7474 next_entry: while (try it.next()) |entry| {
lib/std/Build/Step/Run.zig+11-9
......@@ -851,7 +851,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
851851 .{ file_path, err },
852852 );
853853 };
854 defer file.close();
854 defer file.close(io);
855855
856856 var buf: [1024]u8 = undefined;
857857 var file_reader = file.reader(io, &buf);
......@@ -1111,7 +1111,7 @@ pub fn rerunInFuzzMode(
11111111 result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory;
11121112
11131113 const file = try file_path.root_dir.handle.openFile(file_path.subPathOrDot(), .{});
1114 defer file.close();
1114 defer file.close(io);
11151115
11161116 var buf: [1024]u8 = undefined;
11171117 var file_reader = file.reader(io, &buf);
......@@ -1671,8 +1671,10 @@ fn evalZigTest(
16711671 options: Step.MakeOptions,
16721672 fuzz_context: ?FuzzContext,
16731673) !EvalZigTestResult {
1674 const gpa = run.step.owner.allocator;
1675 const arena = run.step.owner.allocator;
1674 const step_owner = run.step.owner;
1675 const gpa = step_owner.allocator;
1676 const arena = step_owner.allocator;
1677 const io = step_owner.graph.io;
16761678
16771679 // We will update this every time a child runs.
16781680 run.step.result_peak_rss = 0;
......@@ -1724,7 +1726,7 @@ fn evalZigTest(
17241726 run.step.result_stderr = try arena.dupe(u8, poller.reader(.stderr).buffered());
17251727
17261728 // Clean up everything and wait for the child to exit.
1727 child.stdin.?.close();
1729 child.stdin.?.close(io);
17281730 child.stdin = null;
17291731 poller.deinit();
17301732 child_killed = true;
......@@ -1744,7 +1746,7 @@ fn evalZigTest(
17441746 poller.reader(.stderr).tossBuffered();
17451747
17461748 // Clean up everything and wait for the child to exit.
1747 child.stdin.?.close();
1749 child.stdin.?.close(io);
17481750 child.stdin = null;
17491751 poller.deinit();
17501752 child_killed = true;
......@@ -2177,7 +2179,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
21772179 child.stdin.?.writeAll(bytes) catch |err| {
21782180 return run.step.fail("unable to write stdin: {s}", .{@errorName(err)});
21792181 };
2180 child.stdin.?.close();
2182 child.stdin.?.close(io);
21812183 child.stdin = null;
21822184 },
21832185 .lazy_path => |lazy_path| {
......@@ -2185,7 +2187,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
21852187 const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
21862188 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
21872189 };
2188 defer file.close();
2190 defer file.close(io);
21892191 // TODO https://github.com/ziglang/zig/issues/23955
21902192 var read_buffer: [1024]u8 = undefined;
21912193 var file_reader = file.reader(io, &read_buffer);
......@@ -2204,7 +2206,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
22042206 stdin_writer.err.?,
22052207 }),
22062208 };
2207 child.stdin.?.close();
2209 child.stdin.?.close(io);
22082210 child.stdin = null;
22092211 },
22102212 .none => {},
lib/std/Build/Step/WriteFile.zig+6-4
......@@ -206,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
206206 }
207207 }
208208
209 const open_dir_cache = try arena.alloc(fs.Dir, write_file.directories.items.len);
209 const open_dir_cache = try arena.alloc(Io.Dir, write_file.directories.items.len);
210210 var open_dirs_count: usize = 0;
211211 defer closeDirs(open_dir_cache[0..open_dirs_count]);
212212
......@@ -264,7 +264,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
264264 b.cache_root, cache_path, @errorName(err),
265265 });
266266 };
267 defer cache_dir.close();
267 defer cache_dir.close(io);
268268
269269 for (write_file.files.items) |file| {
270270 if (fs.path.dirname(file.sub_path)) |dirname| {
......@@ -342,6 +342,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
342342 try step.writeManifest(&man);
343343}
344344
345fn closeDirs(dirs: []fs.Dir) void {
346 for (dirs) |*d| d.close();
345fn closeDirs(io: Io, dirs: []Io.Dir) void {
346 var group: Io.Group = .init;
347 defer group.wait();
348 for (dirs) |d| group.async(Io.Dir.close, .{ d, io });
347349}
lib/std/Build/Watch/FsEvents.zig+5-4
......@@ -78,10 +78,10 @@ const ResolvedSymbols = struct {
7878 kCFAllocatorUseContext: *const CFAllocatorRef,
7979};
8080
81pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
81pub fn init(io: Io) error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
8282 var core_services = std.DynLib.open("/System/Library/Frameworks/CoreServices.framework/CoreServices") catch
8383 return error.OpenFrameworkFailed;
84 errdefer core_services.close();
84 errdefer core_services.close(io);
8585
8686 var resolved_symbols: ResolvedSymbols = undefined;
8787 inline for (@typeInfo(ResolvedSymbols).@"struct".fields) |f| {
......@@ -102,10 +102,10 @@ pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
102102 };
103103}
104104
105pub fn deinit(fse: *FsEvents, gpa: Allocator) void {
105pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void {
106106 dispatch_release(fse.waiting_semaphore);
107107 dispatch_release(fse.dispatch_queue);
108 fse.core_services.close();
108 fse.core_services.close(io);
109109
110110 gpa.free(fse.watch_roots);
111111 fse.watch_paths.deinit(gpa);
......@@ -487,6 +487,7 @@ const FSEventStreamEventFlags = packed struct(u32) {
487487};
488488
489489const std = @import("std");
490const Io = std.Io;
490491const assert = std.debug.assert;
491492const Allocator = std.mem.Allocator;
492493const watch_log = std.log.scoped(.watch);
lib/std/Build/WebServer.zig+4-3
......@@ -129,6 +129,7 @@ pub fn init(opts: Options) WebServer {
129129}
130130pub fn deinit(ws: *WebServer) void {
131131 const gpa = ws.gpa;
132 const io = ws.graph.io;
132133
133134 gpa.free(ws.step_names_trailing);
134135 gpa.free(ws.step_status_bits);
......@@ -139,7 +140,7 @@ pub fn deinit(ws: *WebServer) void {
139140 gpa.free(ws.time_report_update_times);
140141
141142 if (ws.serve_thread) |t| {
142 if (ws.tcp_server) |*s| s.stream.close();
143 if (ws.tcp_server) |*s| s.stream.close(io);
143144 t.join();
144145 }
145146 if (ws.tcp_server) |*s| s.deinit();
......@@ -507,7 +508,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons
507508 log.err("failed to open '{f}': {s}", .{ path, @errorName(err) });
508509 continue;
509510 };
510 defer file.close();
511 defer file.close(io);
511512 const stat = try file.stat();
512513 var read_buffer: [1024]u8 = undefined;
513514 var file_reader: Io.File.Reader = .initSize(file.adaptToNewApi(), io, &read_buffer, stat.size);
......@@ -634,7 +635,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
634635 }
635636
636637 // Send EOF to stdin.
637 child.stdin.?.close();
638 child.stdin.?.close(io);
638639 child.stdin = null;
639640
640641 switch (try child.wait()) {
lib/std/Io/Dir.zig+25-16
......@@ -131,7 +131,7 @@ pub const SelectiveWalker = struct {
131131 /// After each call to this function, and on deinit(), the memory returned
132132 /// from this function becomes invalid. A copy must be made in order to keep
133133 /// a reference to the path.
134 pub fn next(self: *SelectiveWalker) Error!?Walker.Entry {
134 pub fn next(self: *SelectiveWalker, io: Io) Error!?Walker.Entry {
135135 while (self.stack.items.len > 0) {
136136 const top = &self.stack.items[self.stack.items.len - 1];
137137 var dirname_len = top.dirname_len;
......@@ -142,7 +142,7 @@ pub const SelectiveWalker = struct {
142142 // likely just fail with the same error.
143143 var item = self.stack.pop().?;
144144 if (self.stack.items.len != 0) {
145 item.iter.dir.close();
145 item.iter.dir.close(io);
146146 }
147147 return err;
148148 }) |entry| {
......@@ -164,7 +164,7 @@ pub const SelectiveWalker = struct {
164164 } else {
165165 var item = self.stack.pop().?;
166166 if (self.stack.items.len != 0) {
167 item.iter.dir.close();
167 item.iter.dir.close(io);
168168 }
169169 }
170170 }
......@@ -172,7 +172,7 @@ pub const SelectiveWalker = struct {
172172 }
173173
174174 /// Traverses into the directory, continuing walking one level down.
175 pub fn enter(self: *SelectiveWalker, entry: Walker.Entry) !void {
175 pub fn enter(self: *SelectiveWalker, io: Io, entry: Walker.Entry) !void {
176176 if (entry.kind != .directory) {
177177 @branchHint(.cold);
178178 return;
......@@ -184,7 +184,7 @@ pub const SelectiveWalker = struct {
184184 else => |e| return e,
185185 }
186186 };
187 errdefer new_dir.close();
187 errdefer new_dir.close(io);
188188
189189 try self.stack.append(self.allocator, .{
190190 .iter = new_dir.iterateAssumeFirstIteration(),
......@@ -200,11 +200,11 @@ pub const SelectiveWalker = struct {
200200 /// Leaves the current directory, continuing walking one level up.
201201 /// If the current entry is a directory entry, then the "current directory"
202202 /// will pertain to that entry if `enter` is called before `leave`.
203 pub fn leave(self: *SelectiveWalker) void {
203 pub fn leave(self: *SelectiveWalker, io: Io) void {
204204 var item = self.stack.pop().?;
205205 if (self.stack.items.len != 0) {
206206 @branchHint(.likely);
207 item.iter.dir.close();
207 item.iter.dir.close(io);
208208 }
209209 }
210210};
......@@ -558,7 +558,8 @@ pub fn makeDir(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions)
558558
559559pub const MakePathError = MakeError || StatPathError;
560560
561/// Creates parent directories as necessary to ensure `sub_path` exists as a directory.
561/// Creates parent directories with default permissions as necessary to ensure
562/// `sub_path` exists as a directory.
562563///
563564/// Returns success if the path already exists and is a directory.
564565///
......@@ -579,8 +580,11 @@ pub const MakePathError = MakeError || StatPathError;
579580/// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`,
580581/// meaning a `sub_path` like "first/../second" will create both a `./first`
581582/// and a `./second` directory.
582pub fn makePath(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions) MakePathError!void {
583 _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, permissions);
583///
584/// See also:
585/// * `makePathStatus`
586pub fn makePath(dir: Dir, io: Io, sub_path: []const u8) MakePathError!void {
587 _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, .default_dir);
584588}
585589
586590pub const MakePathStatus = enum { existed, created };
......@@ -593,6 +597,11 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8, permissions: Permi
593597
594598pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
595599
600pub const MakeOpenPathOptions = struct {
601 open_options: OpenOptions = .{},
602 permissions: Permissions = .default_dir,
603};
604
596605/// Performs the equivalent of `makePath` followed by `openDir`, atomically if possible.
597606///
598607/// When this operation is canceled, it may leave the file system in a
......@@ -601,8 +610,8 @@ pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
601610/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
602611/// On WASI, `sub_path` should be encoded as valid UTF-8.
603612/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
604pub fn makeOpenPath(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions, options: OpenOptions) MakeOpenPathError!Dir {
605 return io.vtable.dirMakeOpenPath(io.userdata, dir, sub_path, permissions, options);
613pub fn makeOpenPath(dir: Dir, io: Io, sub_path: []const u8, options: MakeOpenPathOptions) MakeOpenPathError!Dir {
614 return io.vtable.dirMakeOpenPath(io.userdata, dir, sub_path, options.permissions, options.open_options);
606615}
607616
608617pub const Stat = File.Stat;
......@@ -1266,10 +1275,10 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
12661275 start_over: while (true) {
12671276 var dir = (try parent.deleteTreeOpenInitialSubpath(io, sub_path, kind_hint)) orelse return;
12681277 var cleanup_dir_parent: ?Dir = null;
1269 defer if (cleanup_dir_parent) |*d| d.close();
1278 defer if (cleanup_dir_parent) |*d| d.close(io);
12701279
12711280 var cleanup_dir = true;
1272 defer if (cleanup_dir) dir.close();
1281 defer if (cleanup_dir) dir.close(io);
12731282
12741283 // Valid use of max_path_bytes because dir_name_buf will only
12751284 // ever store a single path component that was returned from the
......@@ -1315,7 +1324,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
13151324 error.Canceled,
13161325 => |e| return e,
13171326 };
1318 if (cleanup_dir_parent) |*d| d.close();
1327 if (cleanup_dir_parent) |*d| d.close(io);
13191328 cleanup_dir_parent = dir;
13201329 dir = new_dir;
13211330 const result = dir_name_buf[0..entry.name.len];
......@@ -1354,7 +1363,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
13541363 }
13551364 // Reached the end of the directory entries, which means we successfully deleted all of them.
13561365 // Now to remove the directory itself.
1357 dir.close();
1366 dir.close(io);
13581367 cleanup_dir = false;
13591368
13601369 if (cleanup_dir_parent) |d| {
lib/std/Io/Writer.zig+3-3
......@@ -2835,7 +2835,7 @@ test "discarding sendFile" {
28352835 defer tmp_dir.cleanup();
28362836
28372837 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2838 defer file.close();
2838 defer file.close(io);
28392839 var r_buffer: [256]u8 = undefined;
28402840 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
28412841 try file_writer.interface.writeByte('h');
......@@ -2857,7 +2857,7 @@ test "allocating sendFile" {
28572857 defer tmp_dir.cleanup();
28582858
28592859 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2860 defer file.close();
2860 defer file.close(io);
28612861 var r_buffer: [2]u8 = undefined;
28622862 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
28632863 try file_writer.interface.writeAll("abcd");
......@@ -2881,7 +2881,7 @@ test sendFileReading {
28812881 defer tmp_dir.cleanup();
28822882
28832883 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2884 defer file.close();
2884 defer file.close(io);
28852885 var r_buffer: [2]u8 = undefined;
28862886 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
28872887 try file_writer.interface.writeAll("abcd");
lib/std/Io/net/test.zig+7-3
......@@ -232,8 +232,10 @@ test "listen on an in use port" {
232232fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void {
233233 if (builtin.os.tag == .wasi) return error.SkipZigTest;
234234
235 const io = testing.io;
236
235237 const connection = try net.tcpConnectToHost(allocator, name, port);
236 defer connection.close();
238 defer connection.close(io);
237239
238240 var buf: [100]u8 = undefined;
239241 const len = try connection.read(&buf);
......@@ -244,8 +246,10 @@ fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyer
244246fn testClient(addr: net.IpAddress) anyerror!void {
245247 if (builtin.os.tag == .wasi) return error.SkipZigTest;
246248
249 const io = testing.io;
250
247251 const socket_file = try net.tcpConnectToAddress(addr);
248 defer socket_file.close();
252 defer socket_file.close(io);
249253
250254 var buf: [100]u8 = undefined;
251255 const len = try socket_file.read(&buf);
......@@ -330,7 +334,7 @@ test "non-blocking tcp server" {
330334 try testing.expectError(error.WouldBlock, accept_err);
331335
332336 const socket_file = try net.tcpConnectToAddress(server.socket.address);
333 defer socket_file.close();
337 defer socket_file.close(io);
334338
335339 var stream = try server.accept(io);
336340 defer stream.close(io);
lib/std/Io/test.zig+11-5
......@@ -28,7 +28,7 @@ test "write a file, read it, then delete it" {
2828 const tmp_file_name = "temp_test_file.txt";
2929 {
3030 var file = try tmp.dir.createFile(tmp_file_name, .{});
31 defer file.close();
31 defer file.close(io);
3232
3333 var file_writer = file.writer(&.{});
3434 const st = &file_writer.interface;
......@@ -45,7 +45,7 @@ test "write a file, read it, then delete it" {
4545
4646 {
4747 var file = try tmp.dir.openFile(tmp_file_name, .{});
48 defer file.close();
48 defer file.close(io);
4949
5050 const file_size = try file.getEndPos();
5151 const expected_file_size: u64 = "begin".len + data.len + "end".len;
......@@ -67,9 +67,11 @@ test "File seek ops" {
6767 var tmp = tmpDir(.{});
6868 defer tmp.cleanup();
6969
70 const io = testing.io;
71
7072 const tmp_file_name = "temp_test_file.txt";
7173 var file = try tmp.dir.createFile(tmp_file_name, .{});
72 defer file.close();
74 defer file.close(io);
7375
7476 try file.writeAll(&([_]u8{0x55} ** 8192));
7577
......@@ -88,12 +90,14 @@ test "File seek ops" {
8890}
8991
9092test "setEndPos" {
93 const io = testing.io;
94
9195 var tmp = tmpDir(.{});
9296 defer tmp.cleanup();
9397
9498 const tmp_file_name = "temp_test_file.txt";
9599 var file = try tmp.dir.createFile(tmp_file_name, .{});
96 defer file.close();
100 defer file.close(io);
97101
98102 // Verify that the file size changes and the file offset is not moved
99103 try expect((try file.getEndPos()) == 0);
......@@ -111,12 +115,14 @@ test "setEndPos" {
111115}
112116
113117test "updateTimes" {
118 const io = testing.io;
119
114120 var tmp = tmpDir(.{});
115121 defer tmp.cleanup();
116122
117123 const tmp_file_name = "just_a_temporary_file.txt";
118124 var file = try tmp.dir.createFile(tmp_file_name, .{ .read = true });
119 defer file.close();
125 defer file.close(io);
120126
121127 const stat_old = try file.stat();
122128 // Set atime and mtime to 5s before
lib/std/Thread.zig+4-3
......@@ -7,6 +7,7 @@ const target = builtin.target;
77const native_os = builtin.os.tag;
88
99const std = @import("std.zig");
10const Io = std.Io;
1011const math = std.math;
1112const assert = std.debug.assert;
1213const posix = std.posix;
......@@ -176,7 +177,7 @@ pub const SetNameError = error{
176177 InvalidWtf8,
177178} || posix.PrctlError || posix.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;
178179
179pub fn setName(self: Thread, name: []const u8) SetNameError!void {
180pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {
180181 if (name.len > max_name_len) return error.NameTooLong;
181182
182183 const name_with_terminator = blk: {
......@@ -208,7 +209,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
208209 const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
209210
210211 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });
211 defer file.close();
212 defer file.close(io);
212213
213214 try file.writeAll(name);
214215 return;
......@@ -325,7 +326,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
325326 const io = threaded.ioBasic();
326327
327328 const file = try std.fs.cwd().openFile(path, .{});
328 defer file.close();
329 defer file.close(io);
329330
330331 var file_reader = file.readerStreaming(io, &.{});
331332 const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) {
lib/std/crypto/Certificate/Bundle.zig+3-3
......@@ -181,7 +181,7 @@ pub fn addCertsFromDirPath(
181181 sub_dir_path: []const u8,
182182) AddCertsFromDirPathError!void {
183183 var iterable_dir = try dir.openDir(sub_dir_path, .{ .iterate = true });
184 defer iterable_dir.close();
184 defer iterable_dir.close(io);
185185 return addCertsFromDir(cb, gpa, io, iterable_dir);
186186}
187187
......@@ -194,7 +194,7 @@ pub fn addCertsFromDirPathAbsolute(
194194) AddCertsFromDirPathError!void {
195195 assert(fs.path.isAbsolute(abs_dir_path));
196196 var iterable_dir = try fs.openDirAbsolute(abs_dir_path, .{ .iterate = true });
197 defer iterable_dir.close();
197 defer iterable_dir.close(io);
198198 return addCertsFromDir(cb, gpa, io, now, iterable_dir);
199199}
200200
......@@ -222,7 +222,7 @@ pub fn addCertsFromFilePathAbsolute(
222222 abs_file_path: []const u8,
223223) AddCertsFromFilePathError!void {
224224 var file = try fs.openFileAbsolute(abs_file_path, .{});
225 defer file.close();
225 defer file.close(io);
226226 var file_reader = file.reader(io, &.{});
227227 return addCertsFromFile(cb, gpa, &file_reader, now.toSeconds());
228228}
lib/std/crypto/codecs/asn1/test.zig+1-1
......@@ -75,6 +75,6 @@ test AllTypes {
7575 // Use this to update test file.
7676 // const dir = try std.fs.cwd().openDir("lib/std/crypto/asn1", .{});
7777 // var file = try dir.createFile(path, .{});
78 // defer file.close();
78 // defer file.close(io);
7979 // try file.writeAll(buf);
8080}
lib/std/debug.zig+4-4
......@@ -1298,7 +1298,7 @@ test printLineFromFile {
12981298 }
12991299 {
13001300 const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});
1301 defer file.close();
1301 defer file.close(io);
13021302 const path = try fs.path.join(gpa, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });
13031303 defer gpa.free(path);
13041304
......@@ -1317,7 +1317,7 @@ test printLineFromFile {
13171317 }
13181318 {
13191319 const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});
1320 defer file.close();
1320 defer file.close(io);
13211321 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
13221322 defer gpa.free(path);
13231323
......@@ -1331,7 +1331,7 @@ test printLineFromFile {
13311331 }
13321332 {
13331333 const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});
1334 defer file.close();
1334 defer file.close(io);
13351335 const path = try fs.path.join(gpa, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
13361336 defer gpa.free(path);
13371337
......@@ -1357,7 +1357,7 @@ test printLineFromFile {
13571357 }
13581358 {
13591359 const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});
1360 defer file.close();
1360 defer file.close(io);
13611361 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_of_newlines.zig" });
13621362 defer gpa.free(path);
13631363
lib/std/debug/ElfFile.zig+17-9
......@@ -1,5 +1,13 @@
11//! A helper type for loading an ELF file and collecting its DWARF debug information, unwind
22//! information, and symbol table.
3const ElfFile = @This();
4
5const std = @import("std");
6const Io = std.Io;
7const Endian = std.builtin.Endian;
8const Dwarf = std.debug.Dwarf;
9const Allocator = std.mem.Allocator;
10const elf = std.elf;
311
412is_64: bool,
513endian: Endian,
......@@ -358,10 +366,17 @@ const Section = struct {
358366 const Array = std.enums.EnumArray(Section.Id, ?Section);
359367};
360368
361fn loadSeparateDebugFile(arena: Allocator, main_loaded: *LoadInnerResult, opt_crc: ?u32, comptime fmt: []const u8, args: anytype) Allocator.Error!?[]align(std.heap.page_size_min) const u8 {
369fn loadSeparateDebugFile(
370 arena: Allocator,
371 io: Io,
372 main_loaded: *LoadInnerResult,
373 opt_crc: ?u32,
374 comptime fmt: []const u8,
375 args: anytype,
376) Allocator.Error!?[]align(std.heap.page_size_min) const u8 {
362377 const path = try std.fmt.allocPrint(arena, fmt, args);
363378 const elf_file = std.fs.cwd().openFile(path, .{}) catch return null;
364 defer elf_file.close();
379 defer elf_file.close(io);
365380
366381 const result = loadInner(arena, elf_file, opt_crc) catch |err| switch (err) {
367382 error.OutOfMemory => |e| return e,
......@@ -529,10 +544,3 @@ fn loadInner(
529544 .mapped_mem = mapped_mem,
530545 };
531546}
532
533const std = @import("std");
534const Endian = std.builtin.Endian;
535const Dwarf = std.debug.Dwarf;
536const ElfFile = @This();
537const Allocator = std.mem.Allocator;
538const elf = std.elf;
lib/std/debug/Info.zig+15-6
......@@ -5,19 +5,18 @@
55//! Unlike `std.debug.SelfInfo`, this API does not assume the debug information
66//! in question happens to match the host CPU architecture, OS, or other target
77//! properties.
8const Info = @This();
89
910const std = @import("../std.zig");
11const Io = std.Io;
1012const Allocator = std.mem.Allocator;
1113const Path = std.Build.Cache.Path;
1214const assert = std.debug.assert;
1315const Coverage = std.debug.Coverage;
1416const SourceLocation = std.debug.Coverage.SourceLocation;
15
1617const ElfFile = std.debug.ElfFile;
1718const MachOFile = std.debug.MachOFile;
1819
19const Info = @This();
20
2120impl: union(enum) {
2221 elf: ElfFile,
2322 macho: MachOFile,
......@@ -25,13 +24,23 @@ impl: union(enum) {
2524/// Externally managed, outlives this `Info` instance.
2625coverage: *Coverage,
2726
28pub const LoadError = std.fs.File.OpenError || ElfFile.LoadError || MachOFile.Error || std.debug.Dwarf.ScanError || error{ MissingDebugInfo, UnsupportedDebugInfo };
27pub const LoadError = error{
28 MissingDebugInfo,
29 UnsupportedDebugInfo,
30} || std.fs.File.OpenError || ElfFile.LoadError || MachOFile.Error || std.debug.Dwarf.ScanError;
2931
30pub fn load(gpa: Allocator, path: Path, coverage: *Coverage, format: std.Target.ObjectFormat, arch: std.Target.Cpu.Arch) LoadError!Info {
32pub fn load(
33 gpa: Allocator,
34 io: Io,
35 path: Path,
36 coverage: *Coverage,
37 format: std.Target.ObjectFormat,
38 arch: std.Target.Cpu.Arch,
39) LoadError!Info {
3140 switch (format) {
3241 .elf => {
3342 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
34 defer file.close();
43 defer file.close(io);
3544
3645 var elf_file: ElfFile = try .load(gpa, file, null, &.none);
3746 errdefer elf_file.deinit(gpa);
lib/std/debug/MachOFile.zig+9-9
......@@ -27,13 +27,13 @@ pub fn deinit(mf: *MachOFile, gpa: Allocator) void {
2727 posix.munmap(mf.mapped_memory);
2828}
2929
30pub fn load(gpa: Allocator, path: []const u8, arch: std.Target.Cpu.Arch) Error!MachOFile {
30pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) Error!MachOFile {
3131 switch (arch) {
3232 .x86_64, .aarch64 => {},
3333 else => unreachable,
3434 }
3535
36 const all_mapped_memory = try mapDebugInfoFile(path);
36 const all_mapped_memory = try mapDebugInfoFile(io, path);
3737 errdefer posix.munmap(all_mapped_memory);
3838
3939 // In most cases, the file we just mapped is a Mach-O binary. However, it could be a "universal
......@@ -239,7 +239,7 @@ pub fn load(gpa: Allocator, path: []const u8, arch: std.Target.Cpu.Arch) Error!M
239239 .text_vmaddr = text_vmaddr,
240240 };
241241}
242pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, vaddr: u64) !struct { *Dwarf, u64 } {
242pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, io: Io, vaddr: u64) !struct { *Dwarf, u64 } {
243243 const symbol = Symbol.find(mf.symbols, vaddr) orelse return error.MissingDebugInfo;
244244
245245 if (symbol.ofile == Symbol.unknown_ofile) return error.MissingDebugInfo;
......@@ -254,7 +254,7 @@ pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, vaddr: u64) !struct {
254254 const gop = try mf.ofiles.getOrPut(gpa, symbol.ofile);
255255 if (!gop.found_existing) {
256256 const name = mem.sliceTo(mf.strings[symbol.ofile..], 0);
257 gop.value_ptr.* = loadOFile(gpa, name);
257 gop.value_ptr.* = loadOFile(gpa, io, name);
258258 }
259259 const of = &(gop.value_ptr.* catch |err| return err);
260260
......@@ -356,7 +356,7 @@ test {
356356 _ = Symbol;
357357}
358358
359fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
359fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile {
360360 const all_mapped_memory, const mapped_ofile = map: {
361361 const open_paren = paren: {
362362 if (std.mem.endsWith(u8, o_file_name, ")")) {
......@@ -365,7 +365,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
365365 }
366366 }
367367 // Not an archive, just a normal path to a .o file
368 const m = try mapDebugInfoFile(o_file_name);
368 const m = try mapDebugInfoFile(io, o_file_name);
369369 break :map .{ m, m };
370370 };
371371
......@@ -373,7 +373,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
373373
374374 const archive_path = o_file_name[0..open_paren];
375375 const target_name_in_archive = o_file_name[open_paren + 1 .. o_file_name.len - 1];
376 const mapped_archive = try mapDebugInfoFile(archive_path);
376 const mapped_archive = try mapDebugInfoFile(io, archive_path);
377377 errdefer posix.munmap(mapped_archive);
378378
379379 var ar_reader: Io.Reader = .fixed(mapped_archive);
......@@ -511,12 +511,12 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
511511}
512512
513513/// Uses `mmap` to map the file at `path` into memory.
514fn mapDebugInfoFile(path: []const u8) ![]align(std.heap.page_size_min) const u8 {
514fn mapDebugInfoFile(io: Io, path: []const u8) ![]align(std.heap.page_size_min) const u8 {
515515 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
516516 error.FileNotFound => return error.MissingDebugInfo,
517517 else => return error.ReadFailed,
518518 };
519 defer file.close();
519 defer file.close(io);
520520
521521 const file_len = std.math.cast(
522522 usize,
lib/std/debug/SelfInfo/Elf.zig+5-5
......@@ -319,14 +319,14 @@ const Module = struct {
319319 }
320320
321321 /// Assumes we already hold an exclusive lock.
322 fn getLoadedElf(mod: *Module, gpa: Allocator) Error!*LoadedElf {
323 if (mod.loaded_elf == null) mod.loaded_elf = loadElf(mod, gpa);
322 fn getLoadedElf(mod: *Module, gpa: Allocator, io: Io) Error!*LoadedElf {
323 if (mod.loaded_elf == null) mod.loaded_elf = loadElf(mod, gpa, io);
324324 return if (mod.loaded_elf.?) |*elf| elf else |err| err;
325325 }
326 fn loadElf(mod: *Module, gpa: Allocator) Error!LoadedElf {
326 fn loadElf(mod: *Module, gpa: Allocator, io: Io) Error!LoadedElf {
327327 const load_result = if (mod.name.len > 0) res: {
328328 var file = std.fs.cwd().openFile(mod.name, .{}) catch return error.MissingDebugInfo;
329 defer file.close();
329 defer file.close(io);
330330 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(mod.name));
331331 } else res: {
332332 const path = std.fs.selfExePathAlloc(gpa) catch |err| switch (err) {
......@@ -335,7 +335,7 @@ const Module = struct {
335335 };
336336 defer gpa.free(path);
337337 var file = std.fs.cwd().openFile(path, .{}) catch return error.MissingDebugInfo;
338 defer file.close();
338 defer file.close(io);
339339 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(path));
340340 };
341341
lib/std/debug/SelfInfo/MachO.zig+2-2
......@@ -615,12 +615,12 @@ test {
615615}
616616
617617/// Uses `mmap` to map the file at `path` into memory.
618fn mapDebugInfoFile(path: []const u8) ![]align(std.heap.page_size_min) const u8 {
618fn mapDebugInfoFile(io: Io, path: []const u8) ![]align(std.heap.page_size_min) const u8 {
619619 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
620620 error.FileNotFound => return error.MissingDebugInfo,
621621 else => return error.ReadFailed,
622622 };
623 defer file.close();
623 defer file.close(io);
624624
625625 const file_end_pos = file.getEndPos() catch |err| switch (err) {
626626 error.Unexpected => |e| return e,
lib/std/debug/SelfInfo/Windows.zig+3-3
......@@ -207,11 +207,11 @@ const Module = struct {
207207 file: fs.File,
208208 section_handle: windows.HANDLE,
209209 section_view: []const u8,
210 fn deinit(mf: *const MappedFile) void {
210 fn deinit(mf: *const MappedFile, io: Io) void {
211211 const process_handle = windows.GetCurrentProcess();
212212 assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mf.section_view.ptr)) == .SUCCESS);
213213 windows.CloseHandle(mf.section_handle);
214 mf.file.close();
214 mf.file.close(io);
215215 }
216216 };
217217
......@@ -447,7 +447,7 @@ const Module = struct {
447447 error.FileNotFound, error.IsDir => break :pdb null,
448448 else => return error.ReadFailed,
449449 };
450 errdefer pdb_file.close();
450 errdefer pdb_file.close(io);
451451
452452 const pdb_reader = try arena.create(Io.File.Reader);
453453 pdb_reader.* = pdb_file.reader(io, try arena.alloc(u8, 4096));
lib/std/dynamic_library.zig+18-16
......@@ -1,10 +1,12 @@
1const std = @import("std.zig");
21const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("std.zig");
5const Io = std.Io;
36const mem = std.mem;
47const testing = std.testing;
58const elf = std.elf;
69const windows = std.os.windows;
7const native_os = builtin.os.tag;
810const posix = std.posix;
911
1012/// Cross-platform dynamic library loading and symbol lookup.
......@@ -38,8 +40,8 @@ pub const DynLib = struct {
3840 }
3941
4042 /// Trusts the file.
41 pub fn close(self: *DynLib) void {
42 return self.inner.close();
43 pub fn close(self: *DynLib, io: Io) void {
44 return self.inner.close(io);
4345 }
4446
4547 pub fn lookup(self: *DynLib, comptime T: type, name: [:0]const u8) ?T {
......@@ -155,23 +157,23 @@ pub const ElfDynLib = struct {
155157 dt_gnu_hash: *elf.gnu_hash.Header,
156158 };
157159
158 fn openPath(path: []const u8) !std.fs.Dir {
160 fn openPath(path: []const u8, io: Io) !std.fs.Dir {
159161 if (path.len == 0) return error.NotDir;
160162 var parts = std.mem.tokenizeScalar(u8, path, '/');
161163 var parent = if (path[0] == '/') try std.fs.cwd().openDir("/", .{}) else std.fs.cwd();
162164 while (parts.next()) |part| {
163165 const child = try parent.openDir(part, .{});
164 parent.close();
166 parent.close(io);
165167 parent = child;
166168 }
167169 return parent;
168170 }
169171
170 fn resolveFromSearchPath(search_path: []const u8, file_name: []const u8, delim: u8) ?posix.fd_t {
172 fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?posix.fd_t {
171173 var paths = std.mem.tokenizeScalar(u8, search_path, delim);
172174 while (paths.next()) |p| {
173175 var dir = openPath(p) catch continue;
174 defer dir.close();
176 defer dir.close(io);
175177 const fd = posix.openat(dir.fd, file_name, .{
176178 .ACCMODE = .RDONLY,
177179 .CLOEXEC = true,
......@@ -181,9 +183,9 @@ pub const ElfDynLib = struct {
181183 return null;
182184 }
183185
184 fn resolveFromParent(dir_path: []const u8, file_name: []const u8) ?posix.fd_t {
186 fn resolveFromParent(io: Io, dir_path: []const u8, file_name: []const u8) ?posix.fd_t {
185187 var dir = std.fs.cwd().openDir(dir_path, .{}) catch return null;
186 defer dir.close();
188 defer dir.close(io);
187189 return posix.openat(dir.fd, file_name, .{
188190 .ACCMODE = .RDONLY,
189191 .CLOEXEC = true,
......@@ -195,7 +197,7 @@ pub const ElfDynLib = struct {
195197 // - DT_RPATH of the calling binary is not used as a search path
196198 // - DT_RUNPATH of the calling binary is not used as a search path
197199 // - /etc/ld.so.cache is not read
198 fn resolveFromName(path_or_name: []const u8) !posix.fd_t {
200 fn resolveFromName(io: Io, path_or_name: []const u8) !posix.fd_t {
199201 // If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname
200202 if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {
201203 return posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
......@@ -206,21 +208,21 @@ pub const ElfDynLib = struct {
206208 std.os.linux.getegid() == std.os.linux.getgid())
207209 {
208210 if (posix.getenvZ("LD_LIBRARY_PATH")) |ld_library_path| {
209 if (resolveFromSearchPath(ld_library_path, path_or_name, ':')) |fd| {
211 if (resolveFromSearchPath(io, ld_library_path, path_or_name, ':')) |fd| {
210212 return fd;
211213 }
212214 }
213215 }
214216
215217 // Lastly the directories /lib and /usr/lib are searched (in this exact order)
216 if (resolveFromParent("/lib", path_or_name)) |fd| return fd;
217 if (resolveFromParent("/usr/lib", path_or_name)) |fd| return fd;
218 if (resolveFromParent(io, "/lib", path_or_name)) |fd| return fd;
219 if (resolveFromParent(io, "/usr/lib", path_or_name)) |fd| return fd;
218220 return error.FileNotFound;
219221 }
220222
221223 /// Trusts the file. Malicious file will be able to execute arbitrary code.
222 pub fn open(path: []const u8) Error!ElfDynLib {
223 const fd = try resolveFromName(path);
224 pub fn open(io: Io, path: []const u8) Error!ElfDynLib {
225 const fd = try resolveFromName(io, path);
224226 defer posix.close(fd);
225227
226228 const file: std.fs.File = .{ .handle = fd };
lib/std/fs.zig+2-2
......@@ -227,7 +227,7 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void {
227227/// On Windows, `absolute_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
228228/// On WASI, `absolute_path` should be encoded as valid UTF-8.
229229/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
230pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
230pub fn deleteTreeAbsolute(io: Io, absolute_path: []const u8) !void {
231231 assert(path.isAbsolute(absolute_path));
232232 const dirname = path.dirname(absolute_path) orelse return error{
233233 /// Attempt to remove the root file system path.
......@@ -236,7 +236,7 @@ pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
236236 }.CannotDeleteRootDirectory;
237237
238238 var dir = try cwd().openDir(dirname, .{});
239 defer dir.close();
239 defer dir.close(io);
240240
241241 return dir.deleteTree(path.basename(absolute_path));
242242}
lib/std/fs/test.zig+171-99
......@@ -178,6 +178,8 @@ fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlag
178178}
179179
180180test "Dir.readLink" {
181 const io = testing.io;
182
181183 try testWithAllSupportedPathTypes(struct {
182184 fn impl(ctx: *TestContext) !void {
183185 // Create some targets
......@@ -208,7 +210,7 @@ test "Dir.readLink" {
208210 const parent_file = ".." ++ fs.path.sep_str ++ "target.txt";
209211 const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file);
210212 var subdir = try ctx.dir.makeOpenPath("subdir", .{});
211 defer subdir.close();
213 defer subdir.close(io);
212214 try setupSymlink(subdir, canonical_parent_file, "relative-link.txt", .{});
213215 try testReadLink(subdir, canonical_parent_file, "relative-link.txt");
214216 if (builtin.os.tag == .windows) {
......@@ -268,6 +270,8 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
268270}
269271
270272test "File.stat on a File that is a symlink returns Kind.sym_link" {
273 const io = testing.io;
274
271275 // This test requires getting a file descriptor of a symlink which
272276 // is not possible on all targets
273277 switch (builtin.target.os.tag) {
......@@ -302,7 +306,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
302306 .SecurityDescriptor = null,
303307 .SecurityQualityOfService = null,
304308 };
305 var io: windows.IO_STATUS_BLOCK = undefined;
309 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
306310 const rc = windows.ntdll.NtCreateFile(
307311 &handle,
308312 .{
......@@ -317,7 +321,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
317321 },
318322 },
319323 &attr,
320 &io,
324 &io_status_block,
321325 null,
322326 .{ .NORMAL = true },
323327 .VALID_FLAGS,
......@@ -352,7 +356,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
352356 },
353357 else => unreachable,
354358 };
355 defer symlink.close();
359 defer symlink.close(io);
356360
357361 const stat = try symlink.stat();
358362 try testing.expectEqual(File.Kind.sym_link, stat.kind);
......@@ -361,6 +365,8 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
361365}
362366
363367test "openDir" {
368 const io = testing.io;
369
364370 try testWithAllSupportedPathTypes(struct {
365371 fn impl(ctx: *TestContext) !void {
366372 const allocator = ctx.arena.allocator();
......@@ -370,7 +376,7 @@ test "openDir" {
370376 for ([_][]const u8{ "", ".", ".." }) |sub_path| {
371377 const dir_path = try fs.path.join(allocator, &.{ subdir_path, sub_path });
372378 var dir = try ctx.dir.openDir(dir_path, .{});
373 defer dir.close();
379 defer dir.close(io);
374380 }
375381 }
376382 }.impl);
......@@ -393,6 +399,8 @@ test "openDirAbsolute" {
393399 if (native_os == .wasi) return error.SkipZigTest;
394400 if (native_os == .openbsd) return error.SkipZigTest;
395401
402 const io = testing.io;
403
396404 var tmp = tmpDir(.{});
397405 defer tmp.cleanup();
398406
......@@ -404,7 +412,7 @@ test "openDirAbsolute" {
404412
405413 // Can open sub_path
406414 var tmp_sub = try fs.openDirAbsolute(sub_path, .{});
407 defer tmp_sub.close();
415 defer tmp_sub.close(io);
408416
409417 const sub_ino = (try tmp_sub.stat()).inode;
410418
......@@ -414,7 +422,7 @@ test "openDirAbsolute" {
414422 defer testing.allocator.free(dir_path);
415423
416424 var dir = try fs.openDirAbsolute(dir_path, .{});
417 defer dir.close();
425 defer dir.close(io);
418426
419427 const ino = (try dir.stat()).inode;
420428 try testing.expectEqual(tmp_ino, ino);
......@@ -426,7 +434,7 @@ test "openDirAbsolute" {
426434 defer testing.allocator.free(dir_path);
427435
428436 var dir = try fs.openDirAbsolute(dir_path, .{});
429 defer dir.close();
437 defer dir.close(io);
430438
431439 const ino = (try dir.stat()).inode;
432440 try testing.expectEqual(sub_ino, ino);
......@@ -438,7 +446,7 @@ test "openDirAbsolute" {
438446 defer testing.allocator.free(dir_path);
439447
440448 var dir = try fs.openDirAbsolute(dir_path, .{});
441 defer dir.close();
449 defer dir.close(io);
442450
443451 const ino = (try dir.stat()).inode;
444452 try testing.expectEqual(tmp_ino, ino);
......@@ -446,13 +454,15 @@ test "openDirAbsolute" {
446454}
447455
448456test "openDir cwd parent '..'" {
457 const io = testing.io;
458
449459 var dir = fs.cwd().openDir("..", .{}) catch |err| {
450460 if (native_os == .wasi and err == error.PermissionDenied) {
451461 return; // This is okay. WASI disallows escaping from the fs sandbox
452462 }
453463 return err;
454464 };
455 defer dir.close();
465 defer dir.close(io);
456466}
457467
458468test "openDir non-cwd parent '..'" {
......@@ -461,14 +471,16 @@ test "openDir non-cwd parent '..'" {
461471 else => {},
462472 }
463473
474 const io = testing.io;
475
464476 var tmp = tmpDir(.{});
465477 defer tmp.cleanup();
466478
467479 var subdir = try tmp.dir.makeOpenPath("subdir", .{});
468 defer subdir.close();
480 defer subdir.close(io);
469481
470482 var dir = try subdir.openDir("..", .{});
471 defer dir.close();
483 defer dir.close(io);
472484
473485 const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
474486 defer testing.allocator.free(expected_path);
......@@ -516,12 +528,14 @@ test "readLinkAbsolute" {
516528}
517529
518530test "Dir.Iterator" {
531 const io = testing.io;
532
519533 var tmp_dir = tmpDir(.{ .iterate = true });
520534 defer tmp_dir.cleanup();
521535
522536 // First, create a couple of entries to iterate over.
523537 const file = try tmp_dir.dir.createFile("some_file", .{});
524 file.close();
538 file.close(io);
525539
526540 try tmp_dir.dir.makeDir("some_dir");
527541
......@@ -546,6 +560,8 @@ test "Dir.Iterator" {
546560}
547561
548562test "Dir.Iterator many entries" {
563 const io = testing.io;
564
549565 var tmp_dir = tmpDir(.{ .iterate = true });
550566 defer tmp_dir.cleanup();
551567
......@@ -555,7 +571,7 @@ test "Dir.Iterator many entries" {
555571 while (i < num) : (i += 1) {
556572 const name = try std.fmt.bufPrint(&buf, "{}", .{i});
557573 const file = try tmp_dir.dir.createFile(name, .{});
558 file.close();
574 file.close(io);
559575 }
560576
561577 var arena = ArenaAllocator.init(testing.allocator);
......@@ -581,12 +597,14 @@ test "Dir.Iterator many entries" {
581597}
582598
583599test "Dir.Iterator twice" {
600 const io = testing.io;
601
584602 var tmp_dir = tmpDir(.{ .iterate = true });
585603 defer tmp_dir.cleanup();
586604
587605 // First, create a couple of entries to iterate over.
588606 const file = try tmp_dir.dir.createFile("some_file", .{});
589 file.close();
607 file.close(io);
590608
591609 try tmp_dir.dir.makeDir("some_dir");
592610
......@@ -614,12 +632,14 @@ test "Dir.Iterator twice" {
614632}
615633
616634test "Dir.Iterator reset" {
635 const io = testing.io;
636
617637 var tmp_dir = tmpDir(.{ .iterate = true });
618638 defer tmp_dir.cleanup();
619639
620640 // First, create a couple of entries to iterate over.
621641 const file = try tmp_dir.dir.createFile("some_file", .{});
622 file.close();
642 file.close(io);
623643
624644 try tmp_dir.dir.makeDir("some_dir");
625645
......@@ -650,12 +670,14 @@ test "Dir.Iterator reset" {
650670}
651671
652672test "Dir.Iterator but dir is deleted during iteration" {
673 const io = testing.io;
674
653675 var tmp = std.testing.tmpDir(.{});
654676 defer tmp.cleanup();
655677
656678 // Create directory and setup an iterator for it
657679 var subdir = try tmp.dir.makeOpenPath("subdir", .{ .iterate = true });
658 defer subdir.close();
680 defer subdir.close(io);
659681
660682 var iterator = subdir.iterate();
661683
......@@ -742,11 +764,13 @@ test "Dir.realpath smoke test" {
742764}
743765
744766test "readFileAlloc" {
767 const io = testing.io;
768
745769 var tmp_dir = tmpDir(.{});
746770 defer tmp_dir.cleanup();
747771
748772 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
749 defer file.close();
773 defer file.close(io);
750774
751775 const buf1 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(1024));
752776 defer testing.allocator.free(buf1);
......@@ -815,10 +839,12 @@ test "statFile on dangling symlink" {
815839test "directory operations on files" {
816840 try testWithAllSupportedPathTypes(struct {
817841 fn impl(ctx: *TestContext) !void {
842 const io = ctx.io;
843
818844 const test_file_name = try ctx.transformPath("test_file");
819845
820846 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });
821 file.close();
847 file.close(io);
822848
823849 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(test_file_name));
824850 try testing.expectError(error.NotDir, ctx.dir.openDir(test_file_name, .{}));
......@@ -833,7 +859,7 @@ test "directory operations on files" {
833859 file = try ctx.dir.openFile(test_file_name, .{});
834860 const stat = try file.stat();
835861 try testing.expectEqual(File.Kind.file, stat.kind);
836 file.close();
862 file.close(io);
837863 }
838864 }.impl);
839865}
......@@ -842,6 +868,8 @@ test "file operations on directories" {
842868 // TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
843869 if (native_os == .freebsd) return error.SkipZigTest;
844870
871 const io = testing.io;
872
845873 try testWithAllSupportedPathTypes(struct {
846874 fn impl(ctx: *TestContext) !void {
847875 const test_dir_name = try ctx.transformPath("test_dir");
......@@ -869,7 +897,7 @@ test "file operations on directories" {
869897 if (native_os == .wasi and builtin.link_libc) {
870898 // wasmtime unexpectedly succeeds here, see https://github.com/ziglang/zig/issues/20747
871899 const handle = try ctx.dir.openFile(test_dir_name, .{ .mode = .read_write });
872 handle.close();
900 handle.close(io);
873901 } else {
874902 // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.
875903 // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
......@@ -883,21 +911,23 @@ test "file operations on directories" {
883911
884912 // ensure the directory still exists as a sanity check
885913 var dir = try ctx.dir.openDir(test_dir_name, .{});
886 dir.close();
914 dir.close(io);
887915 }
888916 }.impl);
889917}
890918
891919test "makeOpenPath parent dirs do not exist" {
920 const io = testing.io;
921
892922 var tmp_dir = tmpDir(.{});
893923 defer tmp_dir.cleanup();
894924
895925 var dir = try tmp_dir.dir.makeOpenPath("root_dir/parent_dir/some_dir", .{});
896 dir.close();
926 dir.close(io);
897927
898928 // double check that the full directory structure was created
899929 var dir_verification = try tmp_dir.dir.openDir("root_dir/parent_dir/some_dir", .{});
900 dir_verification.close();
930 dir_verification.close(io);
901931}
902932
903933test "deleteDir" {
......@@ -924,6 +954,7 @@ test "deleteDir" {
924954test "Dir.rename files" {
925955 try testWithAllSupportedPathTypes(struct {
926956 fn impl(ctx: *TestContext) !void {
957 const io = ctx.io;
927958 // Rename on Windows can hit intermittent AccessDenied errors
928959 // when certain conditions are true about the host system.
929960 // For now, skip this test when the path type is UNC to avoid them.
......@@ -939,13 +970,13 @@ test "Dir.rename files" {
939970 const test_file_name = try ctx.transformPath("test_file");
940971 const renamed_test_file_name = try ctx.transformPath("test_file_renamed");
941972 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });
942 file.close();
973 file.close(io);
943974 try ctx.dir.rename(test_file_name, renamed_test_file_name);
944975
945976 // Ensure the file was renamed
946977 try testing.expectError(error.FileNotFound, ctx.dir.openFile(test_file_name, .{}));
947978 file = try ctx.dir.openFile(renamed_test_file_name, .{});
948 file.close();
979 file.close(io);
949980
950981 // Rename to self succeeds
951982 try ctx.dir.rename(renamed_test_file_name, renamed_test_file_name);
......@@ -953,12 +984,12 @@ test "Dir.rename files" {
953984 // Rename to existing file succeeds
954985 const existing_file_path = try ctx.transformPath("existing_file");
955986 var existing_file = try ctx.dir.createFile(existing_file_path, .{ .read = true });
956 existing_file.close();
987 existing_file.close(io);
957988 try ctx.dir.rename(renamed_test_file_name, existing_file_path);
958989
959990 try testing.expectError(error.FileNotFound, ctx.dir.openFile(renamed_test_file_name, .{}));
960991 file = try ctx.dir.openFile(existing_file_path, .{});
961 file.close();
992 file.close(io);
962993 }
963994 }.impl);
964995}
......@@ -966,6 +997,8 @@ test "Dir.rename files" {
966997test "Dir.rename directories" {
967998 try testWithAllSupportedPathTypes(struct {
968999 fn impl(ctx: *TestContext) !void {
1000 const io = ctx.io;
1001
9691002 // Rename on Windows can hit intermittent AccessDenied errors
9701003 // when certain conditions are true about the host system.
9711004 // For now, skip this test when the path type is UNC to avoid them.
......@@ -985,8 +1018,8 @@ test "Dir.rename directories" {
9851018
9861019 // Put a file in the directory
9871020 var file = try dir.createFile("test_file", .{ .read = true });
988 file.close();
989 dir.close();
1021 file.close(io);
1022 dir.close(io);
9901023
9911024 const test_dir_renamed_again_path = try ctx.transformPath("test_dir_renamed_again");
9921025 try ctx.dir.rename(test_dir_renamed_path, test_dir_renamed_again_path);
......@@ -995,8 +1028,8 @@ test "Dir.rename directories" {
9951028 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_renamed_path, .{}));
9961029 dir = try ctx.dir.openDir(test_dir_renamed_again_path, .{});
9971030 file = try dir.openFile("test_file", .{});
998 file.close();
999 dir.close();
1031 file.close(io);
1032 dir.close(io);
10001033 }
10011034 }.impl);
10021035}
......@@ -1007,6 +1040,8 @@ test "Dir.rename directory onto empty dir" {
10071040
10081041 try testWithAllSupportedPathTypes(struct {
10091042 fn impl(ctx: *TestContext) !void {
1043 const io = ctx.io;
1044
10101045 const test_dir_path = try ctx.transformPath("test_dir");
10111046 const target_dir_path = try ctx.transformPath("target_dir_path");
10121047
......@@ -1017,7 +1052,7 @@ test "Dir.rename directory onto empty dir" {
10171052 // Ensure the directory was renamed
10181053 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_path, .{}));
10191054 var dir = try ctx.dir.openDir(target_dir_path, .{});
1020 dir.close();
1055 dir.close(io);
10211056 }
10221057 }.impl);
10231058}
......@@ -1028,6 +1063,7 @@ test "Dir.rename directory onto non-empty dir" {
10281063
10291064 try testWithAllSupportedPathTypes(struct {
10301065 fn impl(ctx: *TestContext) !void {
1066 const io = ctx.io;
10311067 const test_dir_path = try ctx.transformPath("test_dir");
10321068 const target_dir_path = try ctx.transformPath("target_dir_path");
10331069
......@@ -1035,15 +1071,15 @@ test "Dir.rename directory onto non-empty dir" {
10351071
10361072 var target_dir = try ctx.dir.makeOpenPath(target_dir_path, .{});
10371073 var file = try target_dir.createFile("test_file", .{ .read = true });
1038 file.close();
1039 target_dir.close();
1074 file.close(io);
1075 target_dir.close(io);
10401076
10411077 // Rename should fail with PathAlreadyExists if target_dir is non-empty
10421078 try testing.expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, target_dir_path));
10431079
10441080 // Ensure the directory was not renamed
10451081 var dir = try ctx.dir.openDir(test_dir_path, .{});
1046 dir.close();
1082 dir.close(io);
10471083 }
10481084 }.impl);
10491085}
......@@ -1054,11 +1090,12 @@ test "Dir.rename file <-> dir" {
10541090
10551091 try testWithAllSupportedPathTypes(struct {
10561092 fn impl(ctx: *TestContext) !void {
1093 const io = ctx.io;
10571094 const test_file_path = try ctx.transformPath("test_file");
10581095 const test_dir_path = try ctx.transformPath("test_dir");
10591096
10601097 var file = try ctx.dir.createFile(test_file_path, .{ .read = true });
1061 file.close();
1098 file.close(io);
10621099 try ctx.dir.makeDir(test_dir_path);
10631100 try testing.expectError(error.IsDir, ctx.dir.rename(test_file_path, test_dir_path));
10641101 try testing.expectError(error.NotDir, ctx.dir.rename(test_dir_path, test_file_path));
......@@ -1067,6 +1104,8 @@ test "Dir.rename file <-> dir" {
10671104}
10681105
10691106test "rename" {
1107 const io = testing.io;
1108
10701109 var tmp_dir1 = tmpDir(.{});
10711110 defer tmp_dir1.cleanup();
10721111
......@@ -1077,19 +1116,21 @@ test "rename" {
10771116 const test_file_name = "test_file";
10781117 const renamed_test_file_name = "test_file_renamed";
10791118 var file = try tmp_dir1.dir.createFile(test_file_name, .{ .read = true });
1080 file.close();
1119 file.close(io);
10811120 try fs.rename(tmp_dir1.dir, test_file_name, tmp_dir2.dir, renamed_test_file_name);
10821121
10831122 // ensure the file was renamed
10841123 try testing.expectError(error.FileNotFound, tmp_dir1.dir.openFile(test_file_name, .{}));
10851124 file = try tmp_dir2.dir.openFile(renamed_test_file_name, .{});
1086 file.close();
1125 file.close(io);
10871126}
10881127
10891128test "renameAbsolute" {
10901129 if (native_os == .wasi) return error.SkipZigTest;
10911130 if (native_os == .openbsd) return error.SkipZigTest;
10921131
1132 const io = testing.io;
1133
10931134 var tmp_dir = tmpDir(.{});
10941135 defer tmp_dir.cleanup();
10951136
......@@ -1109,7 +1150,7 @@ test "renameAbsolute" {
11091150 const test_file_name = "test_file";
11101151 const renamed_test_file_name = "test_file_renamed";
11111152 var file = try tmp_dir.dir.createFile(test_file_name, .{ .read = true });
1112 file.close();
1153 file.close(io);
11131154 try fs.renameAbsolute(
11141155 try fs.path.join(allocator, &.{ base_path, test_file_name }),
11151156 try fs.path.join(allocator, &.{ base_path, renamed_test_file_name }),
......@@ -1120,7 +1161,7 @@ test "renameAbsolute" {
11201161 file = try tmp_dir.dir.openFile(renamed_test_file_name, .{});
11211162 const stat = try file.stat();
11221163 try testing.expectEqual(File.Kind.file, stat.kind);
1123 file.close();
1164 file.close(io);
11241165
11251166 // Renaming directories
11261167 const test_dir_name = "test_dir";
......@@ -1134,14 +1175,16 @@ test "renameAbsolute" {
11341175 // ensure the directory was renamed
11351176 try testing.expectError(error.FileNotFound, tmp_dir.dir.openDir(test_dir_name, .{}));
11361177 var dir = try tmp_dir.dir.openDir(renamed_test_dir_name, .{});
1137 dir.close();
1178 dir.close(io);
11381179}
11391180
11401181test "openSelfExe" {
11411182 if (native_os == .wasi) return error.SkipZigTest;
11421183
1184 const io = testing.io;
1185
11431186 const self_exe_file = try std.fs.openSelfExe(.{});
1144 self_exe_file.close();
1187 self_exe_file.close(io);
11451188}
11461189
11471190test "selfExePath" {
......@@ -1155,13 +1198,15 @@ test "selfExePath" {
11551198}
11561199
11571200test "deleteTree does not follow symlinks" {
1201 const io = testing.io;
1202
11581203 var tmp = tmpDir(.{});
11591204 defer tmp.cleanup();
11601205
11611206 try tmp.dir.makePath("b");
11621207 {
11631208 var a = try tmp.dir.makeOpenPath("a", .{});
1164 defer a.close();
1209 defer a.close(io);
11651210
11661211 try setupSymlink(a, "../b", "b", .{ .is_directory = true });
11671212 }
......@@ -1257,27 +1302,31 @@ test "makePath but sub_path contains pre-existing file" {
12571302 try testing.expectError(error.NotDir, tmp.dir.makePath("foo/bar/baz"));
12581303}
12591304
1260fn expectDir(dir: Dir, path: []const u8) !void {
1305fn expectDir(io: Io, dir: Dir, path: []const u8) !void {
12611306 var d = try dir.openDir(path, .{});
1262 d.close();
1307 d.close(io);
12631308}
12641309
12651310test "makepath existing directories" {
1311 const io = testing.io;
1312
12661313 var tmp = tmpDir(.{});
12671314 defer tmp.cleanup();
12681315
12691316 try tmp.dir.makeDir("A");
12701317 var tmpA = try tmp.dir.openDir("A", .{});
1271 defer tmpA.close();
1318 defer tmpA.close(io);
12721319 try tmpA.makeDir("B");
12731320
12741321 const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";
12751322 try tmp.dir.makePath(testPath);
12761323
1277 try expectDir(tmp.dir, testPath);
1324 try expectDir(io, tmp.dir, testPath);
12781325}
12791326
12801327test "makepath through existing valid symlink" {
1328 const io = testing.io;
1329
12811330 var tmp = tmpDir(.{});
12821331 defer tmp.cleanup();
12831332
......@@ -1286,10 +1335,12 @@ test "makepath through existing valid symlink" {
12861335
12871336 try tmp.dir.makePath("working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
12881337
1289 try expectDir(tmp.dir, "realfolder" ++ fs.path.sep_str ++ "in-realfolder");
1338 try expectDir(io, tmp.dir, "realfolder" ++ fs.path.sep_str ++ "in-realfolder");
12901339}
12911340
12921341test "makepath relative walks" {
1342 const io = testing.io;
1343
12931344 var tmp = tmpDir(.{});
12941345 defer tmp.cleanup();
12951346
......@@ -1305,21 +1356,23 @@ test "makepath relative walks" {
13051356 .windows => {
13061357 // On Windows, .. is resolved before passing the path to NtCreateFile,
13071358 // meaning everything except `first/C` drops out.
1308 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "C");
1359 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
13091360 try testing.expectError(error.FileNotFound, tmp.dir.access("second", .{}));
13101361 try testing.expectError(error.FileNotFound, tmp.dir.access("third", .{}));
13111362 },
13121363 else => {
1313 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "A");
1314 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "B");
1315 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "C");
1316 try expectDir(tmp.dir, "second");
1317 try expectDir(tmp.dir, "third");
1364 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "A");
1365 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "B");
1366 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
1367 try expectDir(io, tmp.dir, "second");
1368 try expectDir(io, tmp.dir, "third");
13181369 },
13191370 }
13201371}
13211372
13221373test "makepath ignores '.'" {
1374 const io = testing.io;
1375
13231376 var tmp = tmpDir(.{});
13241377 defer tmp.cleanup();
13251378
......@@ -1337,14 +1390,14 @@ test "makepath ignores '.'" {
13371390
13381391 try tmp.dir.makePath(dotPath);
13391392
1340 try expectDir(tmp.dir, expectedPath);
1393 try expectDir(io, tmp.dir, expectedPath);
13411394}
13421395
1343fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {
1396fn testFilenameLimits(io: Io, iterable_dir: Dir, maxed_filename: []const u8) !void {
13441397 // setup, create a dir and a nested file both with maxed filenames, and walk the dir
13451398 {
13461399 var maxed_dir = try iterable_dir.makeOpenPath(maxed_filename, .{});
1347 defer maxed_dir.close();
1400 defer maxed_dir.close(io);
13481401
13491402 try maxed_dir.writeFile(.{ .sub_path = maxed_filename, .data = "" });
13501403
......@@ -1364,6 +1417,8 @@ fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {
13641417}
13651418
13661419test "max file name component lengths" {
1420 const io = testing.io;
1421
13671422 var tmp = tmpDir(.{ .iterate = true });
13681423 defer tmp.cleanup();
13691424
......@@ -1371,16 +1426,16 @@ test "max file name component lengths" {
13711426 // U+FFFF is the character with the largest code point that is encoded as a single
13721427 // UTF-16 code unit, so Windows allows for NAME_MAX of them.
13731428 const maxed_windows_filename = ("\u{FFFF}".*) ** windows.NAME_MAX;
1374 try testFilenameLimits(tmp.dir, &maxed_windows_filename);
1429 try testFilenameLimits(io, tmp.dir, &maxed_windows_filename);
13751430 } else if (native_os == .wasi) {
13761431 // On WASI, the maxed filename depends on the host OS, so in order for this test to
13771432 // work on any host, we need to use a length that will work for all platforms
13781433 // (i.e. the minimum max_name_bytes of all supported platforms).
13791434 const maxed_wasi_filename = [_]u8{'1'} ** 255;
1380 try testFilenameLimits(tmp.dir, &maxed_wasi_filename);
1435 try testFilenameLimits(io, tmp.dir, &maxed_wasi_filename);
13811436 } else {
13821437 const maxed_ascii_filename = [_]u8{'1'} ** std.fs.max_name_bytes;
1383 try testFilenameLimits(tmp.dir, &maxed_ascii_filename);
1438 try testFilenameLimits(io, tmp.dir, &maxed_ascii_filename);
13841439 }
13851440}
13861441
......@@ -1399,7 +1454,7 @@ test "writev, readv" {
13991454 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };
14001455
14011456 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
1402 defer src_file.close();
1457 defer src_file.close(io);
14031458
14041459 var writer = src_file.writerStreaming(&.{});
14051460
......@@ -1429,7 +1484,7 @@ test "pwritev, preadv" {
14291484 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };
14301485
14311486 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
1432 defer src_file.close();
1487 defer src_file.close(io);
14331488
14341489 var writer = src_file.writer(&.{});
14351490
......@@ -1459,7 +1514,7 @@ test "setEndPos" {
14591514 const file_name = "afile.txt";
14601515 try tmp.dir.writeFile(.{ .sub_path = file_name, .data = "ninebytes" });
14611516 const f = try tmp.dir.openFile(file_name, .{ .mode = .read_write });
1462 defer f.close();
1517 defer f.close(io);
14631518
14641519 const initial_size = try f.getEndPos();
14651520 var buffer: [32]u8 = undefined;
......@@ -1522,21 +1577,21 @@ test "sendfile" {
15221577 try tmp.dir.makePath("os_test_tmp");
15231578
15241579 var dir = try tmp.dir.openDir("os_test_tmp", .{});
1525 defer dir.close();
1580 defer dir.close(io);
15261581
15271582 const line1 = "line1\n";
15281583 const line2 = "second line\n";
15291584 var vecs = [_][]const u8{ line1, line2 };
15301585
15311586 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });
1532 defer src_file.close();
1587 defer src_file.close(io);
15331588 {
15341589 var fw = src_file.writer(&.{});
15351590 try fw.interface.writeVecAll(&vecs);
15361591 }
15371592
15381593 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });
1539 defer dest_file.close();
1594 defer dest_file.close(io);
15401595
15411596 const header1 = "header1\n";
15421597 const header2 = "second header\n";
......@@ -1569,15 +1624,15 @@ test "sendfile with buffered data" {
15691624 try tmp.dir.makePath("os_test_tmp");
15701625
15711626 var dir = try tmp.dir.openDir("os_test_tmp", .{});
1572 defer dir.close();
1627 defer dir.close(io);
15731628
15741629 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });
1575 defer src_file.close();
1630 defer src_file.close(io);
15761631
15771632 try src_file.writeAll("AAAABBBB");
15781633
15791634 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });
1580 defer dest_file.close();
1635 defer dest_file.close(io);
15811636
15821637 var src_buffer: [32]u8 = undefined;
15831638 var file_reader = src_file.reader(io, &src_buffer);
......@@ -1659,10 +1714,11 @@ test "open file with exclusive nonblocking lock twice" {
16591714
16601715 try testWithAllSupportedPathTypes(struct {
16611716 fn impl(ctx: *TestContext) !void {
1717 const io = ctx.io;
16621718 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16631719
16641720 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1665 defer file1.close();
1721 defer file1.close(io);
16661722
16671723 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
16681724 try testing.expectError(error.WouldBlock, file2);
......@@ -1675,10 +1731,11 @@ test "open file with shared and exclusive nonblocking lock" {
16751731
16761732 try testWithAllSupportedPathTypes(struct {
16771733 fn impl(ctx: *TestContext) !void {
1734 const io = ctx.io;
16781735 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16791736
16801737 const file1 = try ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });
1681 defer file1.close();
1738 defer file1.close(io);
16821739
16831740 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
16841741 try testing.expectError(error.WouldBlock, file2);
......@@ -1691,10 +1748,11 @@ test "open file with exclusive and shared nonblocking lock" {
16911748
16921749 try testWithAllSupportedPathTypes(struct {
16931750 fn impl(ctx: *TestContext) !void {
1751 const io = ctx.io;
16941752 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16951753
16961754 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1697 defer file1.close();
1755 defer file1.close(io);
16981756
16991757 const file2 = ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });
17001758 try testing.expectError(error.WouldBlock, file2);
......@@ -1707,10 +1765,11 @@ test "open file with exclusive lock twice, make sure second lock waits" {
17071765
17081766 try testWithAllSupportedPathTypes(struct {
17091767 fn impl(ctx: *TestContext) !void {
1768 const io = ctx.io;
17101769 const filename = try ctx.transformPath("file_lock_test.txt");
17111770
17121771 const file = try ctx.dir.createFile(filename, .{ .lock = .exclusive });
1713 errdefer file.close();
1772 errdefer file.close(io);
17141773
17151774 const S = struct {
17161775 fn checkFn(dir: *fs.Dir, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {
......@@ -1718,7 +1777,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
17181777 const file1 = try dir.createFile(path, .{ .lock = .exclusive });
17191778
17201779 locked.set();
1721 file1.close();
1780 file1.close(io);
17221781 }
17231782 };
17241783
......@@ -1739,7 +1798,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
17391798 try testing.expectError(error.Timeout, locked.timedWait(10 * std.time.ns_per_ms));
17401799
17411800 // Release the file lock which should unlock the thread to lock it and set the locked event.
1742 file.close();
1801 file.close(io);
17431802 locked.wait();
17441803 }
17451804 }.impl);
......@@ -1748,6 +1807,8 @@ test "open file with exclusive lock twice, make sure second lock waits" {
17481807test "open file with exclusive nonblocking lock twice (absolute paths)" {
17491808 if (native_os == .wasi) return error.SkipZigTest;
17501809
1810 const io = testing.io;
1811
17511812 var random_bytes: [12]u8 = undefined;
17521813 std.crypto.random.bytes(&random_bytes);
17531814
......@@ -1774,18 +1835,19 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
17741835 .lock = .exclusive,
17751836 .lock_nonblocking = true,
17761837 });
1777 file1.close();
1838 file1.close(io);
17781839 try testing.expectError(error.WouldBlock, file2);
17791840}
17801841
17811842test "read from locked file" {
17821843 try testWithAllSupportedPathTypes(struct {
17831844 fn impl(ctx: *TestContext) !void {
1845 const io = ctx.io;
17841846 const filename = try ctx.transformPath("read_lock_file_test.txt");
17851847
17861848 {
17871849 const f = try ctx.dir.createFile(filename, .{ .read = true });
1788 defer f.close();
1850 defer f.close(io);
17891851 var buffer: [1]u8 = undefined;
17901852 _ = try f.read(&buffer);
17911853 }
......@@ -1794,9 +1856,9 @@ test "read from locked file" {
17941856 .read = true,
17951857 .lock = .exclusive,
17961858 });
1797 defer f.close();
1859 defer f.close(io);
17981860 const f2 = try ctx.dir.openFile(filename, .{});
1799 defer f2.close();
1861 defer f2.close(io);
18001862 var buffer: [1]u8 = undefined;
18011863 if (builtin.os.tag == .windows) {
18021864 try std.testing.expectError(error.LockViolation, f2.read(&buffer));
......@@ -1809,6 +1871,8 @@ test "read from locked file" {
18091871}
18101872
18111873test "walker" {
1874 const io = testing.io;
1875
18121876 var tmp = tmpDir(.{ .iterate = true });
18131877 defer tmp.cleanup();
18141878
......@@ -1857,13 +1921,15 @@ test "walker" {
18571921 };
18581922 // make sure that the entry.dir is the containing dir
18591923 var entry_dir = try entry.dir.openDir(entry.basename, .{});
1860 defer entry_dir.close();
1924 defer entry_dir.close(io);
18611925 num_walked += 1;
18621926 }
18631927 try testing.expectEqual(expected_paths.kvs.len, num_walked);
18641928}
18651929
18661930test "selective walker, skip entries that start with ." {
1931 const io = testing.io;
1932
18671933 var tmp = tmpDir(.{ .iterate = true });
18681934 defer tmp.cleanup();
18691935
......@@ -1923,7 +1989,7 @@ test "selective walker, skip entries that start with ." {
19231989
19241990 // make sure that the entry.dir is the containing dir
19251991 var entry_dir = try entry.dir.openDir(entry.basename, .{});
1926 defer entry_dir.close();
1992 defer entry_dir.close(io);
19271993 num_walked += 1;
19281994 }
19291995 try testing.expectEqual(expected_paths.kvs.len, num_walked);
......@@ -1968,16 +2034,16 @@ test "'.' and '..' in fs.Dir functions" {
19682034 try ctx.dir.makeDir(subdir_path);
19692035 try ctx.dir.access(subdir_path, .{});
19702036 var created_subdir = try ctx.dir.openDir(subdir_path, .{});
1971 created_subdir.close();
2037 created_subdir.close(io);
19722038
19732039 const created_file = try ctx.dir.createFile(file_path, .{});
1974 created_file.close();
2040 created_file.close(io);
19752041 try ctx.dir.access(file_path, .{});
19762042
19772043 try ctx.dir.copyFile(file_path, ctx.dir, copy_path, .{});
19782044 try ctx.dir.rename(copy_path, rename_path);
19792045 const renamed_file = try ctx.dir.openFile(rename_path, .{});
1980 renamed_file.close();
2046 renamed_file.close(io);
19812047 try ctx.dir.deleteFile(rename_path);
19822048
19832049 try ctx.dir.writeFile(.{ .sub_path = update_path, .data = "something" });
......@@ -1994,6 +2060,8 @@ test "'.' and '..' in absolute functions" {
19942060 if (native_os == .wasi) return error.SkipZigTest;
19952061 if (native_os == .openbsd) return error.SkipZigTest;
19962062
2063 const io = testing.io;
2064
19972065 var tmp = tmpDir(.{});
19982066 defer tmp.cleanup();
19992067
......@@ -2007,11 +2075,11 @@ test "'.' and '..' in absolute functions" {
20072075 try fs.makeDirAbsolute(subdir_path);
20082076 try fs.accessAbsolute(subdir_path, .{});
20092077 var created_subdir = try fs.openDirAbsolute(subdir_path, .{});
2010 created_subdir.close();
2078 created_subdir.close(io);
20112079
20122080 const created_file_path = try fs.path.join(allocator, &.{ subdir_path, "../file" });
20132081 const created_file = try fs.createFileAbsolute(created_file_path, .{});
2014 created_file.close();
2082 created_file.close(io);
20152083 try fs.accessAbsolute(created_file_path, .{});
20162084
20172085 const copied_file_path = try fs.path.join(allocator, &.{ subdir_path, "../copy" });
......@@ -2019,7 +2087,7 @@ test "'.' and '..' in absolute functions" {
20192087 const renamed_file_path = try fs.path.join(allocator, &.{ subdir_path, "../rename" });
20202088 try fs.renameAbsolute(copied_file_path, renamed_file_path);
20212089 const renamed_file = try fs.openFileAbsolute(renamed_file_path, .{});
2022 renamed_file.close();
2090 renamed_file.close(io);
20232091 try fs.deleteFileAbsolute(renamed_file_path);
20242092
20252093 try fs.deleteDirAbsolute(subdir_path);
......@@ -2029,11 +2097,13 @@ test "chmod" {
20292097 if (native_os == .windows or native_os == .wasi)
20302098 return error.SkipZigTest;
20312099
2100 const io = testing.io;
2101
20322102 var tmp = tmpDir(.{});
20332103 defer tmp.cleanup();
20342104
20352105 const file = try tmp.dir.createFile("test_file", .{ .mode = 0o600 });
2036 defer file.close();
2106 defer file.close(io);
20372107 try testing.expectEqual(@as(File.Mode, 0o600), (try file.stat()).mode & 0o7777);
20382108
20392109 try file.chmod(0o644);
......@@ -2041,7 +2111,7 @@ test "chmod" {
20412111
20422112 try tmp.dir.makeDir("test_dir");
20432113 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
2044 defer dir.close();
2114 defer dir.close(io);
20452115
20462116 try dir.chmod(0o700);
20472117 try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat()).mode & 0o7777);
......@@ -2051,17 +2121,19 @@ test "chown" {
20512121 if (native_os == .windows or native_os == .wasi)
20522122 return error.SkipZigTest;
20532123
2124 const io = testing.io;
2125
20542126 var tmp = tmpDir(.{});
20552127 defer tmp.cleanup();
20562128
20572129 const file = try tmp.dir.createFile("test_file", .{});
2058 defer file.close();
2130 defer file.close(io);
20592131 try file.chown(null, null);
20602132
20612133 try tmp.dir.makeDir("test_dir");
20622134
20632135 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
2064 defer dir.close();
2136 defer dir.close(io);
20652137 try dir.chown(null, null);
20662138}
20672139
......@@ -2157,7 +2229,7 @@ test "read file non vectored" {
21572229 const contents = "hello, world!\n";
21582230
21592231 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2160 defer file.close();
2232 defer file.close(io);
21612233 {
21622234 var file_writer: std.fs.File.Writer = .init(file, &.{});
21632235 try file_writer.interface.writeAll(contents);
......@@ -2189,7 +2261,7 @@ test "seek keeping partial buffer" {
21892261 const contents = "0123456789";
21902262
21912263 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2192 defer file.close();
2264 defer file.close(io);
21932265 {
21942266 var file_writer: std.fs.File.Writer = .init(file, &.{});
21952267 try file_writer.interface.writeAll(contents);
......@@ -2231,7 +2303,7 @@ test "seekBy" {
22312303
22322304 try tmp_dir.dir.writeFile(.{ .sub_path = "blah.txt", .data = "let's test seekBy" });
22332305 const f = try tmp_dir.dir.openFile("blah.txt", .{ .mode = .read_only });
2234 defer f.close();
2306 defer f.close(io);
22352307 var reader = f.readerStreaming(io, &.{});
22362308 try reader.seekBy(2);
22372309
......@@ -2250,7 +2322,7 @@ test "seekTo flushes buffered data" {
22502322 const contents = "data";
22512323
22522324 const file = try tmp.dir.createFile("seek.bin", .{ .read = true });
2253 defer file.close();
2325 defer file.close(io);
22542326 {
22552327 var buf: [16]u8 = undefined;
22562328 var file_writer = std.fs.File.writer(file, &buf);
......@@ -2277,9 +2349,9 @@ test "File.Writer sendfile with buffered contents" {
22772349 {
22782350 try tmp_dir.dir.writeFile(.{ .sub_path = "a", .data = "bcd" });
22792351 const in = try tmp_dir.dir.openFile("a", .{});
2280 defer in.close();
2352 defer in.close(io);
22812353 const out = try tmp_dir.dir.createFile("b", .{});
2282 defer out.close();
2354 defer out.close(io);
22832355
22842356 var in_buf: [2]u8 = undefined;
22852357 var in_r = in.reader(io, &in_buf);
......@@ -2294,7 +2366,7 @@ test "File.Writer sendfile with buffered contents" {
22942366 }
22952367
22962368 var check = try tmp_dir.dir.openFile("b", .{});
2297 defer check.close();
2369 defer check.close(io);
22982370 var check_buf: [4]u8 = undefined;
22992371 var check_r = check.reader(io, &check_buf);
23002372 try testing.expectEqualStrings("abcd", try check_r.interface.take(4));
lib/std/http/Client.zig+3-1
......@@ -1473,6 +1473,8 @@ pub const ConnectUnixError = Allocator.Error || std.posix.SocketError || error{N
14731473///
14741474/// This function is threadsafe.
14751475pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection {
1476 const io = client.io;
1477
14761478 if (client.connection_pool.findConnection(.{
14771479 .host = path,
14781480 .port = 0,
......@@ -1485,7 +1487,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti
14851487 conn.* = .{ .data = undefined };
14861488
14871489 const stream = try Io.net.connectUnixSocket(path);
1488 errdefer stream.close();
1490 errdefer stream.close(io);
14891491
14901492 conn.data = .{
14911493 .stream = stream,
lib/std/os/linux/IoUring.zig+63-22
......@@ -1,13 +1,16 @@
11const IoUring = @This();
2const std = @import("std");
2
33const builtin = @import("builtin");
4const is_linux = builtin.os.tag == .linux;
5
6const std = @import("std");
7const Io = std.Io;
48const assert = std.debug.assert;
59const mem = std.mem;
610const net = std.Io.net;
711const posix = std.posix;
812const linux = std.os.linux;
913const testing = std.testing;
10const is_linux = builtin.os.tag == .linux;
1114const page_size_min = std.heap.page_size_min;
1215
1316fd: linux.fd_t = -1,
......@@ -1975,6 +1978,8 @@ test "readv" {
19751978test "writev/fsync/readv" {
19761979 if (!is_linux) return error.SkipZigTest;
19771980
1981 const io = testing.io;
1982
19781983 var ring = IoUring.init(4, 0) catch |err| switch (err) {
19791984 error.SystemOutdated => return error.SkipZigTest,
19801985 error.PermissionDenied => return error.SkipZigTest,
......@@ -1987,7 +1992,7 @@ test "writev/fsync/readv" {
19871992
19881993 const path = "test_io_uring_writev_fsync_readv";
19891994 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
1990 defer file.close();
1995 defer file.close(io);
19911996 const fd = file.handle;
19921997
19931998 const buffer_write = [_]u8{42} ** 128;
......@@ -2045,6 +2050,8 @@ test "writev/fsync/readv" {
20452050test "write/read" {
20462051 if (!is_linux) return error.SkipZigTest;
20472052
2053 const io = testing.io;
2054
20482055 var ring = IoUring.init(2, 0) catch |err| switch (err) {
20492056 error.SystemOutdated => return error.SkipZigTest,
20502057 error.PermissionDenied => return error.SkipZigTest,
......@@ -2056,7 +2063,7 @@ test "write/read" {
20562063 defer tmp.cleanup();
20572064 const path = "test_io_uring_write_read";
20582065 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
2059 defer file.close();
2066 defer file.close(io);
20602067 const fd = file.handle;
20612068
20622069 const buffer_write = [_]u8{97} ** 20;
......@@ -2092,6 +2099,8 @@ test "write/read" {
20922099test "splice/read" {
20932100 if (!is_linux) return error.SkipZigTest;
20942101
2102 const io = testing.io;
2103
20952104 var ring = IoUring.init(4, 0) catch |err| switch (err) {
20962105 error.SystemOutdated => return error.SkipZigTest,
20972106 error.PermissionDenied => return error.SkipZigTest,
......@@ -2102,12 +2111,12 @@ test "splice/read" {
21022111 var tmp = std.testing.tmpDir(.{});
21032112 const path_src = "test_io_uring_splice_src";
21042113 const file_src = try tmp.dir.createFile(path_src, .{ .read = true, .truncate = true });
2105 defer file_src.close();
2114 defer file_src.close(io);
21062115 const fd_src = file_src.handle;
21072116
21082117 const path_dst = "test_io_uring_splice_dst";
21092118 const file_dst = try tmp.dir.createFile(path_dst, .{ .read = true, .truncate = true });
2110 defer file_dst.close();
2119 defer file_dst.close(io);
21112120 const fd_dst = file_dst.handle;
21122121
21132122 const buffer_write = [_]u8{97} ** 20;
......@@ -2163,6 +2172,8 @@ test "splice/read" {
21632172test "write_fixed/read_fixed" {
21642173 if (!is_linux) return error.SkipZigTest;
21652174
2175 const io = testing.io;
2176
21662177 var ring = IoUring.init(2, 0) catch |err| switch (err) {
21672178 error.SystemOutdated => return error.SkipZigTest,
21682179 error.PermissionDenied => return error.SkipZigTest,
......@@ -2175,7 +2186,7 @@ test "write_fixed/read_fixed" {
21752186
21762187 const path = "test_io_uring_write_read_fixed";
21772188 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
2178 defer file.close();
2189 defer file.close(io);
21792190 const fd = file.handle;
21802191
21812192 var raw_buffers: [2][11]u8 = undefined;
......@@ -2282,6 +2293,8 @@ test "openat" {
22822293test "close" {
22832294 if (!is_linux) return error.SkipZigTest;
22842295
2296 const io = testing.io;
2297
22852298 var ring = IoUring.init(1, 0) catch |err| switch (err) {
22862299 error.SystemOutdated => return error.SkipZigTest,
22872300 error.PermissionDenied => return error.SkipZigTest,
......@@ -2294,7 +2307,7 @@ test "close" {
22942307
22952308 const path = "test_io_uring_close";
22962309 const file = try tmp.dir.createFile(path, .{});
2297 errdefer file.close();
2310 errdefer file.close(io);
22982311
22992312 const sqe_close = try ring.close(0x44444444, file.handle);
23002313 try testing.expectEqual(linux.IORING_OP.CLOSE, sqe_close.opcode);
......@@ -2313,6 +2326,8 @@ test "close" {
23132326test "accept/connect/send/recv" {
23142327 if (!is_linux) return error.SkipZigTest;
23152328
2329 const io = testing.io;
2330
23162331 var ring = IoUring.init(16, 0) catch |err| switch (err) {
23172332 error.SystemOutdated => return error.SkipZigTest,
23182333 error.PermissionDenied => return error.SkipZigTest,
......@@ -2321,7 +2336,7 @@ test "accept/connect/send/recv" {
23212336 defer ring.deinit();
23222337
23232338 const socket_test_harness = try createSocketTestHarness(&ring);
2324 defer socket_test_harness.close();
2339 defer socket_test_harness.close(io);
23252340
23262341 const buffer_send = [_]u8{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
23272342 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
......@@ -2573,6 +2588,8 @@ test "timeout_remove" {
25732588test "accept/connect/recv/link_timeout" {
25742589 if (!is_linux) return error.SkipZigTest;
25752590
2591 const io = testing.io;
2592
25762593 var ring = IoUring.init(16, 0) catch |err| switch (err) {
25772594 error.SystemOutdated => return error.SkipZigTest,
25782595 error.PermissionDenied => return error.SkipZigTest,
......@@ -2581,7 +2598,7 @@ test "accept/connect/recv/link_timeout" {
25812598 defer ring.deinit();
25822599
25832600 const socket_test_harness = try createSocketTestHarness(&ring);
2584 defer socket_test_harness.close();
2601 defer socket_test_harness.close(io);
25852602
25862603 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
25872604
......@@ -2622,6 +2639,8 @@ test "accept/connect/recv/link_timeout" {
26222639test "fallocate" {
26232640 if (!is_linux) return error.SkipZigTest;
26242641
2642 const io = testing.io;
2643
26252644 var ring = IoUring.init(1, 0) catch |err| switch (err) {
26262645 error.SystemOutdated => return error.SkipZigTest,
26272646 error.PermissionDenied => return error.SkipZigTest,
......@@ -2634,7 +2653,7 @@ test "fallocate" {
26342653
26352654 const path = "test_io_uring_fallocate";
26362655 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
2637 defer file.close();
2656 defer file.close(io);
26382657
26392658 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);
26402659
......@@ -2668,6 +2687,8 @@ test "fallocate" {
26682687test "statx" {
26692688 if (!is_linux) return error.SkipZigTest;
26702689
2690 const io = testing.io;
2691
26712692 var ring = IoUring.init(1, 0) catch |err| switch (err) {
26722693 error.SystemOutdated => return error.SkipZigTest,
26732694 error.PermissionDenied => return error.SkipZigTest,
......@@ -2679,7 +2700,7 @@ test "statx" {
26792700 defer tmp.cleanup();
26802701 const path = "test_io_uring_statx";
26812702 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
2682 defer file.close();
2703 defer file.close(io);
26832704
26842705 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);
26852706
......@@ -2725,6 +2746,8 @@ test "statx" {
27252746test "accept/connect/recv/cancel" {
27262747 if (!is_linux) return error.SkipZigTest;
27272748
2749 const io = testing.io;
2750
27282751 var ring = IoUring.init(16, 0) catch |err| switch (err) {
27292752 error.SystemOutdated => return error.SkipZigTest,
27302753 error.PermissionDenied => return error.SkipZigTest,
......@@ -2733,7 +2756,7 @@ test "accept/connect/recv/cancel" {
27332756 defer ring.deinit();
27342757
27352758 const socket_test_harness = try createSocketTestHarness(&ring);
2736 defer socket_test_harness.close();
2759 defer socket_test_harness.close(io);
27372760
27382761 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
27392762
......@@ -2929,6 +2952,8 @@ test "shutdown" {
29292952test "renameat" {
29302953 if (!is_linux) return error.SkipZigTest;
29312954
2955 const io = testing.io;
2956
29322957 var ring = IoUring.init(1, 0) catch |err| switch (err) {
29332958 error.SystemOutdated => return error.SkipZigTest,
29342959 error.PermissionDenied => return error.SkipZigTest,
......@@ -2945,7 +2970,7 @@ test "renameat" {
29452970 // Write old file with data
29462971
29472972 const old_file = try tmp.dir.createFile(old_path, .{ .truncate = true, .mode = 0o666 });
2948 defer old_file.close();
2973 defer old_file.close(io);
29492974 try old_file.writeAll("hello");
29502975
29512976 // Submit renameat
......@@ -2987,6 +3012,8 @@ test "renameat" {
29873012test "unlinkat" {
29883013 if (!is_linux) return error.SkipZigTest;
29893014
3015 const io = testing.io;
3016
29903017 var ring = IoUring.init(1, 0) catch |err| switch (err) {
29913018 error.SystemOutdated => return error.SkipZigTest,
29923019 error.PermissionDenied => return error.SkipZigTest,
......@@ -3002,7 +3029,7 @@ test "unlinkat" {
30023029 // Write old file with data
30033030
30043031 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
3005 defer file.close();
3032 defer file.close(io);
30063033
30073034 // Submit unlinkat
30083035
......@@ -3083,6 +3110,8 @@ test "mkdirat" {
30833110test "symlinkat" {
30843111 if (!is_linux) return error.SkipZigTest;
30853112
3113 const io = testing.io;
3114
30863115 var ring = IoUring.init(1, 0) catch |err| switch (err) {
30873116 error.SystemOutdated => return error.SkipZigTest,
30883117 error.PermissionDenied => return error.SkipZigTest,
......@@ -3097,7 +3126,7 @@ test "symlinkat" {
30973126 const link_path = "test_io_uring_symlinkat_link";
30983127
30993128 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
3100 defer file.close();
3129 defer file.close(io);
31013130
31023131 // Submit symlinkat
31033132
......@@ -3131,6 +3160,8 @@ test "symlinkat" {
31313160test "linkat" {
31323161 if (!is_linux) return error.SkipZigTest;
31333162
3163 const io = testing.io;
3164
31343165 var ring = IoUring.init(1, 0) catch |err| switch (err) {
31353166 error.SystemOutdated => return error.SkipZigTest,
31363167 error.PermissionDenied => return error.SkipZigTest,
......@@ -3147,7 +3178,7 @@ test "linkat" {
31473178 // Write file with data
31483179
31493180 const first_file = try tmp.dir.createFile(first_path, .{ .truncate = true, .mode = 0o666 });
3150 defer first_file.close();
3181 defer first_file.close(io);
31513182 try first_file.writeAll("hello");
31523183
31533184 // Submit linkat
......@@ -3407,6 +3438,8 @@ test "remove_buffers" {
34073438test "provide_buffers: accept/connect/send/recv" {
34083439 if (!is_linux) return error.SkipZigTest;
34093440
3441 const io = testing.io;
3442
34103443 var ring = IoUring.init(16, 0) catch |err| switch (err) {
34113444 error.SystemOutdated => return error.SkipZigTest,
34123445 error.PermissionDenied => return error.SkipZigTest,
......@@ -3443,7 +3476,7 @@ test "provide_buffers: accept/connect/send/recv" {
34433476 }
34443477
34453478 const socket_test_harness = try createSocketTestHarness(&ring);
3446 defer socket_test_harness.close();
3479 defer socket_test_harness.close(io);
34473480
34483481 // Do 4 send on the socket
34493482
......@@ -3696,6 +3729,8 @@ test "accept multishot" {
36963729test "accept/connect/send_zc/recv" {
36973730 try skipKernelLessThan(.{ .major = 6, .minor = 0, .patch = 0 });
36983731
3732 const io = testing.io;
3733
36993734 var ring = IoUring.init(16, 0) catch |err| switch (err) {
37003735 error.SystemOutdated => return error.SkipZigTest,
37013736 error.PermissionDenied => return error.SkipZigTest,
......@@ -3704,7 +3739,7 @@ test "accept/connect/send_zc/recv" {
37043739 defer ring.deinit();
37053740
37063741 const socket_test_harness = try createSocketTestHarness(&ring);
3707 defer socket_test_harness.close();
3742 defer socket_test_harness.close(io);
37083743
37093744 const buffer_send = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };
37103745 var buffer_recv = [_]u8{0} ** 10;
......@@ -4105,6 +4140,8 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
41054140test BufferGroup {
41064141 if (!is_linux) return error.SkipZigTest;
41074142
4143 const io = testing.io;
4144
41084145 // Init IoUring
41094146 var ring = IoUring.init(16, 0) catch |err| switch (err) {
41104147 error.SystemOutdated => return error.SkipZigTest,
......@@ -4132,7 +4169,7 @@ test BufferGroup {
41324169
41334170 // Create client/server fds
41344171 const fds = try createSocketTestHarness(&ring);
4135 defer fds.close();
4172 defer fds.close(io);
41364173 const data = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };
41374174
41384175 // Client sends data
......@@ -4170,6 +4207,8 @@ test BufferGroup {
41704207test "ring mapped buffers recv" {
41714208 if (!is_linux) return error.SkipZigTest;
41724209
4210 const io = testing.io;
4211
41734212 var ring = IoUring.init(16, 0) catch |err| switch (err) {
41744213 error.SystemOutdated => return error.SkipZigTest,
41754214 error.PermissionDenied => return error.SkipZigTest,
......@@ -4196,7 +4235,7 @@ test "ring mapped buffers recv" {
41964235
41974236 // create client/server fds
41984237 const fds = try createSocketTestHarness(&ring);
4199 defer fds.close();
4238 defer fds.close(io);
42004239
42014240 // for random user_data in sqe/cqe
42024241 var Rnd = std.Random.DefaultPrng.init(std.testing.random_seed);
......@@ -4259,6 +4298,8 @@ test "ring mapped buffers recv" {
42594298test "ring mapped buffers multishot recv" {
42604299 if (!is_linux) return error.SkipZigTest;
42614300
4301 const io = testing.io;
4302
42624303 var ring = IoUring.init(16, 0) catch |err| switch (err) {
42634304 error.SystemOutdated => return error.SkipZigTest,
42644305 error.PermissionDenied => return error.SkipZigTest,
......@@ -4285,7 +4326,7 @@ test "ring mapped buffers multishot recv" {
42854326
42864327 // create client/server fds
42874328 const fds = try createSocketTestHarness(&ring);
4288 defer fds.close();
4329 defer fds.close(io);
42894330
42904331 // for random user_data in sqe/cqe
42914332 var Rnd = std.Random.DefaultPrng.init(std.testing.random_seed);
lib/std/os/linux/test.zig+9-3
......@@ -12,12 +12,14 @@ const fs = std.fs;
1212test "fallocate" {
1313 if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30220
1414
15 const io = std.testing.io;
16
1517 var tmp = std.testing.tmpDir(.{});
1618 defer tmp.cleanup();
1719
1820 const path = "test_fallocate";
1921 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
20 defer file.close();
22 defer file.close(io);
2123
2224 try expect((try file.stat()).size == 0);
2325
......@@ -77,12 +79,14 @@ test "timer" {
7779}
7880
7981test "statx" {
82 const io = std.testing.io;
83
8084 var tmp = std.testing.tmpDir(.{});
8185 defer tmp.cleanup();
8286
8387 const tmp_file_name = "just_a_temporary_file.txt";
8488 var file = try tmp.dir.createFile(tmp_file_name, .{});
85 defer file.close();
89 defer file.close(io);
8690
8791 var buf: linux.Statx = undefined;
8892 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, .BASIC_STATS, &buf))) {
......@@ -111,12 +115,14 @@ test "user and group ids" {
111115}
112116
113117test "fadvise" {
118 const io = std.testing.io;
119
114120 var tmp = std.testing.tmpDir(.{});
115121 defer tmp.cleanup();
116122
117123 const tmp_file_name = "temp_posix_fadvise.txt";
118124 var file = try tmp.dir.createFile(tmp_file_name, .{});
119 defer file.close();
125 defer file.close(io);
120126
121127 var buf: [2048]u8 = undefined;
122128 try file.writeAll(&buf);
lib/std/posix/test.zig+38-16
......@@ -148,6 +148,8 @@ test "linkat with different directories" {
148148 else => return error.SkipZigTest,
149149 }
150150
151 const io = testing.io;
152
151153 var tmp = tmpDir(.{});
152154 defer tmp.cleanup();
153155
......@@ -163,10 +165,10 @@ test "linkat with different directories" {
163165 try posix.linkat(tmp.dir.fd, target_name, subdir.fd, link_name, 0);
164166
165167 const efd = try tmp.dir.openFile(target_name, .{});
166 defer efd.close();
168 defer efd.close(io);
167169
168170 const nfd = try subdir.openFile(link_name, .{});
169 defer nfd.close();
171 defer nfd.close(io);
170172
171173 {
172174 const eino, _ = try getLinkInfo(efd.handle);
......@@ -381,6 +383,8 @@ test "mmap" {
381383 if (native_os == .windows or native_os == .wasi)
382384 return error.SkipZigTest;
383385
386 const io = testing.io;
387
384388 var tmp = tmpDir(.{});
385389 defer tmp.cleanup();
386390
......@@ -413,7 +417,7 @@ test "mmap" {
413417 // Create a file used for testing mmap() calls with a file descriptor
414418 {
415419 const file = try tmp.dir.createFile(test_out_file, .{});
416 defer file.close();
420 defer file.close(io);
417421
418422 var stream = file.writer(&.{});
419423
......@@ -426,7 +430,7 @@ test "mmap" {
426430 // Map the whole file
427431 {
428432 const file = try tmp.dir.openFile(test_out_file, .{});
429 defer file.close();
433 defer file.close(io);
430434
431435 const data = try posix.mmap(
432436 null,
......@@ -451,7 +455,7 @@ test "mmap" {
451455 // Map the upper half of the file
452456 {
453457 const file = try tmp.dir.openFile(test_out_file, .{});
454 defer file.close();
458 defer file.close(io);
455459
456460 const data = try posix.mmap(
457461 null,
......@@ -476,13 +480,15 @@ test "fcntl" {
476480 if (native_os == .windows or native_os == .wasi)
477481 return error.SkipZigTest;
478482
483 const io = testing.io;
484
479485 var tmp = tmpDir(.{});
480486 defer tmp.cleanup();
481487
482488 const test_out_file = "os_tmp_test";
483489
484490 const file = try tmp.dir.createFile(test_out_file, .{});
485 defer file.close();
491 defer file.close(io);
486492
487493 // Note: The test assumes createFile opens the file with CLOEXEC
488494 {
......@@ -526,12 +532,14 @@ test "fsync" {
526532 else => return error.SkipZigTest,
527533 }
528534
535 const io = testing.io;
536
529537 var tmp = tmpDir(.{});
530538 defer tmp.cleanup();
531539
532540 const test_out_file = "os_tmp_test";
533541 const file = try tmp.dir.createFile(test_out_file, .{});
534 defer file.close();
542 defer file.close(io);
535543
536544 try posix.fsync(file.handle);
537545 try posix.fdatasync(file.handle);
......@@ -646,22 +654,24 @@ test "dup & dup2" {
646654 else => return error.SkipZigTest,
647655 }
648656
657 const io = testing.io;
658
649659 var tmp = tmpDir(.{});
650660 defer tmp.cleanup();
651661
652662 {
653663 var file = try tmp.dir.createFile("os_dup_test", .{});
654 defer file.close();
664 defer file.close(io);
655665
656666 var duped = std.fs.File{ .handle = try posix.dup(file.handle) };
657 defer duped.close();
667 defer duped.close(io);
658668 try duped.writeAll("dup");
659669
660670 // Tests aren't run in parallel so using the next fd shouldn't be an issue.
661671 const new_fd = duped.handle + 1;
662672 try posix.dup2(file.handle, new_fd);
663673 var dup2ed = std.fs.File{ .handle = new_fd };
664 defer dup2ed.close();
674 defer dup2ed.close(io);
665675 try dup2ed.writeAll("dup2");
666676 }
667677
......@@ -687,11 +697,13 @@ test "getppid" {
687697test "writev longer than IOV_MAX" {
688698 if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
689699
700 const io = testing.io;
701
690702 var tmp = tmpDir(.{});
691703 defer tmp.cleanup();
692704
693705 var file = try tmp.dir.createFile("pwritev", .{});
694 defer file.close();
706 defer file.close(io);
695707
696708 const iovecs = [_]posix.iovec_const{.{ .base = "a", .len = 1 }} ** (posix.IOV_MAX + 1);
697709 const amt = try file.writev(&iovecs);
......@@ -709,12 +721,14 @@ test "POSIX file locking with fcntl" {
709721 return error.SkipZigTest;
710722 }
711723
724 const io = testing.io;
725
712726 var tmp = tmpDir(.{});
713727 defer tmp.cleanup();
714728
715729 // Create a temporary lock file
716730 var file = try tmp.dir.createFile("lock", .{ .read = true });
717 defer file.close();
731 defer file.close(io);
718732 try file.setEndPos(2);
719733 const fd = file.handle;
720734
......@@ -905,21 +919,25 @@ test "timerfd" {
905919}
906920
907921test "isatty" {
922 const io = testing.io;
923
908924 var tmp = tmpDir(.{});
909925 defer tmp.cleanup();
910926
911927 var file = try tmp.dir.createFile("foo", .{});
912 defer file.close();
928 defer file.close(io);
913929
914930 try expectEqual(posix.isatty(file.handle), false);
915931}
916932
917933test "pread with empty buffer" {
934 const io = testing.io;
935
918936 var tmp = tmpDir(.{});
919937 defer tmp.cleanup();
920938
921939 var file = try tmp.dir.createFile("pread_empty", .{ .read = true });
922 defer file.close();
940 defer file.close(io);
923941
924942 const bytes = try a.alloc(u8, 0);
925943 defer a.free(bytes);
......@@ -929,11 +947,13 @@ test "pread with empty buffer" {
929947}
930948
931949test "write with empty buffer" {
950 const io = testing.io;
951
932952 var tmp = tmpDir(.{});
933953 defer tmp.cleanup();
934954
935955 var file = try tmp.dir.createFile("write_empty", .{});
936 defer file.close();
956 defer file.close(io);
937957
938958 const bytes = try a.alloc(u8, 0);
939959 defer a.free(bytes);
......@@ -943,11 +963,13 @@ test "write with empty buffer" {
943963}
944964
945965test "pwrite with empty buffer" {
966 const io = testing.io;
967
946968 var tmp = tmpDir(.{});
947969 defer tmp.cleanup();
948970
949971 var file = try tmp.dir.createFile("pwrite_empty", .{});
950 defer file.close();
972 defer file.close(io);
951973
952974 const bytes = try a.alloc(u8, 0);
953975 defer a.free(bytes);
lib/std/process.zig+7-5
......@@ -1,12 +1,14 @@
1const std = @import("std.zig");
21const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("std.zig");
5const Io = std.Io;
36const fs = std.fs;
47const mem = std.mem;
58const math = std.math;
6const Allocator = mem.Allocator;
9const Allocator = std.mem.Allocator;
710const assert = std.debug.assert;
811const testing = std.testing;
9const native_os = builtin.os.tag;
1012const posix = std.posix;
1113const windows = std.os.windows;
1214const unicode = std.unicode;
......@@ -1571,9 +1573,9 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
15711573
15721574/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
15731575/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
1574pub fn posixGetUserInfo(name: []const u8) !UserInfo {
1576pub fn posixGetUserInfo(io: Io, name: []const u8) !UserInfo {
15751577 const file = try std.fs.openFileAbsolute("/etc/passwd", .{});
1576 defer file.close();
1578 defer file.close(io);
15771579 var buffer: [4096]u8 = undefined;
15781580 var file_reader = file.reader(&buffer);
15791581 return posixGetUserInfoPasswdStream(name, &file_reader.interface) catch |err| switch (err) {
lib/std/process/Child.zig+22-21
......@@ -4,6 +4,7 @@ const builtin = @import("builtin");
44const native_os = builtin.os.tag;
55
66const std = @import("../std.zig");
7const Io = std.Io;
78const unicode = std.unicode;
89const fs = std.fs;
910const process = std.process;
......@@ -277,17 +278,17 @@ pub fn spawnAndWait(self: *ChildProcess) SpawnError!Term {
277278}
278279
279280/// Forcibly terminates child process and then cleans up all resources.
280pub fn kill(self: *ChildProcess) !Term {
281pub fn kill(self: *ChildProcess, io: Io) !Term {
281282 if (native_os == .windows) {
282 return self.killWindows(1);
283 return self.killWindows(io, 1);
283284 } else {
284 return self.killPosix();
285 return self.killPosix(io);
285286 }
286287}
287288
288pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
289pub fn killWindows(self: *ChildProcess, io: Io, exit_code: windows.UINT) !Term {
289290 if (self.term) |term| {
290 self.cleanupStreams();
291 self.cleanupStreams(io);
291292 return term;
292293 }
293294
......@@ -303,20 +304,20 @@ pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
303304 },
304305 else => return err,
305306 };
306 try self.waitUnwrappedWindows();
307 try self.waitUnwrappedWindows(io);
307308 return self.term.?;
308309}
309310
310pub fn killPosix(self: *ChildProcess) !Term {
311pub fn killPosix(self: *ChildProcess, io: Io) !Term {
311312 if (self.term) |term| {
312 self.cleanupStreams();
313 self.cleanupStreams(io);
313314 return term;
314315 }
315316 posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {
316317 error.ProcessNotFound => return error.AlreadyTerminated,
317318 else => return err,
318319 };
319 self.waitUnwrappedPosix();
320 self.waitUnwrappedPosix(io);
320321 return self.term.?;
321322}
322323
......@@ -354,15 +355,15 @@ pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {
354355}
355356
356357/// Blocks until child process terminates and then cleans up all resources.
357pub fn wait(self: *ChildProcess) WaitError!Term {
358pub fn wait(self: *ChildProcess, io: Io) WaitError!Term {
358359 try self.waitForSpawn(); // report spawn errors
359360 if (self.term) |term| {
360 self.cleanupStreams();
361 self.cleanupStreams(io);
361362 return term;
362363 }
363364 switch (native_os) {
364 .windows => try self.waitUnwrappedWindows(),
365 else => self.waitUnwrappedPosix(),
365 .windows => try self.waitUnwrappedWindows(io),
366 else => self.waitUnwrappedPosix(io),
366367 }
367368 self.id = undefined;
368369 return self.term.?;
......@@ -474,7 +475,7 @@ pub fn run(args: struct {
474475 };
475476}
476477
477fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {
478fn waitUnwrappedWindows(self: *ChildProcess, io: Io) WaitError!void {
478479 const result = windows.WaitForSingleObjectEx(self.id, windows.INFINITE, false);
479480
480481 self.term = @as(SpawnError!Term, x: {
......@@ -492,11 +493,11 @@ fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {
492493
493494 posix.close(self.id);
494495 posix.close(self.thread_handle);
495 self.cleanupStreams();
496 self.cleanupStreams(io);
496497 return result;
497498}
498499
499fn waitUnwrappedPosix(self: *ChildProcess) void {
500fn waitUnwrappedPosix(self: *ChildProcess, io: Io) void {
500501 const res: posix.WaitPidResult = res: {
501502 if (self.request_resource_usage_statistics) {
502503 switch (native_os) {
......@@ -527,7 +528,7 @@ fn waitUnwrappedPosix(self: *ChildProcess) void {
527528 break :res posix.waitpid(self.id, 0);
528529 };
529530 const status = res.status;
530 self.cleanupStreams();
531 self.cleanupStreams(io);
531532 self.handleWaitResult(status);
532533}
533534
......@@ -535,17 +536,17 @@ fn handleWaitResult(self: *ChildProcess, status: u32) void {
535536 self.term = statusToTerm(status);
536537}
537538
538fn cleanupStreams(self: *ChildProcess) void {
539fn cleanupStreams(self: *ChildProcess, io: Io) void {
539540 if (self.stdin) |*stdin| {
540 stdin.close();
541 stdin.close(io);
541542 self.stdin = null;
542543 }
543544 if (self.stdout) |*stdout| {
544 stdout.close();
545 stdout.close(io);
545546 self.stdout = null;
546547 }
547548 if (self.stderr) |*stderr| {
548 stderr.close();
549 stderr.close(io);
549550 self.stderr = null;
550551 }
551552}
lib/std/tar.zig+40-31
......@@ -16,6 +16,7 @@
1616//! pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
1717
1818const std = @import("std");
19const Io = std.Io;
1920const assert = std.debug.assert;
2021const testing = std.testing;
2122
......@@ -302,7 +303,7 @@ pub const FileKind = enum {
302303
303304/// Iterator over entries in the tar file represented by reader.
304305pub const Iterator = struct {
305 reader: *std.Io.Reader,
306 reader: *Io.Reader,
306307 diagnostics: ?*Diagnostics = null,
307308
308309 // buffers for heeader and file attributes
......@@ -328,7 +329,7 @@ pub const Iterator = struct {
328329
329330 /// Iterates over files in tar archive.
330331 /// `next` returns each file in tar archive.
331 pub fn init(reader: *std.Io.Reader, options: Options) Iterator {
332 pub fn init(reader: *Io.Reader, options: Options) Iterator {
332333 return .{
333334 .reader = reader,
334335 .diagnostics = options.diagnostics,
......@@ -473,7 +474,7 @@ pub const Iterator = struct {
473474 return null;
474475 }
475476
476 pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void {
477 pub fn streamRemaining(it: *Iterator, file: File, w: *Io.Writer) Io.Reader.StreamError!void {
477478 try it.reader.streamExact64(w, file.size);
478479 it.unread_file_bytes = 0;
479480 }
......@@ -499,14 +500,14 @@ const pax_max_size_attr_len = 64;
499500
500501pub const PaxIterator = struct {
501502 size: usize, // cumulative size of all pax attributes
502 reader: *std.Io.Reader,
503 reader: *Io.Reader,
503504
504505 const Self = @This();
505506
506507 const Attribute = struct {
507508 kind: PaxAttributeKind,
508509 len: usize, // length of the attribute value
509 reader: *std.Io.Reader, // reader positioned at value start
510 reader: *Io.Reader, // reader positioned at value start
510511
511512 // Copies pax attribute value into destination buffer.
512513 // Must be called with destination buffer of size at least Attribute.len.
......@@ -573,13 +574,13 @@ pub const PaxIterator = struct {
573574 }
574575
575576 // Checks that each record ends with new line.
576 fn validateAttributeEnding(reader: *std.Io.Reader) !void {
577 fn validateAttributeEnding(reader: *Io.Reader) !void {
577578 if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd;
578579 }
579580};
580581
581582/// Saves tar file content to the file systems.
582pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOptions) !void {
583pub fn pipeToFileSystem(io: Io, dir: Io.Dir, reader: *Io.Reader, options: PipeOptions) !void {
583584 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
584585 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
585586 var file_contents_buffer: [1024]u8 = undefined;
......@@ -610,7 +611,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp
610611 },
611612 .file => {
612613 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
613 defer fs_file.close();
614 defer fs_file.close(io);
614615 var file_writer = fs_file.writer(&file_contents_buffer);
615616 try it.streamRemaining(file, &file_writer.interface);
616617 try file_writer.interface.flush();
......@@ -637,7 +638,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp
637638 }
638639}
639640
640fn createDirAndFile(dir: std.fs.Dir, file_name: []const u8, mode: std.fs.File.Mode) !std.fs.File {
641fn createDirAndFile(dir: Io.Dir, file_name: []const u8, mode: Io.File.Mode) !Io.File {
641642 const fs_file = dir.createFile(file_name, .{ .exclusive = true, .mode = mode }) catch |err| {
642643 if (err == error.FileNotFound) {
643644 if (std.fs.path.dirname(file_name)) |dir_name| {
......@@ -651,7 +652,7 @@ fn createDirAndFile(dir: std.fs.Dir, file_name: []const u8, mode: std.fs.File.Mo
651652}
652653
653654// Creates a symbolic link at path `file_name` which points to `link_name`.
654fn createDirAndSymlink(dir: std.fs.Dir, link_name: []const u8, file_name: []const u8) !void {
655fn createDirAndSymlink(dir: Io.Dir, link_name: []const u8, file_name: []const u8) !void {
655656 dir.symLink(link_name, file_name, .{}) catch |err| {
656657 if (err == error.FileNotFound) {
657658 if (std.fs.path.dirname(file_name)) |dir_name| {
......@@ -783,7 +784,7 @@ test PaxIterator {
783784 var buffer: [1024]u8 = undefined;
784785
785786 outer: for (cases) |case| {
786 var reader: std.Io.Reader = .fixed(case.data);
787 var reader: Io.Reader = .fixed(case.data);
787788 var it: PaxIterator = .{
788789 .size = case.data.len,
789790 .reader = &reader,
......@@ -874,13 +875,15 @@ test "header parse mode" {
874875}
875876
876877test "create file and symlink" {
878 const io = testing.io;
879
877880 var root = testing.tmpDir(.{});
878881 defer root.cleanup();
879882
880883 var file = try createDirAndFile(root.dir, "file1", default_mode);
881 file.close();
884 file.close(io);
882885 file = try createDirAndFile(root.dir, "a/b/c/file2", default_mode);
883 file.close();
886 file.close(io);
884887
885888 createDirAndSymlink(root.dir, "a/b/c/file2", "symlink1") catch |err| {
886889 // On Windows when developer mode is not enabled
......@@ -892,7 +895,7 @@ test "create file and symlink" {
892895 // Danglink symlnik, file created later
893896 try createDirAndSymlink(root.dir, "../../../g/h/i/file4", "j/k/l/symlink3");
894897 file = try createDirAndFile(root.dir, "g/h/i/file4", default_mode);
895 file.close();
898 file.close(io);
896899}
897900
898901test Iterator {
......@@ -916,7 +919,7 @@ test Iterator {
916919 // example/empty/
917920
918921 const data = @embedFile("tar/testdata/example.tar");
919 var reader: std.Io.Reader = .fixed(data);
922 var reader: Io.Reader = .fixed(data);
920923
921924 // User provided buffers to the iterator
922925 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
......@@ -942,7 +945,7 @@ test Iterator {
942945 .file => {
943946 try testing.expectEqualStrings("example/a/file", file.name);
944947 var buf: [16]u8 = undefined;
945 var w: std.Io.Writer = .fixed(&buf);
948 var w: Io.Writer = .fixed(&buf);
946949 try it.streamRemaining(file, &w);
947950 try testing.expectEqualStrings("content\n", w.buffered());
948951 },
......@@ -955,6 +958,7 @@ test Iterator {
955958}
956959
957960test pipeToFileSystem {
961 const io = testing.io;
958962 // Example tar file is created from this tree structure:
959963 // $ tree example
960964 // example
......@@ -975,14 +979,14 @@ test pipeToFileSystem {
975979 // example/empty/
976980
977981 const data = @embedFile("tar/testdata/example.tar");
978 var reader: std.Io.Reader = .fixed(data);
982 var reader: Io.Reader = .fixed(data);
979983
980984 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
981985 defer tmp.cleanup();
982986 const dir = tmp.dir;
983987
984988 // Save tar from reader to the file system `dir`
985 pipeToFileSystem(dir, &reader, .{
989 pipeToFileSystem(io, dir, &reader, .{
986990 .mode_mode = .ignore,
987991 .strip_components = 1,
988992 .exclude_empty_directories = true,
......@@ -1005,8 +1009,9 @@ test pipeToFileSystem {
10051009}
10061010
10071011test "pipeToFileSystem root_dir" {
1012 const io = testing.io;
10081013 const data = @embedFile("tar/testdata/example.tar");
1009 var reader: std.Io.Reader = .fixed(data);
1014 var reader: Io.Reader = .fixed(data);
10101015
10111016 // with strip_components = 1
10121017 {
......@@ -1015,7 +1020,7 @@ test "pipeToFileSystem root_dir" {
10151020 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10161021 defer diagnostics.deinit();
10171022
1018 pipeToFileSystem(tmp.dir, &reader, .{
1023 pipeToFileSystem(io, tmp.dir, &reader, .{
10191024 .strip_components = 1,
10201025 .diagnostics = &diagnostics,
10211026 }) catch |err| {
......@@ -1037,7 +1042,7 @@ test "pipeToFileSystem root_dir" {
10371042 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10381043 defer diagnostics.deinit();
10391044
1040 pipeToFileSystem(tmp.dir, &reader, .{
1045 pipeToFileSystem(io, tmp.dir, &reader, .{
10411046 .strip_components = 0,
10421047 .diagnostics = &diagnostics,
10431048 }) catch |err| {
......@@ -1053,43 +1058,46 @@ test "pipeToFileSystem root_dir" {
10531058}
10541059
10551060test "findRoot with single file archive" {
1061 const io = testing.io;
10561062 const data = @embedFile("tar/testdata/22752.tar");
1057 var reader: std.Io.Reader = .fixed(data);
1063 var reader: Io.Reader = .fixed(data);
10581064
10591065 var tmp = testing.tmpDir(.{});
10601066 defer tmp.cleanup();
10611067
10621068 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10631069 defer diagnostics.deinit();
1064 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
1070 try pipeToFileSystem(io, tmp.dir, &reader, .{ .diagnostics = &diagnostics });
10651071
10661072 try testing.expectEqualStrings("", diagnostics.root_dir);
10671073}
10681074
10691075test "findRoot without explicit root dir" {
1076 const io = testing.io;
10701077 const data = @embedFile("tar/testdata/19820.tar");
1071 var reader: std.Io.Reader = .fixed(data);
1078 var reader: Io.Reader = .fixed(data);
10721079
10731080 var tmp = testing.tmpDir(.{});
10741081 defer tmp.cleanup();
10751082
10761083 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10771084 defer diagnostics.deinit();
1078 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
1085 try pipeToFileSystem(io, tmp.dir, &reader, .{ .diagnostics = &diagnostics });
10791086
10801087 try testing.expectEqualStrings("root", diagnostics.root_dir);
10811088}
10821089
10831090test "pipeToFileSystem strip_components" {
1091 const io = testing.io;
10841092 const data = @embedFile("tar/testdata/example.tar");
1085 var reader: std.Io.Reader = .fixed(data);
1093 var reader: Io.Reader = .fixed(data);
10861094
10871095 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
10881096 defer tmp.cleanup();
10891097 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10901098 defer diagnostics.deinit();
10911099
1092 pipeToFileSystem(tmp.dir, &reader, .{
1100 pipeToFileSystem(io, tmp.dir, &reader, .{
10931101 .strip_components = 3,
10941102 .diagnostics = &diagnostics,
10951103 }) catch |err| {
......@@ -1110,10 +1118,10 @@ fn normalizePath(bytes: []u8) []u8 {
11101118 return bytes;
11111119}
11121120
1113const default_mode = std.fs.File.default_mode;
1121const default_mode = Io.File.default_mode;
11141122
11151123// File system mode based on tar header mode and mode_mode options.
1116fn fileMode(mode: u32, options: PipeOptions) std.fs.File.Mode {
1124fn fileMode(mode: u32, options: PipeOptions) Io.File.Mode {
11171125 if (!std.fs.has_executable_bit or options.mode_mode == .ignore)
11181126 return default_mode;
11191127
......@@ -1139,16 +1147,17 @@ test fileMode {
11391147test "executable bit" {
11401148 if (!std.fs.has_executable_bit) return error.SkipZigTest;
11411149
1150 const io = testing.io;
11421151 const S = std.posix.S;
11431152 const data = @embedFile("tar/testdata/example.tar");
11441153
11451154 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {
1146 var reader: std.Io.Reader = .fixed(data);
1155 var reader: Io.Reader = .fixed(data);
11471156
11481157 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
11491158 //defer tmp.cleanup();
11501159
1151 pipeToFileSystem(tmp.dir, &reader, .{
1160 pipeToFileSystem(io, tmp.dir, &reader, .{
11521161 .strip_components = 1,
11531162 .exclude_empty_directories = true,
11541163 .mode_mode = opt,
lib/std/tar/test.zig+5-3
......@@ -424,6 +424,7 @@ test "insufficient buffer in Header name filed" {
424424}
425425
426426test "should not overwrite existing file" {
427 const io = testing.io;
427428 // Starting from this folder structure:
428429 // $ tree root
429430 // root
......@@ -469,17 +470,18 @@ test "should not overwrite existing file" {
469470 defer root.cleanup();
470471 try testing.expectError(
471472 error.PathAlreadyExists,
472 tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }),
473 tar.pipeToFileSystem(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }),
473474 );
474475
475476 // Unpack with strip_components = 0 should pass
476477 r = .fixed(data);
477478 var root2 = std.testing.tmpDir(.{});
478479 defer root2.cleanup();
479 try tar.pipeToFileSystem(root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 });
480 try tar.pipeToFileSystem(io, root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 });
480481}
481482
482483test "case sensitivity" {
484 const io = testing.io;
483485 // Mimicking issue #18089, this tar contains, same file name in two case
484486 // sensitive name version. Should fail on case insensitive file systems.
485487 //
......@@ -495,7 +497,7 @@ test "case sensitivity" {
495497 var root = std.testing.tmpDir(.{});
496498 defer root.cleanup();
497499
498 tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| {
500 tar.pipeToFileSystem(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| {
499501 // on case insensitive fs we fail on overwrite existing file
500502 try testing.expectEqual(error.PathAlreadyExists, err);
501503 return;
lib/std/testing.zig+3-3
......@@ -613,9 +613,9 @@ pub const TmpDir = struct {
613613 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
614614
615615 pub fn cleanup(self: *TmpDir) void {
616 self.dir.close();
616 self.dir.close(io);
617617 self.parent_dir.deleteTree(&self.sub_path) catch {};
618 self.parent_dir.close();
618 self.parent_dir.close(io);
619619 self.* = undefined;
620620 }
621621};
......@@ -629,7 +629,7 @@ pub fn tmpDir(opts: std.fs.Dir.OpenOptions) TmpDir {
629629 const cwd = std.fs.cwd();
630630 var cache_dir = cwd.makeOpenPath(".zig-cache", .{}) catch
631631 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
632 defer cache_dir.close();
632 defer cache_dir.close(io);
633633 const parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch
634634 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
635635 const dir = parent_dir.makeOpenPath(&sub_path, opts) catch
lib/std/zig/LibCInstallation.zig+40-31
......@@ -1,4 +1,18 @@
11//! See the render function implementation for documentation of the fields.
2const LibCInstallation = @This();
3
4const builtin = @import("builtin");
5const is_darwin = builtin.target.os.tag.isDarwin();
6const is_windows = builtin.target.os.tag == .windows;
7const is_haiku = builtin.target.os.tag == .haiku;
8
9const std = @import("std");
10const Io = std.Io;
11const Target = std.Target;
12const fs = std.fs;
13const Allocator = std.mem.Allocator;
14const Path = std.Build.Cache.Path;
15const log = std.log.scoped(.libc_installation);
216
317include_dir: ?[]const u8 = null,
418sys_include_dir: ?[]const u8 = null,
......@@ -157,6 +171,7 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {
157171
158172pub const FindNativeOptions = struct {
159173 allocator: Allocator,
174 io: Io,
160175 target: *const std.Target,
161176
162177 /// If enabled, will print human-friendly errors to stderr.
......@@ -165,29 +180,32 @@ pub const FindNativeOptions = struct {
165180
166181/// Finds the default, native libc.
167182pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
183 const gpa = args.allocator;
184 const io = args.io;
185
168186 var self: LibCInstallation = .{};
169187
170188 if (is_darwin and args.target.os.tag.isDarwin()) {
171 if (!std.zig.system.darwin.isSdkInstalled(args.allocator))
189 if (!std.zig.system.darwin.isSdkInstalled(gpa))
172190 return error.DarwinSdkNotFound;
173 const sdk = std.zig.system.darwin.getSdk(args.allocator, args.target) orelse
191 const sdk = std.zig.system.darwin.getSdk(gpa, args.target) orelse
174192 return error.DarwinSdkNotFound;
175 defer args.allocator.free(sdk);
193 defer gpa.free(sdk);
176194
177 self.include_dir = try fs.path.join(args.allocator, &.{
195 self.include_dir = try fs.path.join(gpa, &.{
178196 sdk, "usr/include",
179197 });
180 self.sys_include_dir = try fs.path.join(args.allocator, &.{
198 self.sys_include_dir = try fs.path.join(gpa, &.{
181199 sdk, "usr/include",
182200 });
183201 return self;
184202 } else if (is_windows) {
185 const sdk = std.zig.WindowsSdk.find(args.allocator, args.target.cpu.arch) catch |err| switch (err) {
203 const sdk = std.zig.WindowsSdk.find(gpa, io, args.target.cpu.arch) catch |err| switch (err) {
186204 error.NotFound => return error.WindowsSdkNotFound,
187205 error.PathTooLong => return error.WindowsSdkNotFound,
188206 error.OutOfMemory => return error.OutOfMemory,
189207 };
190 defer sdk.free(args.allocator);
208 defer sdk.free(gpa);
191209
192210 try self.findNativeMsvcIncludeDir(args, sdk);
193211 try self.findNativeMsvcLibDir(args, sdk);
......@@ -197,16 +215,16 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
197215 } else if (is_haiku) {
198216 try self.findNativeIncludeDirPosix(args);
199217 try self.findNativeGccDirHaiku(args);
200 self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib");
218 self.crt_dir = try gpa.dupeZ(u8, "/system/develop/lib");
201219 } else if (builtin.target.os.tag == .illumos) {
202220 // There is only one libc, and its headers/libraries are always in the same spot.
203 self.include_dir = try args.allocator.dupeZ(u8, "/usr/include");
204 self.sys_include_dir = try args.allocator.dupeZ(u8, "/usr/include");
205 self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib/64");
221 self.include_dir = try gpa.dupeZ(u8, "/usr/include");
222 self.sys_include_dir = try gpa.dupeZ(u8, "/usr/include");
223 self.crt_dir = try gpa.dupeZ(u8, "/usr/lib/64");
206224 } else if (std.process.can_spawn) {
207225 try self.findNativeIncludeDirPosix(args);
208226 switch (builtin.target.os.tag) {
209 .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib"),
227 .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try gpa.dupeZ(u8, "/usr/lib"),
210228 .linux => try self.findNativeCrtDirPosix(args),
211229 else => {},
212230 }
......@@ -229,6 +247,7 @@ pub fn deinit(self: *LibCInstallation, allocator: Allocator) void {
229247
230248fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
231249 const allocator = args.allocator;
250 const io = args.io;
232251
233252 // Detect infinite loops.
234253 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
......@@ -326,7 +345,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
326345
327346 else => return error.FileSystem,
328347 };
329 defer search_dir.close();
348 defer search_dir.close(io);
330349
331350 if (self.include_dir == null) {
332351 if (search_dir.access(include_dir_example_file, .{})) |_| {
......@@ -361,6 +380,7 @@ fn findNativeIncludeDirWindows(
361380 sdk: std.zig.WindowsSdk,
362381) FindError!void {
363382 const allocator = args.allocator;
383 const io = args.io;
364384
365385 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
366386 const installs = fillInstallations(&install_buf, sdk);
......@@ -380,7 +400,7 @@ fn findNativeIncludeDirWindows(
380400
381401 else => return error.FileSystem,
382402 };
383 defer dir.close();
403 defer dir.close(io);
384404
385405 dir.access("stdlib.h", .{}) catch |err| switch (err) {
386406 error.FileNotFound => continue,
......@@ -400,6 +420,7 @@ fn findNativeCrtDirWindows(
400420 sdk: std.zig.WindowsSdk,
401421) FindError!void {
402422 const allocator = args.allocator;
423 const io = args.io;
403424
404425 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
405426 const installs = fillInstallations(&install_buf, sdk);
......@@ -427,7 +448,7 @@ fn findNativeCrtDirWindows(
427448
428449 else => return error.FileSystem,
429450 };
430 defer dir.close();
451 defer dir.close(io);
431452
432453 dir.access("ucrt.lib", .{}) catch |err| switch (err) {
433454 error.FileNotFound => continue,
......@@ -467,6 +488,7 @@ fn findNativeKernel32LibDir(
467488 sdk: std.zig.WindowsSdk,
468489) FindError!void {
469490 const allocator = args.allocator;
491 const io = args.io;
470492
471493 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
472494 const installs = fillInstallations(&install_buf, sdk);
......@@ -494,7 +516,7 @@ fn findNativeKernel32LibDir(
494516
495517 else => return error.FileSystem,
496518 };
497 defer dir.close();
519 defer dir.close(io);
498520
499521 dir.access("kernel32.lib", .{}) catch |err| switch (err) {
500522 error.FileNotFound => continue,
......@@ -513,6 +535,7 @@ fn findNativeMsvcIncludeDir(
513535 sdk: std.zig.WindowsSdk,
514536) FindError!void {
515537 const allocator = args.allocator;
538 const io = args.io;
516539
517540 const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCStdLibHeaderNotFound;
518541 const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound;
......@@ -529,7 +552,7 @@ fn findNativeMsvcIncludeDir(
529552
530553 else => return error.FileSystem,
531554 };
532 defer dir.close();
555 defer dir.close(io);
533556
534557 dir.access("vcruntime.h", .{}) catch |err| switch (err) {
535558 error.FileNotFound => return error.LibCStdLibHeaderNotFound,
......@@ -1015,17 +1038,3 @@ pub fn resolveCrtPaths(
10151038 },
10161039 }
10171040}
1018
1019const LibCInstallation = @This();
1020const std = @import("std");
1021const builtin = @import("builtin");
1022const Target = std.Target;
1023const fs = std.fs;
1024const Allocator = std.mem.Allocator;
1025const Path = std.Build.Cache.Path;
1026
1027const is_darwin = builtin.target.os.tag.isDarwin();
1028const is_windows = builtin.target.os.tag == .windows;
1029const is_haiku = builtin.target.os.tag == .haiku;
1030
1031const log = std.log.scoped(.libc_installation);
lib/std/zig/WindowsSdk.zig+38-29
......@@ -1,7 +1,10 @@
11const WindowsSdk = @This();
22const builtin = @import("builtin");
3
34const std = @import("std");
5const Io = std.Io;
46const Writer = std.Io.Writer;
7const Allocator = std.mem.Allocator;
58
69windows10sdk: ?Installation,
710windows81sdk: ?Installation,
......@@ -20,7 +23,7 @@ const product_version_max_length = version_major_minor_max_length + ".65535".len
2023/// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory.
2124/// Caller owns the result's fields.
2225/// After finishing work, call `free(allocator)`.
23pub fn find(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk {
26pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk {
2427 if (builtin.os.tag != .windows) return error.NotFound;
2528
2629 //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed
......@@ -58,7 +61,7 @@ pub fn find(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutO
5861 };
5962}
6063
61pub fn free(sdk: WindowsSdk, allocator: std.mem.Allocator) void {
64pub fn free(sdk: WindowsSdk, allocator: Allocator) void {
6265 if (sdk.windows10sdk) |*w10sdk| {
6366 w10sdk.free(allocator);
6467 }
......@@ -75,7 +78,7 @@ pub fn free(sdk: WindowsSdk, allocator: std.mem.Allocator) void {
7578/// Caller owns result.
7679fn iterateAndFilterByVersion(
7780 iterator: *std.fs.Dir.Iterator,
78 allocator: std.mem.Allocator,
81 allocator: Allocator,
7982 prefix: []const u8,
8083) error{OutOfMemory}![][]const u8 {
8184 const Version = struct {
......@@ -174,7 +177,7 @@ const RegistryWtf8 = struct {
174177
175178 /// Get string from registry.
176179 /// Caller owns result.
177 pub fn getString(reg: RegistryWtf8, allocator: std.mem.Allocator, subkey: []const u8, value_name: []const u8) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]u8 {
180 pub fn getString(reg: RegistryWtf8, allocator: Allocator, subkey: []const u8, value_name: []const u8) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]u8 {
178181 const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: {
179182 var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined;
180183 const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable;
......@@ -282,7 +285,7 @@ const RegistryWtf16Le = struct {
282285 }
283286
284287 /// Get string ([:0]const u16) from registry.
285 fn getString(reg: RegistryWtf16Le, allocator: std.mem.Allocator, subkey_wtf16le: [:0]const u16, value_name_wtf16le: [:0]const u16) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]const u16 {
288 fn getString(reg: RegistryWtf16Le, allocator: Allocator, subkey_wtf16le: [:0]const u16, value_name_wtf16le: [:0]const u16) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]const u16 {
286289 var actual_type: windows.ULONG = undefined;
287290
288291 // Calculating length to allocate
......@@ -416,7 +419,7 @@ pub const Installation = struct {
416419 /// Caller owns the result's fields.
417420 /// After finishing work, call `free(allocator)`.
418421 fn find(
419 allocator: std.mem.Allocator,
422 allocator: Allocator,
420423 roots_key: RegistryWtf8,
421424 roots_subkey: []const u8,
422425 prefix: []const u8,
......@@ -437,7 +440,8 @@ pub const Installation = struct {
437440 }
438441
439442 fn findFromRoot(
440 allocator: std.mem.Allocator,
443 allocator: Allocator,
444 io: Io,
441445 roots_key: RegistryWtf8,
442446 roots_subkey: []const u8,
443447 prefix: []const u8,
......@@ -478,7 +482,7 @@ pub const Installation = struct {
478482 error.NameTooLong => return error.PathTooLong,
479483 else => return error.InstallationNotFound,
480484 };
481 defer sdk_lib_dir.close();
485 defer sdk_lib_dir.close(io);
482486
483487 var iterator = sdk_lib_dir.iterate();
484488 const versions = try iterateAndFilterByVersion(&iterator, allocator, prefix);
......@@ -495,7 +499,7 @@ pub const Installation = struct {
495499 }
496500
497501 fn findFromInstallationFolder(
498 allocator: std.mem.Allocator,
502 allocator: Allocator,
499503 version_key_name: []const u8,
500504 ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation {
501505 var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined;
......@@ -597,14 +601,14 @@ pub const Installation = struct {
597601 return (reg_value == 1);
598602 }
599603
600 fn free(install: Installation, allocator: std.mem.Allocator) void {
604 fn free(install: Installation, allocator: Allocator) void {
601605 allocator.free(install.path);
602606 allocator.free(install.version);
603607 }
604608};
605609
606610const MsvcLibDir = struct {
607 fn findInstancesDirViaSetup(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
611 fn findInstancesDirViaSetup(allocator: Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
608612 const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup";
609613 const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) {
610614 error.KeyNotFound => return error.PathNotFound,
......@@ -629,7 +633,7 @@ const MsvcLibDir = struct {
629633 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
630634 }
631635
632 fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
636 fn findInstancesDirViaCLSID(allocator: Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
633637 const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";
634638 const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) {
635639 error.KeyNotFound => return error.PathNotFound,
......@@ -665,7 +669,7 @@ const MsvcLibDir = struct {
665669 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
666670 }
667671
668 fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
672 fn findInstancesDir(allocator: Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
669673 // First, try getting the packages cache path from the registry.
670674 // This only seems to exist when the path is different from the default.
671675 method1: {
......@@ -748,13 +752,13 @@ const MsvcLibDir = struct {
748752 ///
749753 /// The logic in this function is intended to match what ISetupConfiguration does
750754 /// under-the-hood, as verified using Procmon.
751 fn findViaCOM(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
755 fn findViaCOM(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
752756 // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances`
753757 // This will contain directories with names of instance IDs like 80a758ca,
754758 // which will contain `state.json` files that have the version and
755759 // installation directory.
756760 var instances_dir = try findInstancesDir(allocator);
757 defer instances_dir.close();
761 defer instances_dir.close(io);
758762
759763 var state_subpath_buf: [std.fs.max_name_bytes + 32]u8 = undefined;
760764 var latest_version_lib_dir: std.ArrayList(u8) = .empty;
......@@ -791,7 +795,7 @@ const MsvcLibDir = struct {
791795 const installation_path = parsed.value.object.get("installationPath") orelse continue;
792796 if (installation_path != .string) continue;
793797
794 const lib_dir_path = libDirFromInstallationPath(allocator, installation_path.string, arch) catch |err| switch (err) {
798 const lib_dir_path = libDirFromInstallationPath(allocator, io, installation_path.string, arch) catch |err| switch (err) {
795799 error.OutOfMemory => |e| return e,
796800 error.PathNotFound => continue,
797801 };
......@@ -806,7 +810,12 @@ const MsvcLibDir = struct {
806810 return latest_version_lib_dir.toOwnedSlice(allocator);
807811 }
808812
809 fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path: []const u8, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
813 fn libDirFromInstallationPath(
814 allocator: Allocator,
815 io: Io,
816 installation_path: []const u8,
817 arch: std.Target.Cpu.Arch,
818 ) error{ OutOfMemory, PathNotFound }![]const u8 {
810819 var lib_dir_buf = try std.array_list.Managed(u8).initCapacity(allocator, installation_path.len + 64);
811820 errdefer lib_dir_buf.deinit();
812821
......@@ -837,7 +846,7 @@ const MsvcLibDir = struct {
837846 else => unreachable,
838847 });
839848
840 if (!verifyLibDir(lib_dir_buf.items)) {
849 if (!verifyLibDir(io, lib_dir_buf.items)) {
841850 return error.PathNotFound;
842851 }
843852
......@@ -845,7 +854,7 @@ const MsvcLibDir = struct {
845854 }
846855
847856 // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#editing-the-registry-for-a-visual-studio-instance
848 fn findViaRegistry(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
857 fn findViaRegistry(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
849858
850859 // %localappdata%\Microsoft\VisualStudio\
851860 // %appdata%\Local\Microsoft\VisualStudio\
......@@ -859,7 +868,7 @@ const MsvcLibDir = struct {
859868 var visualstudio_folder = std.fs.openDirAbsolute(visualstudio_folder_path, .{
860869 .iterate = true,
861870 }) catch return error.PathNotFound;
862 defer visualstudio_folder.close();
871 defer visualstudio_folder.close(io);
863872
864873 var iterator = visualstudio_folder.iterate();
865874 break :vs_versions try iterateAndFilterByVersion(&iterator, allocator, "");
......@@ -926,14 +935,14 @@ const MsvcLibDir = struct {
926935 };
927936 errdefer allocator.free(msvc_dir);
928937
929 if (!verifyLibDir(msvc_dir)) {
938 if (!verifyLibDir(io, msvc_dir)) {
930939 return error.PathNotFound;
931940 }
932941
933942 return msvc_dir;
934943 }
935944
936 fn findViaVs7Key(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
945 fn findViaVs7Key(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
937946 var base_path: std.array_list.Managed(u8) = base_path: {
938947 try_env: {
939948 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
......@@ -989,7 +998,7 @@ const MsvcLibDir = struct {
989998 else => unreachable,
990999 });
9911000
992 if (!verifyLibDir(base_path.items)) {
1001 if (!verifyLibDir(io, base_path.items)) {
9931002 return error.PathNotFound;
9941003 }
9951004
......@@ -997,11 +1006,11 @@ const MsvcLibDir = struct {
9971006 return full_path;
9981007 }
9991008
1000 fn verifyLibDir(lib_dir_path: []const u8) bool {
1009 fn verifyLibDir(io: Io, lib_dir_path: []const u8) bool {
10011010 std.debug.assert(std.fs.path.isAbsolute(lib_dir_path)); // should be already handled in `findVia*`
10021011
10031012 var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false;
1004 defer dir.close();
1013 defer dir.close(io);
10051014
10061015 const stat = dir.statFile("vcruntime.lib") catch return false;
10071016 if (stat.kind != .file)
......@@ -1012,12 +1021,12 @@ const MsvcLibDir = struct {
10121021
10131022 /// Find path to MSVC's `lib/` directory.
10141023 /// Caller owns the result.
1015 pub fn find(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 {
1016 const full_path = MsvcLibDir.findViaCOM(allocator, arch) catch |err1| switch (err1) {
1024 pub fn find(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 {
1025 const full_path = MsvcLibDir.findViaCOM(allocator, io, arch) catch |err1| switch (err1) {
10171026 error.OutOfMemory => return error.OutOfMemory,
1018 error.PathNotFound => MsvcLibDir.findViaRegistry(allocator, arch) catch |err2| switch (err2) {
1027 error.PathNotFound => MsvcLibDir.findViaRegistry(allocator, io, arch) catch |err2| switch (err2) {
10191028 error.OutOfMemory => return error.OutOfMemory,
1020 error.PathNotFound => MsvcLibDir.findViaVs7Key(allocator, arch) catch |err3| switch (err3) {
1029 error.PathNotFound => MsvcLibDir.findViaVs7Key(allocator, io, arch) catch |err3| switch (err3) {
10211030 error.OutOfMemory => return error.OutOfMemory,
10221031 error.PathNotFound => return error.MsvcLibDirNotFound,
10231032 },
lib/std/zig/llvm/Builder.zig+11-8
......@@ -1,14 +1,17 @@
1const builtin = @import("builtin");
2const Builder = @This();
3
14const std = @import("../../std.zig");
5const Io = std.Io;
26const Allocator = std.mem.Allocator;
37const assert = std.debug.assert;
4const bitcode_writer = @import("bitcode_writer.zig");
5const Builder = @This();
6const builtin = @import("builtin");
78const DW = std.dwarf;
8const ir = @import("ir.zig");
99const log = std.log.scoped(.llvm);
1010const Writer = std.Io.Writer;
1111
12const bitcode_writer = @import("bitcode_writer.zig");
13const ir = @import("ir.zig");
14
1215gpa: Allocator,
1316strip: bool,
1417
......@@ -9579,11 +9582,11 @@ pub fn dump(b: *Builder) void {
95799582 b.printToFile(stderr, &buffer) catch {};
95809583}
95819584
9582pub fn printToFilePath(b: *Builder, dir: std.fs.Dir, path: []const u8) !void {
9585pub fn printToFilePath(b: *Builder, io: Io, dir: std.fs.Dir, path: []const u8) !void {
95839586 var buffer: [4000]u8 = undefined;
9584 const file = try dir.createFile(path, .{});
9585 defer file.close();
9586 try b.printToFile(file, &buffer);
9587 const file = try dir.createFile(io, path, .{});
9588 defer file.close(io);
9589 try b.printToFile(io, file, &buffer);
95879590}
95889591
95899592pub fn printToFile(b: *Builder, file: std.fs.File, buffer: []u8) !void {
lib/std/zig/system.zig+2-2
......@@ -847,7 +847,7 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {
847847 error.Unexpected => |e| return e,
848848 error.Canceled => |e| return e,
849849 };
850 defer file.close();
850 defer file.close(io);
851851
852852 // Empirically, glibc 2.34 libc.so .dynstr section is 32441 bytes on my system.
853853 var buffer: [8000]u8 = undefined;
......@@ -1051,7 +1051,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
10511051 else => |e| return e,
10521052 };
10531053 var is_elf_file = false;
1054 defer if (!is_elf_file) file.close();
1054 defer if (!is_elf_file) file.close(io);
10551055
10561056 file_reader = .initAdapted(file, io, &file_reader_buffer);
10571057 file_name = undefined; // it aliases file_reader_buffer
lib/std/zig/system/linux.zig+1-1
......@@ -447,7 +447,7 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
447447 var file = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) {
448448 else => return null,
449449 };
450 defer file.close();
450 defer file.close(io);
451451
452452 var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long.
453453 var file_reader = file.reader(io, &buffer);
lib/std/zip.zig+4-2
......@@ -554,17 +554,19 @@ pub const Iterator = struct {
554554 return;
555555 }
556556
557 const io = stream.io;
558
557559 const out_file = blk: {
558560 if (std.fs.path.dirname(filename)) |dirname| {
559561 var parent_dir = try dest.makeOpenPath(dirname, .{});
560 defer parent_dir.close();
562 defer parent_dir.close(io);
561563
562564 const basename = std.fs.path.basename(filename);
563565 break :blk try parent_dir.createFile(basename, .{ .exclusive = true });
564566 }
565567 break :blk try dest.createFile(filename, .{ .exclusive = true });
566568 };
567 defer out_file.close();
569 defer out_file.close(io);
568570 var out_file_buffer: [1024]u8 = undefined;
569571 var file_writer = out_file.writer(&out_file_buffer);
570572 const local_data_file_offset: u64 =
src/Compilation.zig+34-30
......@@ -721,13 +721,13 @@ pub const Directories = struct {
721721 /// This may be the same as `global_cache`.
722722 local_cache: Cache.Directory,
723723
724 pub fn deinit(dirs: *Directories) void {
724 pub fn deinit(dirs: *Directories, io: Io) void {
725725 // The local and global caches could be the same.
726726 const close_local = dirs.local_cache.handle.fd != dirs.global_cache.handle.fd;
727727
728 dirs.global_cache.handle.close();
729 if (close_local) dirs.local_cache.handle.close();
730 dirs.zig_lib.handle.close();
728 dirs.global_cache.handle.close(io);
729 if (close_local) dirs.local_cache.handle.close(io);
730 dirs.zig_lib.handle.close(io);
731731 }
732732
733733 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for
......@@ -1105,7 +1105,7 @@ pub const CObject = struct {
11051105 if (diag.src_loc.offset == 0 or diag.src_loc.column == 0) break :source_line 0;
11061106
11071107 const file = fs.cwd().openFile(file_name, .{}) catch break :source_line 0;
1108 defer file.close();
1108 defer file.close(io);
11091109 var buffer: [1024]u8 = undefined;
11101110 var file_reader = file.reader(io, &buffer);
11111111 file_reader.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0;
......@@ -1180,7 +1180,7 @@ pub const CObject = struct {
11801180
11811181 var buffer: [1024]u8 = undefined;
11821182 const file = try fs.cwd().openFile(path, .{});
1183 defer file.close();
1183 defer file.close(io);
11841184 var file_reader = file.reader(io, &buffer);
11851185 var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = &file_reader.interface });
11861186 defer bc.deinit();
......@@ -1617,13 +1617,13 @@ const CacheUse = union(CacheMode) {
16171617 }
16181618 };
16191619
1620 fn deinit(cu: CacheUse) void {
1620 fn deinit(cu: CacheUse, io: Io) void {
16211621 switch (cu) {
16221622 .none => |none| {
16231623 assert(none.tmp_artifact_directory == null);
16241624 },
16251625 .incremental => |incremental| {
1626 incremental.artifact_directory.handle.close();
1626 incremental.artifact_directory.handle.close(io);
16271627 },
16281628 .whole => |whole| {
16291629 assert(whole.tmp_artifact_directory == null);
......@@ -2113,7 +2113,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
21132113 cache.addPrefix(options.dirs.zig_lib);
21142114 cache.addPrefix(options.dirs.local_cache);
21152115 cache.addPrefix(options.dirs.global_cache);
2116 errdefer cache.manifest_dir.close();
2116 errdefer cache.manifest_dir.close(io);
21172117
21182118 // This is shared hasher state common to zig source and all C source files.
21192119 cache.hash.addBytes(build_options.version);
......@@ -2157,7 +2157,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
21572157 var local_zir_dir = options.dirs.local_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {
21582158 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = zir_sub_dir, .err = err } });
21592159 };
2160 errdefer local_zir_dir.close();
2160 errdefer local_zir_dir.close(io);
21612161 const local_zir_cache: Cache.Directory = .{
21622162 .handle = local_zir_dir,
21632163 .path = try options.dirs.local_cache.join(arena, &.{zir_sub_dir}),
......@@ -2165,7 +2165,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
21652165 var global_zir_dir = options.dirs.global_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {
21662166 return diag.fail(.{ .create_cache_path = .{ .which = .global, .sub = zir_sub_dir, .err = err } });
21672167 };
2168 errdefer global_zir_dir.close();
2168 errdefer global_zir_dir.close(io);
21692169 const global_zir_cache: Cache.Directory = .{
21702170 .handle = global_zir_dir,
21712171 .path = try options.dirs.global_cache.join(arena, &.{zir_sub_dir}),
......@@ -2436,7 +2436,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
24362436 var artifact_dir = options.dirs.local_cache.handle.makeOpenPath(artifact_sub_dir, .{}) catch |err| {
24372437 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = artifact_sub_dir, .err = err } });
24382438 };
2439 errdefer artifact_dir.close();
2439 errdefer artifact_dir.close(io);
24402440 const artifact_directory: Cache.Directory = .{
24412441 .handle = artifact_dir,
24422442 .path = try options.dirs.local_cache.join(arena, &.{artifact_sub_dir}),
......@@ -2689,6 +2689,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
26892689
26902690pub fn destroy(comp: *Compilation) void {
26912691 const gpa = comp.gpa;
2692 const io = comp.io;
26922693
26932694 if (comp.bin_file) |lf| lf.destroy();
26942695 if (comp.zcu) |zcu| zcu.deinit();
......@@ -2760,7 +2761,7 @@ pub fn destroy(comp: *Compilation) void {
27602761
27612762 comp.clearMiscFailures();
27622763
2763 comp.cache_parent.manifest_dir.close();
2764 comp.cache_parent.manifest_dir.close(io);
27642765}
27652766
27662767pub fn clearMiscFailures(comp: *Compilation) void {
......@@ -2791,10 +2792,12 @@ pub fn hotCodeSwap(
27912792}
27922793
27932794fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2795 const io = comp.io;
2796
27942797 switch (comp.cache_use) {
27952798 .none => |none| {
27962799 if (none.tmp_artifact_directory) |*tmp_dir| {
2797 tmp_dir.handle.close();
2800 tmp_dir.handle.close(io);
27982801 none.tmp_artifact_directory = null;
27992802 if (dev.env == .bootstrap) {
28002803 // zig1 uses `CacheMode.none`, but it doesn't need to know how to delete
......@@ -2834,7 +2837,7 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
28342837 comp.bin_file = null;
28352838 }
28362839 if (whole.tmp_artifact_directory) |*tmp_dir| {
2837 tmp_dir.handle.close();
2840 tmp_dir.handle.close(io);
28382841 whole.tmp_artifact_directory = null;
28392842 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
28402843 comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| {
......@@ -3152,7 +3155,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
31523155 // the file handle and re-open it in the follow up call to
31533156 // `makeWritable`.
31543157 if (lf.file) |f| {
3155 f.close();
3158 f.close(io);
31563159 lf.file = null;
31573160
31583161 if (lf.closeDebugInfo()) break :w .lf_and_debug;
......@@ -3165,7 +3168,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
31653168
31663169 // Rename the temporary directory into place.
31673170 // Close tmp dir and link.File to avoid open handle during rename.
3168 whole.tmp_artifact_directory.?.handle.close();
3171 whole.tmp_artifact_directory.?.handle.close(io);
31693172 whole.tmp_artifact_directory = null;
31703173 const s = fs.path.sep_str;
31713174 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
......@@ -5258,6 +5261,7 @@ fn workerDocsCopy(comp: *Compilation) void {
52585261
52595262fn docsCopyFallible(comp: *Compilation) anyerror!void {
52605263 const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});
5264 const io = comp.io;
52615265
52625266 const docs_path = comp.resolveEmitPath(comp.emit_docs.?);
52635267 var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| {
......@@ -5267,7 +5271,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
52675271 .{ docs_path, @errorName(err) },
52685272 );
52695273 };
5270 defer out_dir.close();
5274 defer out_dir.close(io);
52715275
52725276 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
52735277 const basename = fs.path.basename(sub_path);
......@@ -5287,7 +5291,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
52875291 .{ docs_path, @errorName(err) },
52885292 );
52895293 };
5290 defer tar_file.close();
5294 defer tar_file.close(io);
52915295
52925296 var buffer: [1024]u8 = undefined;
52935297 var tar_file_writer = tar_file.writer(&buffer);
......@@ -5331,7 +5335,7 @@ fn docsCopyModule(
53315335 } catch |err| {
53325336 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err });
53335337 };
5334 defer mod_dir.close();
5338 defer mod_dir.close(io);
53355339
53365340 var walker = try mod_dir.walk(comp.gpa);
53375341 defer walker.deinit();
......@@ -5355,7 +5359,7 @@ fn docsCopyModule(
53555359 root.fmt(comp), entry.path, err,
53565360 });
53575361 };
5358 defer file.close();
5362 defer file.close(io);
53595363 const stat = try file.stat();
53605364 var file_reader: fs.File.Reader = .initSize(file.adaptToNewApi(), io, &buffer, stat.size);
53615365
......@@ -5510,7 +5514,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
55105514 );
55115515 return error.AlreadyReported;
55125516 };
5513 defer out_dir.close();
5517 defer out_dir.close(io);
55145518
55155519 crt_file.full_object_path.root_dir.handle.copyFile(
55165520 crt_file.full_object_path.sub_path,
......@@ -5693,7 +5697,7 @@ pub fn translateC(
56935697 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename;
56945698 const cache_dir = comp.dirs.local_cache.handle;
56955699 var cache_tmp_dir = try cache_dir.makeOpenPath(tmp_sub_path, .{});
5696 defer cache_tmp_dir.close();
5700 defer cache_tmp_dir.close(io);
56975701
56985702 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename });
56995703 const source_path = switch (source) {
......@@ -6268,7 +6272,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
62686272 // so we need a temporary filename.
62696273 const out_obj_path = try comp.tmpFilePath(arena, o_basename);
62706274 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
6271 defer zig_cache_tmp_dir.close();
6275 defer zig_cache_tmp_dir.close(io);
62726276
62736277 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics())
62746278 null
......@@ -6433,7 +6437,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
64336437 const digest = man.final();
64346438 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
64356439 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
6436 defer o_dir.close();
6440 defer o_dir.close(io);
64376441 const tmp_basename = fs.path.basename(out_obj_path);
64386442 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
64396443 break :blk digest;
......@@ -6477,8 +6481,6 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
64776481 const tracy_trace = trace(@src());
64786482 defer tracy_trace.end();
64796483
6480 const io = comp.io;
6481
64826484 const src_path = switch (win32_resource.src) {
64836485 .rc => |rc_src| rc_src.src_path,
64846486 .manifest => |src_path| src_path,
......@@ -6487,6 +6489,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
64876489
64886490 log.debug("updating win32 resource: {s}", .{src_path});
64896491
6492 const io = comp.io;
6493
64906494 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
64916495 defer arena_allocator.deinit();
64926496 const arena = arena_allocator.allocator();
......@@ -6522,7 +6526,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
65226526
65236527 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });
65246528 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
6525 defer o_dir.close();
6529 defer o_dir.close(io);
65266530
65276531 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{
65286532 o_sub_path, rc_basename,
......@@ -6610,7 +6614,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
66106614
66116615 const digest = if (try man.hit()) man.final() else blk: {
66126616 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
6613 defer zig_cache_tmp_dir.close();
6617 defer zig_cache_tmp_dir.close(io);
66146618
66156619 const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext});
66166620
......@@ -6681,7 +6685,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
66816685 const digest = man.final();
66826686 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
66836687 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
6684 defer o_dir.close();
6688 defer o_dir.close(io);
66856689 const tmp_basename = fs.path.basename(out_res_path);
66866690 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
66876691 break :blk digest;
src/Package/Fetch.zig+38-34
......@@ -513,7 +513,7 @@ fn runResource(
513513 break :handle dir;
514514 },
515515 };
516 defer tmp_directory.handle.close();
516 defer tmp_directory.handle.close(io);
517517
518518 // Fetch and unpack a resource into a temporary directory.
519519 var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);
......@@ -523,7 +523,7 @@ fn runResource(
523523 // Apply btrfs workaround if needed. Reopen tmp_directory.
524524 if (native_os == .linux and f.job_queue.work_around_btrfs_bug) {
525525 // https://github.com/ziglang/zig/issues/17095
526 pkg_path.root_dir.handle.close();
526 pkg_path.root_dir.handle.close(io);
527527 pkg_path.root_dir.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{
528528 .iterate = true,
529529 }) catch @panic("btrfs workaround failed");
......@@ -885,7 +885,7 @@ const Resource = union(enum) {
885885 file: fs.File.Reader,
886886 http_request: HttpRequest,
887887 git: Git,
888 dir: fs.Dir,
888 dir: Io.Dir,
889889
890890 const Git = struct {
891891 session: git.Session,
......@@ -908,7 +908,7 @@ const Resource = union(enum) {
908908 .git => |*git_resource| {
909909 git_resource.fetch_stream.deinit();
910910 },
911 .dir => |*dir| dir.close(),
911 .dir => |*dir| dir.close(io),
912912 }
913913 resource.* = undefined;
914914 }
......@@ -1247,13 +1247,14 @@ fn unpackResource(
12471247 }
12481248}
12491249
1250fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *Io.Reader) RunError!UnpackResult {
1250fn unpackTarball(f: *Fetch, out_dir: Io.Dir, reader: *Io.Reader) RunError!UnpackResult {
12511251 const eb = &f.error_bundle;
12521252 const arena = f.arena.allocator();
1253 const io = f.job_queue.io;
12531254
12541255 var diagnostics: std.tar.Diagnostics = .{ .allocator = arena };
12551256
1256 std.tar.pipeToFileSystem(out_dir, reader, .{
1257 std.tar.pipeToFileSystem(io, out_dir, reader, .{
12571258 .diagnostics = &diagnostics,
12581259 .strip_components = 0,
12591260 .mode_mode = .ignore,
......@@ -1280,7 +1281,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *Io.Reader) RunError!Unpack
12801281
12811282fn unzip(
12821283 f: *Fetch,
1283 out_dir: fs.Dir,
1284 out_dir: Io.Dir,
12841285 reader: *Io.Reader,
12851286) error{ ReadFailed, OutOfMemory, Canceled, FetchFailed }!UnpackResult {
12861287 // We write the entire contents to a file first because zip files
......@@ -1314,7 +1315,7 @@ fn unzip(
13141315 ),
13151316 };
13161317 };
1317 defer zip_file.close();
1318 defer zip_file.close(io);
13181319 var zip_file_buffer: [4096]u8 = undefined;
13191320 var zip_file_reader = b: {
13201321 var zip_file_writer = zip_file.writer(&zip_file_buffer);
......@@ -1349,7 +1350,7 @@ fn unzip(
13491350 return .{ .root_dir = diagnostics.root_dir };
13501351}
13511352
1352fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!UnpackResult {
1353fn unpackGitPack(f: *Fetch, out_dir: Io.Dir, resource: *Resource.Git) anyerror!UnpackResult {
13531354 const io = f.job_queue.io;
13541355 const arena = f.arena.allocator();
13551356 // TODO don't try to get a gpa from an arena. expose this dependency higher up
......@@ -1363,9 +1364,9 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
13631364 // directory, since that isn't relevant for fetching a package.
13641365 {
13651366 var pack_dir = try out_dir.makeOpenPath(".git", .{});
1366 defer pack_dir.close();
1367 defer pack_dir.close(io);
13671368 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
1368 defer pack_file.close();
1369 defer pack_file.close(io);
13691370 var pack_file_buffer: [4096]u8 = undefined;
13701371 var pack_file_reader = b: {
13711372 var pack_file_writer = pack_file.writer(&pack_file_buffer);
......@@ -1376,7 +1377,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
13761377 };
13771378
13781379 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
1379 defer index_file.close();
1380 defer index_file.close(io);
13801381 var index_file_buffer: [2000]u8 = undefined;
13811382 var index_file_writer = index_file.writer(&index_file_buffer);
13821383 {
......@@ -1393,7 +1394,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
13931394 try repository.init(gpa, object_format, &pack_file_reader, &index_file_reader);
13941395 defer repository.deinit();
13951396 var diagnostics: git.Diagnostics = .{ .allocator = arena };
1396 try repository.checkout(out_dir, resource.want_oid, &diagnostics);
1397 try repository.checkout(io, out_dir, resource.want_oid, &diagnostics);
13971398
13981399 if (diagnostics.errors.items.len > 0) {
13991400 try res.allocErrors(arena, diagnostics.errors.items.len, "unable to unpack packfile");
......@@ -1411,7 +1412,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
14111412 return res;
14121413}
14131414
1414fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void {
1415fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void {
14151416 const gpa = f.arena.child_allocator;
14161417 // Recursive directory copy.
14171418 var it = try dir.walk(gpa);
......@@ -1451,7 +1452,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void
14511452 }
14521453}
14531454
1454pub fn renameTmpIntoCache(cache_dir: fs.Dir, tmp_dir_sub_path: []const u8, dest_dir_sub_path: []const u8) !void {
1455pub fn renameTmpIntoCache(cache_dir: Io.Dir, tmp_dir_sub_path: []const u8, dest_dir_sub_path: []const u8) !void {
14551456 assert(dest_dir_sub_path[1] == fs.path.sep);
14561457 var handled_missing_dir = false;
14571458 while (true) {
......@@ -1660,15 +1661,15 @@ fn dumpHashInfo(all_files: []const *const HashedFile) !void {
16601661 try w.flush();
16611662}
16621663
1663fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile) void {
1664fn workerHashFile(dir: Io.Dir, hashed_file: *HashedFile) void {
16641665 hashed_file.failure = hashFileFallible(dir, hashed_file);
16651666}
16661667
1667fn workerDeleteFile(dir: fs.Dir, deleted_file: *DeletedFile) void {
1668fn workerDeleteFile(dir: Io.Dir, deleted_file: *DeletedFile) void {
16681669 deleted_file.failure = deleteFileFallible(dir, deleted_file);
16691670}
16701671
1671fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
1672fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
16721673 var buf: [8000]u8 = undefined;
16731674 var hasher = Package.Hash.Algo.init(.{});
16741675 hasher.update(hashed_file.normalized_path);
......@@ -1677,7 +1678,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
16771678 switch (hashed_file.kind) {
16781679 .file => {
16791680 var file = try dir.openFile(hashed_file.fs_path, .{});
1680 defer file.close();
1681 defer file.close(io);
16811682 // Hard-coded false executable bit: https://github.com/ziglang/zig/issues/17463
16821683 hasher.update(&.{ 0, 0 });
16831684 var file_header: FileHeader = .{};
......@@ -1707,7 +1708,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
17071708 hashed_file.size = file_size;
17081709}
17091710
1710fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {
1711fn deleteFileFallible(dir: Io.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {
17111712 try dir.deleteFile(deleted_file.fs_path);
17121713}
17131714
......@@ -1724,8 +1725,8 @@ const DeletedFile = struct {
17241725 failure: Error!void,
17251726
17261727 const Error =
1727 fs.Dir.DeleteFileError ||
1728 fs.Dir.DeleteDirError;
1728 Io.Dir.DeleteFileError ||
1729 Io.Dir.DeleteDirError;
17291730};
17301731
17311732const HashedFile = struct {
......@@ -1741,7 +1742,7 @@ const HashedFile = struct {
17411742 fs.File.ReadError ||
17421743 fs.File.StatError ||
17431744 fs.File.ChmodError ||
1744 fs.Dir.ReadLinkError;
1745 Io.Dir.ReadLinkError;
17451746
17461747 const Kind = enum { file, link };
17471748
......@@ -2074,7 +2075,7 @@ test "tarball with duplicate paths" {
20742075 defer tmp.cleanup();
20752076
20762077 const tarball_name = "duplicate_paths.tar.gz";
2077 try saveEmbedFile(tarball_name, tmp.dir);
2078 try saveEmbedFile(io, tarball_name, tmp.dir);
20782079 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
20792080 defer gpa.free(tarball_path);
20802081
......@@ -2107,7 +2108,7 @@ test "tarball with excluded duplicate paths" {
21072108 defer tmp.cleanup();
21082109
21092110 const tarball_name = "duplicate_paths_excluded.tar.gz";
2110 try saveEmbedFile(tarball_name, tmp.dir);
2111 try saveEmbedFile(io, tarball_name, tmp.dir);
21112112 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
21122113 defer gpa.free(tarball_path);
21132114
......@@ -2153,7 +2154,7 @@ test "tarball without root folder" {
21532154 defer tmp.cleanup();
21542155
21552156 const tarball_name = "no_root.tar.gz";
2156 try saveEmbedFile(tarball_name, tmp.dir);
2157 try saveEmbedFile(io, tarball_name, tmp.dir);
21572158 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
21582159 defer gpa.free(tarball_path);
21592160
......@@ -2186,7 +2187,7 @@ test "set executable bit based on file content" {
21862187 defer tmp.cleanup();
21872188
21882189 const tarball_name = "executables.tar.gz";
2189 try saveEmbedFile(tarball_name, tmp.dir);
2190 try saveEmbedFile(io, tarball_name, tmp.dir);
21902191 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
21912192 defer gpa.free(tarball_path);
21922193
......@@ -2210,7 +2211,7 @@ test "set executable bit based on file content" {
22102211 );
22112212
22122213 var out = try fb.packageDir();
2213 defer out.close();
2214 defer out.close(io);
22142215 const S = std.posix.S;
22152216 // expect executable bit not set
22162217 try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0);
......@@ -2231,11 +2232,11 @@ test "set executable bit based on file content" {
22312232 // -rwxrwxr-x 1 17 Apr script_with_shebang_without_exec_bit
22322233}
22332234
2234fn saveEmbedFile(comptime tarball_name: []const u8, dir: fs.Dir) !void {
2235fn saveEmbedFile(io: Io, comptime tarball_name: []const u8, dir: Io.Dir) !void {
22352236 //const tarball_name = "duplicate_paths_excluded.tar.gz";
22362237 const tarball_content = @embedFile("Fetch/testdata/" ++ tarball_name);
22372238 var tmp_file = try dir.createFile(tarball_name, .{});
2238 defer tmp_file.close();
2239 defer tmp_file.close(io);
22392240 try tmp_file.writeAll(tarball_content);
22402241}
22412242
......@@ -2250,7 +2251,7 @@ const TestFetchBuilder = struct {
22502251 self: *TestFetchBuilder,
22512252 allocator: std.mem.Allocator,
22522253 io: Io,
2253 cache_parent_dir: std.fs.Dir,
2254 cache_parent_dir: std.Io.Dir,
22542255 path_or_url: []const u8,
22552256 ) !*Fetch {
22562257 const cache_dir = try cache_parent_dir.makeOpenPath("zig-global-cache", .{});
......@@ -2301,14 +2302,15 @@ const TestFetchBuilder = struct {
23012302 }
23022303
23032304 fn deinit(self: *TestFetchBuilder) void {
2305 const io = self.job_queue.io;
23042306 self.fetch.deinit();
23052307 self.job_queue.deinit();
23062308 self.fetch.prog_node.end();
2307 self.global_cache_directory.handle.close();
2309 self.global_cache_directory.handle.close(io);
23082310 self.http_client.deinit();
23092311 }
23102312
2311 fn packageDir(self: *TestFetchBuilder) !fs.Dir {
2313 fn packageDir(self: *TestFetchBuilder) !Io.Dir {
23122314 const root = self.fetch.package_root;
23132315 return try root.root_dir.handle.openDir(root.sub_path, .{ .iterate = true });
23142316 }
......@@ -2316,8 +2318,10 @@ const TestFetchBuilder = struct {
23162318 // Test helper, asserts thet package dir constains expected_files.
23172319 // expected_files must be sorted.
23182320 fn expectPackageFiles(self: *TestFetchBuilder, expected_files: []const []const u8) !void {
2321 const io = self.job_queue.io;
2322
23192323 var package_dir = try self.packageDir();
2320 defer package_dir.close();
2324 defer package_dir.close(io);
23212325
23222326 var actual_files: std.ArrayList([]u8) = .empty;
23232327 defer actual_files.deinit(std.testing.allocator);
src/Package/Fetch/git.zig+14-12
......@@ -213,6 +213,7 @@ pub const Repository = struct {
213213 /// Checks out the repository at `commit_oid` to `worktree`.
214214 pub fn checkout(
215215 repository: *Repository,
216 io: Io,
216217 worktree: std.fs.Dir,
217218 commit_oid: Oid,
218219 diagnostics: *Diagnostics,
......@@ -223,12 +224,13 @@ pub const Repository = struct {
223224 if (commit_object.type != .commit) return error.NotACommit;
224225 break :tree_oid try getCommitTree(repository.odb.format, commit_object.data);
225226 };
226 try repository.checkoutTree(worktree, tree_oid, "", diagnostics);
227 try repository.checkoutTree(io, worktree, tree_oid, "", diagnostics);
227228 }
228229
229230 /// Checks out the tree at `tree_oid` to `worktree`.
230231 fn checkoutTree(
231232 repository: *Repository,
233 io: Io,
232234 dir: std.fs.Dir,
233235 tree_oid: Oid,
234236 current_path: []const u8,
......@@ -253,10 +255,10 @@ pub const Repository = struct {
253255 .directory => {
254256 try dir.makeDir(entry.name);
255257 var subdir = try dir.openDir(entry.name, .{});
256 defer subdir.close();
258 defer subdir.close(io);
257259 const sub_path = try std.fs.path.join(repository.odb.allocator, &.{ current_path, entry.name });
258260 defer repository.odb.allocator.free(sub_path);
259 try repository.checkoutTree(subdir, entry.oid, sub_path, diagnostics);
261 try repository.checkoutTree(io, subdir, entry.oid, sub_path, diagnostics);
260262 },
261263 .file => {
262264 try repository.odb.seekOid(entry.oid);
......@@ -271,7 +273,7 @@ pub const Repository = struct {
271273 } });
272274 continue;
273275 };
274 defer file.close();
276 defer file.close(io);
275277 try file.writeAll(file_object.data);
276278 },
277279 .symlink => {
......@@ -1583,14 +1585,14 @@ fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u
15831585 var git_dir = testing.tmpDir(.{});
15841586 defer git_dir.cleanup();
15851587 var pack_file = try git_dir.dir.createFile("testrepo.pack", .{ .read = true });
1586 defer pack_file.close();
1588 defer pack_file.close(io);
15871589 try pack_file.writeAll(testrepo_pack);
15881590
15891591 var pack_file_buffer: [2000]u8 = undefined;
15901592 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);
15911593
15921594 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
1593 defer index_file.close();
1595 defer index_file.close(io);
15941596 var index_file_buffer: [2000]u8 = undefined;
15951597 var index_file_writer = index_file.writer(&index_file_buffer);
15961598 try indexPack(testing.allocator, format, &pack_file_reader, &index_file_writer);
......@@ -1621,7 +1623,7 @@ fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u
16211623
16221624 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
16231625 defer diagnostics.deinit();
1624 try repository.checkout(worktree.dir, commit_id, &diagnostics);
1626 try repository.checkout(io, worktree.dir, commit_id, &diagnostics);
16251627 try testing.expect(diagnostics.errors.items.len == 0);
16261628
16271629 const expected_files: []const []const u8 = &.{
......@@ -1713,20 +1715,20 @@ pub fn main() !void {
17131715 const format = std.meta.stringToEnum(Oid.Format, args[1]) orelse return error.InvalidFormat;
17141716
17151717 var pack_file = try std.fs.cwd().openFile(args[2], .{});
1716 defer pack_file.close();
1718 defer pack_file.close(io);
17171719 var pack_file_buffer: [4096]u8 = undefined;
17181720 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);
17191721
17201722 const commit = try Oid.parse(format, args[3]);
17211723 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});
1722 defer worktree.close();
1724 defer worktree.close(io);
17231725
17241726 var git_dir = try worktree.makeOpenPath(".git", .{});
1725 defer git_dir.close();
1727 defer git_dir.close(io);
17261728
17271729 std.debug.print("Starting index...\n", .{});
17281730 var index_file = try git_dir.createFile("idx", .{ .read = true });
1729 defer index_file.close();
1731 defer index_file.close(io);
17301732 var index_file_buffer: [4096]u8 = undefined;
17311733 var index_file_writer = index_file.writer(&index_file_buffer);
17321734 try indexPack(allocator, format, &pack_file_reader, &index_file_writer);
......@@ -1738,7 +1740,7 @@ pub fn main() !void {
17381740 defer repository.deinit();
17391741 var diagnostics: Diagnostics = .{ .allocator = allocator };
17401742 defer diagnostics.deinit();
1741 try repository.checkout(worktree, commit, &diagnostics);
1743 try repository.checkout(io, worktree, commit, &diagnostics);
17421744
17431745 for (diagnostics.errors.items) |err| {
17441746 std.debug.print("Diagnostic: {}\n", .{err});
src/Zcu.zig+5-5
......@@ -1078,7 +1078,7 @@ pub const File = struct {
10781078 const dir, const sub_path = file.path.openInfo(zcu.comp.dirs);
10791079 break :f try dir.openFile(sub_path, .{});
10801080 };
1081 defer f.close();
1081 defer f.close(io);
10821082
10831083 const stat = f.stat() catch |err| switch (err) {
10841084 error.Streaming => {
......@@ -2813,8 +2813,8 @@ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {
28132813
28142814pub fn deinit(zcu: *Zcu) void {
28152815 const comp = zcu.comp;
2816 const gpa = comp.gpa;
28172816 const io = comp.io;
2817 const gpa = zcu.gpa;
28182818 {
28192819 const pt: Zcu.PerThread = .activate(zcu, .main);
28202820 defer pt.deactivate();
......@@ -2835,8 +2835,8 @@ pub fn deinit(zcu: *Zcu) void {
28352835 }
28362836 zcu.embed_table.deinit(gpa);
28372837
2838 zcu.local_zir_cache.handle.close();
2839 zcu.global_zir_cache.handle.close();
2838 zcu.local_zir_cache.handle.close(io);
2839 zcu.global_zir_cache.handle.close(io);
28402840
28412841 for (zcu.failed_analysis.values()) |value| value.destroy(gpa);
28422842 for (zcu.failed_codegen.values()) |value| value.destroy(gpa);
......@@ -2900,7 +2900,7 @@ pub fn deinit(zcu: *Zcu) void {
29002900
29012901 if (zcu.resolved_references) |*r| r.deinit(gpa);
29022902
2903 if (zcu.comp.debugIncremental()) {
2903 if (comp.debugIncremental()) {
29042904 zcu.incremental_debug_state.deinit(gpa);
29052905 }
29062906 }
src/Zcu/PerThread.zig+3-3
......@@ -96,7 +96,7 @@ pub fn updateFile(
9696 const dir, const sub_path = file.path.openInfo(comp.dirs);
9797 break :f try dir.openFile(sub_path, .{});
9898 };
99 defer source_file.close();
99 defer source_file.close(io);
100100
101101 const stat = try source_file.stat();
102102
......@@ -215,7 +215,7 @@ pub fn updateFile(
215215 else => |e| return e, // Retryable errors are handled at callsite.
216216 };
217217 };
218 defer cache_file.close();
218 defer cache_file.close(io);
219219
220220 // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers.
221221 const ignore_hit = comp.time_report != null;
......@@ -2468,7 +2468,7 @@ fn updateEmbedFileInner(
24682468 const dir, const sub_path = ef.path.openInfo(zcu.comp.dirs);
24692469 break :f try dir.openFile(sub_path, .{});
24702470 };
2471 defer file.close();
2471 defer file.close(io);
24722472
24732473 const stat: Cache.File.Stat = .fromFs(try file.stat());
24742474
src/codegen/llvm.zig+3-2
......@@ -799,6 +799,7 @@ pub const Object = struct {
799799 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) error{ LinkFailure, OutOfMemory }!void {
800800 const zcu = pt.zcu;
801801 const comp = zcu.comp;
802 const io = comp.io;
802803 const diags = &comp.link_diags;
803804
804805 {
......@@ -979,7 +980,7 @@ pub const Object = struct {
979980 if (options.pre_bc_path) |path| {
980981 var file = std.fs.cwd().createFile(path, .{}) catch |err|
981982 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });
982 defer file.close();
983 defer file.close(io);
983984
984985 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
985986 file.writeAll(ptr[0..(bitcode.len * 4)]) catch |err|
......@@ -992,7 +993,7 @@ pub const Object = struct {
992993 if (options.post_bc_path) |path| {
993994 var file = std.fs.cwd().createFile(path, .{}) catch |err|
994995 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });
995 defer file.close();
996 defer file.close(io);
996997
997998 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
998999 file.writeAll(ptr[0..(bitcode.len * 4)]) catch |err|
src/fmt.zig+6-4
......@@ -187,7 +187,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
187187 // On Windows, statFile does not work for directories
188188 error.IsDir => dir: {
189189 var dir = try fs.cwd().openDir(file_path, .{});
190 defer dir.close();
190 defer dir.close(io);
191191 break :dir try dir.stat();
192192 },
193193 else => |e| return e,
......@@ -222,8 +222,10 @@ fn fmtPathDir(
222222 parent_dir: fs.Dir,
223223 parent_sub_path: []const u8,
224224) !void {
225 const io = fmt.io;
226
225227 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
226 defer dir.close();
228 defer dir.close(io);
227229
228230 const stat = try dir.stat();
229231 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
......@@ -262,7 +264,7 @@ fn fmtPathFile(
262264
263265 const source_file = try dir.openFile(sub_path, .{});
264266 var file_closed = false;
265 errdefer if (!file_closed) source_file.close();
267 errdefer if (!file_closed) source_file.close(io);
266268
267269 const stat = try source_file.stat();
268270
......@@ -280,7 +282,7 @@ fn fmtPathFile(
280282 };
281283 defer gpa.free(source_code);
282284
283 source_file.close();
285 source_file.close(io);
284286 file_closed = true;
285287
286288 // Add to set after no longer possible to get error.IsDir.
src/introspect.zig+16-12
......@@ -1,18 +1,21 @@
1const std = @import("std");
21const builtin = @import("builtin");
2const build_options = @import("build_options");
3
4const std = @import("std");
5const Io = std.Io;
36const mem = std.mem;
4const Allocator = mem.Allocator;
7const Allocator = std.mem.Allocator;
58const os = std.os;
69const fs = std.fs;
710const Cache = std.Build.Cache;
11
812const Compilation = @import("Compilation.zig");
913const Package = @import("Package.zig");
10const build_options = @import("build_options");
1114
1215/// Returns the sub_path that worked, or `null` if none did.
1316/// The path of the returned Directory is relative to `base`.
1417/// The handle of the returned Directory is open.
15fn testZigInstallPrefix(base_dir: fs.Dir) ?Cache.Directory {
18fn testZigInstallPrefix(io: Io, base_dir: Io.Dir) ?Cache.Directory {
1619 const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";
1720
1821 zig_dir: {
......@@ -20,31 +23,31 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Cache.Directory {
2023 const lib_zig = "lib" ++ fs.path.sep_str ++ "zig";
2124 var test_zig_dir = base_dir.openDir(lib_zig, .{}) catch break :zig_dir;
2225 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
23 test_zig_dir.close();
26 test_zig_dir.close(io);
2427 break :zig_dir;
2528 };
26 file.close();
29 file.close(io);
2730 return .{ .handle = test_zig_dir, .path = lib_zig };
2831 }
2932
3033 // Try lib/std/std.zig
3134 var test_zig_dir = base_dir.openDir("lib", .{}) catch return null;
3235 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
33 test_zig_dir.close();
36 test_zig_dir.close(io);
3437 return null;
3538 };
36 file.close();
39 file.close(io);
3740 return .{ .handle = test_zig_dir, .path = "lib" };
3841}
3942
4043/// Both the directory handle and the path are newly allocated resources which the caller now owns.
41pub fn findZigLibDir(gpa: Allocator) !Cache.Directory {
44pub fn findZigLibDir(gpa: Allocator, io: Io) !Cache.Directory {
4245 const cwd_path = try getResolvedCwd(gpa);
4346 defer gpa.free(cwd_path);
4447 const self_exe_path = try fs.selfExePathAlloc(gpa);
4548 defer gpa.free(self_exe_path);
4649
47 return findZigLibDirFromSelfExe(gpa, cwd_path, self_exe_path);
50 return findZigLibDirFromSelfExe(gpa, io, cwd_path, self_exe_path);
4851}
4952
5053/// Like `std.process.getCwdAlloc`, but also resolves the path with `std.fs.path.resolve`. This
......@@ -73,6 +76,7 @@ pub fn getResolvedCwd(gpa: Allocator) error{
7376/// Both the directory handle and the path are newly allocated resources which the caller now owns.
7477pub fn findZigLibDirFromSelfExe(
7578 allocator: Allocator,
79 io: Io,
7680 /// The return value of `getResolvedCwd`.
7781 /// Passed as an argument to avoid pointlessly repeating the call.
7882 cwd_path: []const u8,
......@@ -82,9 +86,9 @@ pub fn findZigLibDirFromSelfExe(
8286 var cur_path: []const u8 = self_exe_path;
8387 while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {
8488 var base_dir = cwd.openDir(dirname, .{}) catch continue;
85 defer base_dir.close();
89 defer base_dir.close(io);
8690
87 const sub_directory = testZigInstallPrefix(base_dir) orelse continue;
91 const sub_directory = testZigInstallPrefix(io, base_dir) orelse continue;
8892 const p = try fs.path.join(allocator, &.{ dirname, sub_directory.path.? });
8993 defer allocator.free(p);
9094
src/libs/freebsd.zig+2-2
......@@ -449,7 +449,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
449449 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
450450 cache.addPrefix(comp.dirs.zig_lib);
451451 cache.addPrefix(comp.dirs.global_cache);
452 defer cache.manifest_dir.close();
452 defer cache.manifest_dir.close(io);
453453
454454 var man = cache.obtain();
455455 defer man.deinit();
......@@ -480,7 +480,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
480480 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
481481 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
482482 };
483 defer o_directory.handle.close();
483 defer o_directory.handle.close(io);
484484
485485 const abilists_contents = man.files.keys()[abilists_index].contents.?;
486486 const metadata = try loadMetaData(gpa, abilists_contents);
src/libs/glibc.zig+2-2
......@@ -684,7 +684,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
684684 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
685685 cache.addPrefix(comp.dirs.zig_lib);
686686 cache.addPrefix(comp.dirs.global_cache);
687 defer cache.manifest_dir.close();
687 defer cache.manifest_dir.close(io);
688688
689689 var man = cache.obtain();
690690 defer man.deinit();
......@@ -715,7 +715,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
715715 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
716716 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
717717 };
718 defer o_directory.handle.close();
718 defer o_directory.handle.close(io);
719719
720720 const abilists_contents = man.files.keys()[abilists_index].contents.?;
721721 const metadata = try loadMetaData(gpa, abilists_contents);
src/libs/mingw.zig+3-3
......@@ -262,7 +262,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
262262 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
263263 cache.addPrefix(comp.dirs.zig_lib);
264264 cache.addPrefix(comp.dirs.global_cache);
265 defer cache.manifest_dir.close();
265 defer cache.manifest_dir.close(io);
266266
267267 cache.hash.addBytes(build_options.version);
268268 cache.hash.addOptionalBytes(comp.dirs.zig_lib.path);
......@@ -297,7 +297,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
297297 const digest = man.final();
298298 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
299299 var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});
300 defer o_dir.close();
300 defer o_dir.close(io);
301301
302302 const aro = @import("aro");
303303 var diagnostics: aro.Diagnostics = .{
......@@ -377,7 +377,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
377377
378378 {
379379 const lib_final_file = try o_dir.createFile(final_lib_basename, .{ .truncate = true });
380 defer lib_final_file.close();
380 defer lib_final_file.close(io);
381381 var buffer: [1024]u8 = undefined;
382382 var file_writer = lib_final_file.writer(&buffer);
383383 try implib.writeCoffArchive(gpa, &file_writer.interface, members);
src/libs/netbsd.zig+2-2
......@@ -390,7 +390,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
390390 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
391391 cache.addPrefix(comp.dirs.zig_lib);
392392 cache.addPrefix(comp.dirs.global_cache);
393 defer cache.manifest_dir.close();
393 defer cache.manifest_dir.close(io);
394394
395395 var man = cache.obtain();
396396 defer man.deinit();
......@@ -421,7 +421,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
421421 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
422422 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
423423 };
424 defer o_directory.handle.close();
424 defer o_directory.handle.close(io);
425425
426426 const abilists_contents = man.files.keys()[abilists_index].contents.?;
427427 const metadata = try loadMetaData(gpa, abilists_contents);
src/link.zig+49-34
......@@ -687,7 +687,7 @@ pub const File = struct {
687687 .lld => assert(base.file == null),
688688 .elf => if (base.file) |f| {
689689 dev.check(.elf_linker);
690 f.close();
690 f.close(io);
691691 base.file = null;
692692
693693 if (base.child_pid) |pid| {
......@@ -701,7 +701,7 @@ pub const File = struct {
701701 },
702702 .macho, .wasm => if (base.file) |f| {
703703 dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
704 f.close();
704 f.close(io);
705705 base.file = null;
706706
707707 if (base.child_pid) |pid| {
......@@ -866,8 +866,9 @@ pub const File = struct {
866866 }
867867
868868 pub fn destroy(base: *File) void {
869 const io = base.comp.io;
869870 base.releaseLock();
870 if (base.file) |f| f.close();
871 if (base.file) |f| f.close(io);
871872 switch (base.tag) {
872873 .plan9 => unreachable,
873874 inline else => |tag| {
......@@ -1060,9 +1061,10 @@ pub const File = struct {
10601061 /// Opens a path as an object file and parses it into the linker.
10611062 fn openLoadObject(base: *File, path: Path) anyerror!void {
10621063 if (base.tag == .lld) return;
1064 const io = base.comp.io;
10631065 const diags = &base.comp.link_diags;
1064 const input = try openObjectInput(diags, path);
1065 errdefer input.object.file.close();
1066 const input = try openObjectInput(io, diags, path);
1067 errdefer input.object.file.close(io);
10661068 try loadInput(base, input);
10671069 }
10681070
......@@ -1070,21 +1072,22 @@ pub const File = struct {
10701072 /// If `query` is non-null, allows GNU ld scripts.
10711073 fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void {
10721074 if (base.tag == .lld) return;
1075 const io = base.comp.io;
10731076 if (opt_query) |query| {
1074 const archive = try openObject(path, query.must_link, query.hidden);
1075 errdefer archive.file.close();
1077 const archive = try openObject(io, path, query.must_link, query.hidden);
1078 errdefer archive.file.close(io);
10761079 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
10771080 error.BadMagic, error.UnexpectedEndOfFile => {
10781081 if (base.tag != .elf and base.tag != .elf2) return err;
10791082 try loadGnuLdScript(base, path, query, archive.file);
1080 archive.file.close();
1083 archive.file.close(io);
10811084 return;
10821085 },
10831086 else => return err,
10841087 };
10851088 } else {
1086 const archive = try openObject(path, false, false);
1087 errdefer archive.file.close();
1089 const archive = try openObject(io, path, false, false);
1090 errdefer archive.file.close(io);
10881091 try loadInput(base, .{ .archive = archive });
10891092 }
10901093 }
......@@ -1093,13 +1096,14 @@ pub const File = struct {
10931096 /// Handles GNU ld scripts.
10941097 fn openLoadDso(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void {
10951098 if (base.tag == .lld) return;
1096 const dso = try openDso(path, query.needed, query.weak, query.reexport);
1097 errdefer dso.file.close();
1099 const io = base.comp.io;
1100 const dso = try openDso(io, path, query.needed, query.weak, query.reexport);
1101 errdefer dso.file.close(io);
10981102 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {
10991103 error.BadMagic, error.UnexpectedEndOfFile => {
11001104 if (base.tag != .elf and base.tag != .elf2) return err;
11011105 try loadGnuLdScript(base, path, query, dso.file);
1102 dso.file.close();
1106 dso.file.close(io);
11031107 return;
11041108 },
11051109 else => return err,
......@@ -1735,6 +1739,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
17351739pub fn resolveInputs(
17361740 gpa: Allocator,
17371741 arena: Allocator,
1742 io: Io,
17381743 target: *const std.Target,
17391744 /// This function mutates this array but does not take ownership.
17401745 /// Allocated with `gpa`.
......@@ -1784,6 +1789,7 @@ pub fn resolveInputs(
17841789 for (lib_directories) |lib_directory| switch (try resolveLibInput(
17851790 gpa,
17861791 arena,
1792 io,
17871793 unresolved_inputs,
17881794 resolved_inputs,
17891795 &checked_paths,
......@@ -1810,6 +1816,7 @@ pub fn resolveInputs(
18101816 for (lib_directories) |lib_directory| switch (try resolveLibInput(
18111817 gpa,
18121818 arena,
1819 io,
18131820 unresolved_inputs,
18141821 resolved_inputs,
18151822 &checked_paths,
......@@ -1837,6 +1844,7 @@ pub fn resolveInputs(
18371844 switch (try resolveLibInput(
18381845 gpa,
18391846 arena,
1847 io,
18401848 unresolved_inputs,
18411849 resolved_inputs,
18421850 &checked_paths,
......@@ -1855,6 +1863,7 @@ pub fn resolveInputs(
18551863 switch (try resolveLibInput(
18561864 gpa,
18571865 arena,
1866 io,
18581867 unresolved_inputs,
18591868 resolved_inputs,
18601869 &checked_paths,
......@@ -1886,6 +1895,7 @@ pub fn resolveInputs(
18861895 if (try resolvePathInput(
18871896 gpa,
18881897 arena,
1898 io,
18891899 unresolved_inputs,
18901900 resolved_inputs,
18911901 &ld_script_bytes,
......@@ -1903,6 +1913,7 @@ pub fn resolveInputs(
19031913 switch ((try resolvePathInput(
19041914 gpa,
19051915 arena,
1916 io,
19061917 unresolved_inputs,
19071918 resolved_inputs,
19081919 &ld_script_bytes,
......@@ -1930,6 +1941,7 @@ pub fn resolveInputs(
19301941 if (try resolvePathInput(
19311942 gpa,
19321943 arena,
1944 io,
19331945 unresolved_inputs,
19341946 resolved_inputs,
19351947 &ld_script_bytes,
......@@ -1969,6 +1981,7 @@ const fatal = std.process.fatal;
19691981fn resolveLibInput(
19701982 gpa: Allocator,
19711983 arena: Allocator,
1984 io: Io,
19721985 /// Allocated via `gpa`.
19731986 unresolved_inputs: *std.ArrayList(UnresolvedInput),
19741987 /// Allocated via `gpa`.
......@@ -1998,7 +2011,7 @@ fn resolveLibInput(
19982011 error.FileNotFound => break :tbd,
19992012 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),
20002013 };
2001 errdefer file.close();
2014 errdefer file.close(io);
20022015 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
20032016 }
20042017
......@@ -2013,7 +2026,7 @@ fn resolveLibInput(
20132026 }),
20142027 };
20152028 try checked_paths.print(gpa, "\n {f}", .{test_path});
2016 switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
2029 switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
20172030 .path = test_path,
20182031 .query = name_query.query,
20192032 }, link_mode, color)) {
......@@ -2036,7 +2049,7 @@ fn resolveLibInput(
20362049 test_path, @errorName(e),
20372050 }),
20382051 };
2039 errdefer file.close();
2052 errdefer file.close(io);
20402053 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
20412054 }
20422055
......@@ -2052,7 +2065,7 @@ fn resolveLibInput(
20522065 error.FileNotFound => break :mingw,
20532066 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),
20542067 };
2055 errdefer file.close();
2068 errdefer file.close(io);
20562069 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
20572070 }
20582071
......@@ -2087,6 +2100,7 @@ fn finishResolveLibInput(
20872100fn resolvePathInput(
20882101 gpa: Allocator,
20892102 arena: Allocator,
2103 io: Io,
20902104 /// Allocated with `gpa`.
20912105 unresolved_inputs: *std.ArrayList(UnresolvedInput),
20922106 /// Allocated with `gpa`.
......@@ -2098,12 +2112,12 @@ fn resolvePathInput(
20982112 color: std.zig.Color,
20992113) Allocator.Error!?ResolveLibInputResult {
21002114 switch (Compilation.classifyFileExt(pq.path.sub_path)) {
2101 .static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color),
2102 .shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
2115 .static_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color),
2116 .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
21032117 .object => {
21042118 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
21052119 fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) });
2106 errdefer file.close();
2120 errdefer file.close(io);
21072121 try resolved_inputs.append(gpa, .{ .object = .{
21082122 .path = pq.path,
21092123 .file = file,
......@@ -2115,7 +2129,7 @@ fn resolvePathInput(
21152129 .res => {
21162130 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
21172131 fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) });
2118 errdefer file.close();
2132 errdefer file.close(io);
21192133 try resolved_inputs.append(gpa, .{ .res = .{
21202134 .path = pq.path,
21212135 .file = file,
......@@ -2129,6 +2143,7 @@ fn resolvePathInput(
21292143fn resolvePathInputLib(
21302144 gpa: Allocator,
21312145 arena: Allocator,
2146 io: Io,
21322147 /// Allocated with `gpa`.
21332148 unresolved_inputs: *std.ArrayList(UnresolvedInput),
21342149 /// Allocated with `gpa`.
......@@ -2155,7 +2170,7 @@ fn resolvePathInputLib(
21552170 @tagName(link_mode), std.fmt.alt(test_path, .formatEscapeChar), @errorName(e),
21562171 }),
21572172 };
2158 errdefer file.close();
2173 errdefer file.close(io);
21592174 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));
21602175 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f}': {s}", .{
21612176 std.fmt.alt(test_path, .formatEscapeChar), @errorName(err),
......@@ -2223,7 +2238,7 @@ fn resolvePathInputLib(
22232238 } });
22242239 }
22252240 }
2226 file.close();
2241 file.close(io);
22272242 return .ok;
22282243 }
22292244
......@@ -2233,13 +2248,13 @@ fn resolvePathInputLib(
22332248 @tagName(link_mode), test_path, @errorName(e),
22342249 }),
22352250 };
2236 errdefer file.close();
2251 errdefer file.close(io);
22372252 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
22382253}
22392254
2240pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
2255pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object {
22412256 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
2242 errdefer file.close();
2257 errdefer file.close(io);
22432258 return .{
22442259 .path = path,
22452260 .file = file,
......@@ -2248,9 +2263,9 @@ pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
22482263 };
22492264}
22502265
2251pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso {
2266pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso {
22522267 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
2253 errdefer file.close();
2268 errdefer file.close(io);
22542269 return .{
22552270 .path = path,
22562271 .file = file,
......@@ -2260,20 +2275,20 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
22602275 };
22612276}
22622277
2263pub fn openObjectInput(diags: *Diags, path: Path) error{LinkFailure}!Input {
2264 return .{ .object = openObject(path, false, false) catch |err| {
2278pub fn openObjectInput(io: Io, diags: *Diags, path: Path) error{LinkFailure}!Input {
2279 return .{ .object = openObject(io, path, false, false) catch |err| {
22652280 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
22662281 } };
22672282}
22682283
2269pub fn openArchiveInput(diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input {
2270 return .{ .archive = openObject(path, must_link, hidden) catch |err| {
2284pub fn openArchiveInput(io: Io, diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input {
2285 return .{ .archive = openObject(io, path, must_link, hidden) catch |err| {
22712286 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
22722287 } };
22732288}
22742289
2275pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input {
2276 return .{ .dso = openDso(path, needed, weak, reexport) catch |err| {
2290pub fn openDsoInput(io: Io, diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input {
2291 return .{ .dso = openDso(io, path, needed, weak, reexport) catch |err| {
22772292 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
22782293 } };
22792294}
src/link/C.zig+4-2
......@@ -124,6 +124,7 @@ pub fn createEmpty(
124124 emit: Path,
125125 options: link.File.OpenOptions,
126126) !*C {
127 const io = comp.io;
127128 const target = &comp.root_mod.resolved_target.result;
128129 assert(target.ofmt == .c);
129130 const optimize_mode = comp.root_mod.optimize_mode;
......@@ -139,7 +140,7 @@ pub fn createEmpty(
139140 // Truncation is done on `flush`.
140141 .truncate = false,
141142 });
142 errdefer file.close();
143 errdefer file.close(io);
143144
144145 const c_file = try arena.create(C);
145146
......@@ -763,6 +764,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {
763764 if (true) return; // emit-h is regressed
764765
765766 const emit_h = zcu.emit_h orelse return;
767 const io = zcu.comp.io;
766768
767769 // We collect a list of buffers to write, and write them all at once with pwritev 😎
768770 const num_buffers = emit_h.decl_table.count() + 1;
......@@ -795,7 +797,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {
795797 // make it easier on the file system by doing 1 reallocation instead of two.
796798 .truncate = false,
797799 });
798 defer file.close();
800 defer file.close(io);
799801
800802 try file.setEndPos(file_size);
801803 try file.pwritevAll(all_buffers.items, 0);
src/link/Elf.zig+4-2
......@@ -406,10 +406,12 @@ pub fn open(
406406}
407407
408408pub fn deinit(self: *Elf) void {
409 const gpa = self.base.comp.gpa;
409 const comp = self.base.comp;
410 const gpa = comp.gpa;
411 const io = comp.io;
410412
411413 for (self.file_handles.items) |fh| {
412 fh.close();
414 fh.close(io);
413415 }
414416 self.file_handles.deinit(gpa);
415417
src/link/Lld.zig+1-1
......@@ -1628,7 +1628,7 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
16281628 defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err|
16291629 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });
16301630 {
1631 defer rsp_file.close();
1631 defer rsp_file.close(io);
16321632 var rsp_file_buffer: [1024]u8 = undefined;
16331633 var rsp_file_writer = rsp_file.writer(&rsp_file_buffer);
16341634 const rsp_writer = &rsp_file_writer.interface;
src/link/MachO.zig+11-5
......@@ -267,14 +267,16 @@ pub fn open(
267267}
268268
269269pub fn deinit(self: *MachO) void {
270 const gpa = self.base.comp.gpa;
270 const comp = self.base.comp;
271 const gpa = comp.gpa;
272 const io = comp.io;
271273
272274 if (self.d_sym) |*d_sym| {
273275 d_sym.deinit();
274276 }
275277
276278 for (self.file_handles.items) |handle| {
277 handle.close();
279 handle.close(io);
278280 }
279281 self.file_handles.deinit(gpa);
280282
......@@ -3257,8 +3259,10 @@ const InitMetadataOptions = struct {
32573259};
32583260
32593261pub fn closeDebugInfo(self: *MachO) bool {
3262 const comp = self.base.comp;
3263 const io = comp.io;
32603264 const d_sym = &(self.d_sym orelse return false);
3261 d_sym.file.?.close();
3265 d_sym.file.?.close(io);
32623266 d_sym.file = null;
32633267 return true;
32643268}
......@@ -3269,7 +3273,9 @@ pub fn reopenDebugInfo(self: *MachO) !void {
32693273 assert(!self.base.comp.config.use_llvm);
32703274 assert(self.base.comp.config.debug_format == .dwarf);
32713275
3272 const gpa = self.base.comp.gpa;
3276 const comp = self.base.comp;
3277 const io = comp.io;
3278 const gpa = comp.gpa;
32733279 const sep = fs.path.sep_str;
32743280 const d_sym_path = try std.fmt.allocPrint(
32753281 gpa,
......@@ -3279,7 +3285,7 @@ pub fn reopenDebugInfo(self: *MachO) !void {
32793285 defer gpa.free(d_sym_path);
32803286
32813287 var d_sym_bundle = try self.base.emit.root_dir.handle.makeOpenPath(d_sym_path, .{});
3282 defer d_sym_bundle.close();
3288 defer d_sym_bundle.close(io);
32833289
32843290 self.d_sym.?.file = try d_sym_bundle.createFile(fs.path.basename(self.base.emit.sub_path), .{
32853291 .truncate = false,
src/link/MachO/DebugSymbols.zig+26-24
......@@ -1,5 +1,28 @@
1const DebugSymbols = @This();
2
3const std = @import("std");
4const Io = std.Io;
5const assert = std.debug.assert;
6const fs = std.fs;
7const log = std.log.scoped(.link_dsym);
8const macho = std.macho;
9const makeStaticString = MachO.makeStaticString;
10const math = std.math;
11const mem = std.mem;
12const Writer = std.Io.Writer;
13const Allocator = std.mem.Allocator;
14
15const link = @import("../../link.zig");
16const MachO = @import("../MachO.zig");
17const StringTable = @import("../StringTable.zig");
18const Type = @import("../../Type.zig");
19const trace = @import("../../tracy.zig").trace;
20const load_commands = @import("load_commands.zig");
21const padToIdeal = MachO.padToIdeal;
22
23io: Io,
124allocator: Allocator,
2file: ?fs.File,
25file: ?Io.File,
326
427symtab_cmd: macho.symtab_command = .{},
528uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
......@@ -208,7 +231,8 @@ pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void {
208231
209232pub fn deinit(self: *DebugSymbols) void {
210233 const gpa = self.allocator;
211 if (self.file) |file| file.close();
234 const io = self.io;
235 if (self.file) |file| file.close(io);
212236 self.segments.deinit(gpa);
213237 self.sections.deinit(gpa);
214238 self.relocs.deinit(gpa);
......@@ -443,25 +467,3 @@ pub fn getSection(self: DebugSymbols, sect: u8) macho.section_64 {
443467 assert(sect < self.sections.items.len);
444468 return self.sections.items[sect];
445469}
446
447const DebugSymbols = @This();
448
449const std = @import("std");
450const build_options = @import("build_options");
451const assert = std.debug.assert;
452const fs = std.fs;
453const link = @import("../../link.zig");
454const load_commands = @import("load_commands.zig");
455const log = std.log.scoped(.link_dsym);
456const macho = std.macho;
457const makeStaticString = MachO.makeStaticString;
458const math = std.math;
459const mem = std.mem;
460const padToIdeal = MachO.padToIdeal;
461const trace = @import("../../tracy.zig").trace;
462const Writer = std.Io.Writer;
463
464const Allocator = mem.Allocator;
465const MachO = @import("../MachO.zig");
466const StringTable = @import("../StringTable.zig");
467const Type = @import("../../Type.zig");
src/link/Wasm.zig+2-2
......@@ -3032,7 +3032,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
30323032 const io = wasm.base.comp.io;
30333033 const gc_sections = wasm.base.gc_sections;
30343034
3035 defer obj.file.close();
3035 defer obj.file.close(io);
30363036
30373037 var file_reader = obj.file.reader(io, &.{});
30383038
......@@ -3060,7 +3060,7 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {
30603060 const io = wasm.base.comp.io;
30613061 const gc_sections = wasm.base.gc_sections;
30623062
3063 defer obj.file.close();
3063 defer obj.file.close(io);
30643064
30653065 var file_reader = obj.file.reader(io, &.{});
30663066
src/main.zig+71-64
......@@ -328,21 +328,21 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
328328 .prepend_global_cache_path = true,
329329 });
330330 } else if (mem.eql(u8, cmd, "init")) {
331 return cmdInit(gpa, arena, cmd_args);
331 return cmdInit(gpa, arena, io, cmd_args);
332332 } else if (mem.eql(u8, cmd, "targets")) {
333333 dev.check(.targets_command);
334334 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
335 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
336 try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host);
335 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
336 try @import("print_targets.zig").cmdTargets(arena, io, cmd_args, &stdout_writer.interface, &host);
337337 return stdout_writer.interface.flush();
338338 } else if (mem.eql(u8, cmd, "version")) {
339339 dev.check(.version_command);
340 try fs.File.stdout().writeAll(build_options.version ++ "\n");
340 try Io.File.stdout().writeAll(build_options.version ++ "\n");
341341 return;
342342 } else if (mem.eql(u8, cmd, "env")) {
343343 dev.check(.env_command);
344344 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
345 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
345 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
346346 try @import("print_env.zig").cmdEnv(
347347 arena,
348348 &stdout_writer.interface,
......@@ -358,10 +358,10 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
358358 });
359359 } else if (mem.eql(u8, cmd, "zen")) {
360360 dev.check(.zen_command);
361 return fs.File.stdout().writeAll(info_zen);
361 return Io.File.stdout().writeAll(info_zen);
362362 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
363363 dev.check(.help_command);
364 return fs.File.stdout().writeAll(usage);
364 return Io.File.stdout().writeAll(usage);
365365 } else if (mem.eql(u8, cmd, "ast-check")) {
366366 return cmdAstCheck(arena, io, cmd_args);
367367 } else if (mem.eql(u8, cmd, "detect-cpu")) {
......@@ -698,7 +698,7 @@ const Emit = union(enum) {
698698 yes: []const u8,
699699
700700 const OutputToCacheReason = enum { listen, @"zig run", @"zig test" };
701 fn resolve(emit: Emit, default_basename: []const u8, output_to_cache: ?OutputToCacheReason) Compilation.CreateOptions.Emit {
701 fn resolve(io: Io, emit: Emit, default_basename: []const u8, output_to_cache: ?OutputToCacheReason) Compilation.CreateOptions.Emit {
702702 return switch (emit) {
703703 .no => .no,
704704 .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename },
......@@ -716,7 +716,7 @@ const Emit = union(enum) {
716716 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
717717 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
718718 };
719 dir.close();
719 dir.close(io);
720720 }
721721 break :e .{ .yes_path = path };
722722 },
......@@ -1034,7 +1034,7 @@ fn buildOutputType(
10341034 };
10351035 } else if (mem.startsWith(u8, arg, "-")) {
10361036 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
1037 try fs.File.stdout().writeAll(usage_build_generic);
1037 try Io.File.stdout().writeAll(usage_build_generic);
10381038 return cleanExit();
10391039 } else if (mem.eql(u8, arg, "--")) {
10401040 if (arg_mode == .run) {
......@@ -2834,9 +2834,9 @@ fn buildOutputType(
28342834 } else if (mem.eql(u8, arg, "-V")) {
28352835 warn("ignoring request for supported emulations: unimplemented", .{});
28362836 } else if (mem.eql(u8, arg, "-v")) {
2837 try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
2837 try Io.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
28382838 } else if (mem.eql(u8, arg, "--version")) {
2839 try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
2839 try Io.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
28402840 process.exit(0);
28412841 } else {
28422842 fatal("unsupported linker arg: {s}", .{arg});
......@@ -3251,8 +3251,8 @@ fn buildOutputType(
32513251 }
32523252 }
32533253
3254 var cleanup_emit_bin_dir: ?fs.Dir = null;
3255 defer if (cleanup_emit_bin_dir) |*dir| dir.close();
3254 var cleanup_emit_bin_dir: ?Io.Dir = null;
3255 defer if (cleanup_emit_bin_dir) |*dir| dir.close(io);
32563256
32573257 // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if
32583258 // the binary is requested with no explicit path (as is the default), we emit to the cache.
......@@ -3307,7 +3307,7 @@ fn buildOutputType(
33073307 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
33083308 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
33093309 };
3310 dir.close();
3310 dir.close(io);
33113311 }
33123312 break :emit .{ .yes_path = path };
33133313 },
......@@ -3390,7 +3390,7 @@ fn buildOutputType(
33903390 // will be a hash of its contents — so multiple invocations of
33913391 // `zig cc -` will result in the same temp file name.
33923392 var f = try dirs.local_cache.handle.createFile(dump_path, .{});
3393 defer f.close();
3393 defer f.close(io);
33943394
33953395 // Re-using the hasher from Cache, since the functional requirements
33963396 // for the hashing algorithm here and in the cache are the same.
......@@ -3399,7 +3399,7 @@ fn buildOutputType(
33993399 var file_writer = f.writer(&.{});
34003400 var buffer: [1000]u8 = undefined;
34013401 var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer);
3402 var stdin_reader = fs.File.stdin().readerStreaming(io, &.{});
3402 var stdin_reader = Io.File.stdin().readerStreaming(io, &.{});
34033403 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {
34043404 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),
34053405 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),
......@@ -3630,13 +3630,13 @@ fn buildOutputType(
36303630 if (show_builtin) {
36313631 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
36323632 const source = try builtin_opts.generate(arena);
3633 return fs.File.stdout().writeAll(source);
3633 return Io.File.stdout().writeAll(source);
36343634 }
36353635 switch (listen) {
36363636 .none => {},
36373637 .stdio => {
3638 var stdin_reader = fs.File.stdin().reader(io, &stdin_buffer);
3639 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
3638 var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer);
3639 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
36403640 try serve(
36413641 comp,
36423642 &stdin_reader.interface,
......@@ -4034,6 +4034,7 @@ fn createModule(
40344034 link.resolveInputs(
40354035 gpa,
40364036 arena,
4037 io,
40374038 target,
40384039 &unresolved_link_inputs,
40394040 &create_module.link_inputs,
......@@ -4689,8 +4690,8 @@ fn cmdTranslateC(
46894690 @errorName(err),
46904691 });
46914692 };
4692 defer zig_file.close();
4693 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
4693 defer zig_file.close(io);
4694 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
46944695 var file_reader = zig_file.reader(io, &.{});
46954696 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
46964697 try stdout_writer.interface.flush();
......@@ -4728,7 +4729,7 @@ const usage_init =
47284729 \\
47294730;
47304731
4731fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4732fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !void {
47324733 dev.check(.init_command);
47334734
47344735 var template: enum { example, minimal } = .example;
......@@ -4740,7 +4741,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
47404741 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
47414742 template = .minimal;
47424743 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
4743 try fs.File.stdout().writeAll(usage_init);
4744 try Io.File.stdout().writeAll(usage_init);
47444745 return cleanExit();
47454746 } else {
47464747 fatal("unrecognized parameter: '{s}'", .{arg});
......@@ -4759,7 +4760,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
47594760
47604761 switch (template) {
47614762 .example => {
4762 var templates = findTemplates(gpa, arena);
4763 var templates = findTemplates(gpa, arena, io);
47634764 defer templates.deinit();
47644765
47654766 const s = fs.path.sep_str;
......@@ -4789,7 +4790,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
47894790 return cleanExit();
47904791 },
47914792 .minimal => {
4792 writeSimpleTemplateFile(Package.Manifest.basename,
4793 writeSimpleTemplateFile(io, Package.Manifest.basename,
47934794 \\.{{
47944795 \\ .name = .{s},
47954796 \\ .version = "0.0.1",
......@@ -4806,7 +4807,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
48064807 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
48074808 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
48084809 };
4809 writeSimpleTemplateFile(Package.build_zig_basename,
4810 writeSimpleTemplateFile(io, Package.build_zig_basename,
48104811 \\const std = @import("std");
48114812 \\
48124813 \\pub fn build(b: *std.Build) void {{
......@@ -5203,8 +5204,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
52035204 .parent = root_mod,
52045205 });
52055206
5206 var cleanup_build_dir: ?fs.Dir = null;
5207 defer if (cleanup_build_dir) |*dir| dir.close();
5207 var cleanup_build_dir: ?Io.Dir = null;
5208 defer if (cleanup_build_dir) |*dir| dir.close(io);
52085209
52095210 if (dev.env.supports(.fetch_command)) {
52105211 const fetch_prog_node = root_prog_node.start("Fetch Packages", 0);
......@@ -5296,6 +5297,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
52965297 try job_queue.createDependenciesSource(&source_buf);
52975298 const deps_mod = try createDependenciesModule(
52985299 arena,
5300 io,
52995301 source_buf.items,
53005302 root_mod,
53015303 dirs,
......@@ -5357,6 +5359,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
53575359 }
53585360 } else try createEmptyDependenciesModule(
53595361 arena,
5362 io,
53605363 root_mod,
53615364 dirs,
53625365 config,
......@@ -5623,7 +5626,7 @@ fn jitCmd(
56235626 defer comp.destroy();
56245627
56255628 if (options.server) {
5626 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
5629 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
56275630 var server: std.zig.Server = .{
56285631 .out = &stdout_writer.interface,
56295632 .in = undefined, // won't be receiving messages
......@@ -6156,7 +6159,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
61566159 const arg = args[i];
61576160 if (mem.startsWith(u8, arg, "-")) {
61586161 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6159 try fs.File.stdout().writeAll(usage_ast_check);
6162 try Io.File.stdout().writeAll(usage_ast_check);
61606163 return cleanExit();
61616164 } else if (mem.eql(u8, arg, "-t")) {
61626165 want_output_text = true;
......@@ -6187,9 +6190,9 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
61876190 break :file fs.cwd().openFile(p, .{}) catch |err| {
61886191 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
61896192 };
6190 } else fs.File.stdin();
6191 defer if (zig_source_path != null) f.close();
6192 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);
6193 } else Io.File.stdin();
6194 defer if (zig_source_path != null) f.close(io);
6195 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
61936196 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
61946197 fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
61956198 };
......@@ -6207,7 +6210,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
62076210
62086211 const tree = try Ast.parse(arena, source, mode);
62096212
6210 var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
6213 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
62116214 const stdout_bw = &stdout_writer.interface;
62126215 switch (mode) {
62136216 .zig => {
......@@ -6330,7 +6333,7 @@ fn cmdDetectCpu(io: Io, args: []const []const u8) !void {
63306333 const arg = args[i];
63316334 if (mem.startsWith(u8, arg, "-")) {
63326335 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6333 try fs.File.stdout().writeAll(detect_cpu_usage);
6336 try Io.File.stdout().writeAll(detect_cpu_usage);
63346337 return cleanExit();
63356338 } else if (mem.eql(u8, arg, "--llvm")) {
63366339 use_llvm = true;
......@@ -6422,7 +6425,7 @@ fn detectNativeCpuWithLLVM(
64226425}
64236426
64246427fn printCpu(cpu: std.Target.Cpu) !void {
6425 var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
6428 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
64266429 const stdout_bw = &stdout_writer.interface;
64276430
64286431 if (cpu.model.llvm_name) |llvm_name| {
......@@ -6471,7 +6474,7 @@ fn cmdDumpLlvmInts(
64716474 const dl = tm.createTargetDataLayout();
64726475 const context = llvm.Context.create();
64736476
6474 var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
6477 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
64756478 const stdout_bw = &stdout_writer.interface;
64766479 for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
64776480 const int_type = context.intType(bits);
......@@ -6494,10 +6497,10 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
64946497 var f = fs.cwd().openFile(cache_file, .{}) catch |err| {
64956498 fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) });
64966499 };
6497 defer f.close();
6500 defer f.close(io);
64986501
64996502 const zir = try Zcu.loadZirCache(arena, io, f);
6500 var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
6503 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
65016504 const stdout_bw = &stdout_writer.interface;
65026505 {
65036506 const instruction_bytes = zir.instructions.len *
......@@ -6540,16 +6543,16 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {
65406543 const old_source = source: {
65416544 var f = fs.cwd().openFile(old_source_path, .{}) catch |err|
65426545 fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
6543 defer f.close();
6544 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);
6546 defer f.close(io);
6547 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
65456548 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
65466549 fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
65476550 };
65486551 const new_source = source: {
65496552 var f = fs.cwd().openFile(new_source_path, .{}) catch |err|
65506553 fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
6551 defer f.close();
6552 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);
6554 defer f.close(io);
6555 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
65536556 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
65546557 fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
65556558 };
......@@ -6581,7 +6584,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {
65816584 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
65826585 try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
65836586
6584 var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
6587 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
65856588 const stdout_bw = &stdout_writer.interface;
65866589 {
65876590 try stdout_bw.print("Instruction mappings:\n", .{});
......@@ -6912,7 +6915,7 @@ fn cmdFetch(
69126915 const arg = args[i];
69136916 if (mem.startsWith(u8, arg, "-")) {
69146917 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6915 try fs.File.stdout().writeAll(usage_fetch);
6918 try Io.File.stdout().writeAll(usage_fetch);
69166919 return cleanExit();
69176920 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
69186921 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
......@@ -6958,7 +6961,7 @@ fn cmdFetch(
69586961 .path = p,
69596962 };
69606963 };
6961 defer global_cache_directory.handle.close();
6964 defer global_cache_directory.handle.close(io);
69626965
69636966 var job_queue: Package.Fetch.JobQueue = .{
69646967 .io = io,
......@@ -7021,7 +7024,7 @@ fn cmdFetch(
70217024
70227025 const name = switch (save) {
70237026 .no => {
7024 var stdout = fs.File.stdout().writerStreaming(&stdout_buffer);
7027 var stdout = Io.File.stdout().writerStreaming(&stdout_buffer);
70257028 try stdout.interface.print("{s}\n", .{package_hash_slice});
70267029 try stdout.interface.flush();
70277030 return cleanExit();
......@@ -7043,7 +7046,7 @@ fn cmdFetch(
70437046
70447047 // The name to use in case the manifest file needs to be created now.
70457048 const init_root_name = fs.path.basename(build_root.directory.path orelse cwd_path);
7046 var manifest, var ast = try loadManifest(gpa, arena, .{
7049 var manifest, var ast = try loadManifest(gpa, arena, io, .{
70477050 .root_name = try sanitizeExampleName(arena, init_root_name),
70487051 .dir = build_root.directory.handle,
70497052 .color = color,
......@@ -7168,6 +7171,7 @@ fn cmdFetch(
71687171
71697172fn createEmptyDependenciesModule(
71707173 arena: Allocator,
7174 io: Io,
71717175 main_mod: *Package.Module,
71727176 dirs: Compilation.Directories,
71737177 global_options: Compilation.Config,
......@@ -7176,6 +7180,7 @@ fn createEmptyDependenciesModule(
71767180 try Package.Fetch.JobQueue.createEmptyDependenciesSource(&source);
71777181 _ = try createDependenciesModule(
71787182 arena,
7183 io,
71797184 source.items,
71807185 main_mod,
71817186 dirs,
......@@ -7187,6 +7192,7 @@ fn createEmptyDependenciesModule(
71877192/// build runner to obtain via `@import("@dependencies")`.
71887193fn createDependenciesModule(
71897194 arena: Allocator,
7195 io: Io,
71907196 source: []const u8,
71917197 main_mod: *Package.Module,
71927198 dirs: Compilation.Directories,
......@@ -7198,7 +7204,7 @@ fn createDependenciesModule(
71987204 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
71997205 {
72007206 var tmp_dir = try dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
7201 defer tmp_dir.close();
7207 defer tmp_dir.close(io);
72027208 try tmp_dir.writeFile(.{ .sub_path = basename, .data = source });
72037209 }
72047210
......@@ -7232,10 +7238,10 @@ fn createDependenciesModule(
72327238const BuildRoot = struct {
72337239 directory: Cache.Directory,
72347240 build_zig_basename: []const u8,
7235 cleanup_build_dir: ?fs.Dir,
7241 cleanup_build_dir: ?Io.Dir,
72367242
7237 fn deinit(br: *BuildRoot) void {
7238 if (br.cleanup_build_dir) |*dir| dir.close();
7243 fn deinit(br: *BuildRoot, io: Io) void {
7244 if (br.cleanup_build_dir) |*dir| dir.close(io);
72397245 br.* = undefined;
72407246 }
72417247};
......@@ -7304,13 +7310,14 @@ fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {
73047310
73057311const LoadManifestOptions = struct {
73067312 root_name: []const u8,
7307 dir: fs.Dir,
7313 dir: Io.Dir,
73087314 color: Color,
73097315};
73107316
73117317fn loadManifest(
73127318 gpa: Allocator,
73137319 arena: Allocator,
7320 io: Io,
73147321 options: LoadManifestOptions,
73157322) !struct { Package.Manifest, Ast } {
73167323 const manifest_bytes = while (true) {
......@@ -7322,7 +7329,7 @@ fn loadManifest(
73227329 0,
73237330 ) catch |err| switch (err) {
73247331 error.FileNotFound => {
7325 writeSimpleTemplateFile(Package.Manifest.basename,
7332 writeSimpleTemplateFile(io, Package.Manifest.basename,
73267333 \\.{{
73277334 \\ .name = .{s},
73287335 \\ .version = "{s}",
......@@ -7374,12 +7381,12 @@ fn loadManifest(
73747381
73757382const Templates = struct {
73767383 zig_lib_directory: Cache.Directory,
7377 dir: fs.Dir,
7384 dir: Io.Dir,
73787385 buffer: std.array_list.Managed(u8),
73797386
7380 fn deinit(templates: *Templates) void {
7381 templates.zig_lib_directory.handle.close();
7382 templates.dir.close();
7387 fn deinit(templates: *Templates, io: Io) void {
7388 templates.zig_lib_directory.handle.close(io);
7389 templates.dir.close(io);
73837390 templates.buffer.deinit();
73847391 templates.* = undefined;
73857392 }
......@@ -7387,7 +7394,7 @@ const Templates = struct {
73877394 fn write(
73887395 templates: *Templates,
73897396 arena: Allocator,
7390 out_dir: fs.Dir,
7397 out_dir: Io.Dir,
73917398 root_name: []const u8,
73927399 template_path: []const u8,
73937400 fingerprint: Package.Fingerprint,
......@@ -7435,23 +7442,23 @@ const Templates = struct {
74357442 });
74367443 }
74377444};
7438fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
7445fn writeSimpleTemplateFile(io: Io, file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
74397446 const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
7440 defer f.close();
7447 defer f.close(io);
74417448 var buf: [4096]u8 = undefined;
74427449 var fw = f.writer(&buf);
74437450 try fw.interface.print(fmt, args);
74447451 try fw.interface.flush();
74457452}
74467453
7447fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
7454fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
74487455 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
74497456 fatal("unable to get cwd: {s}", .{@errorName(err)});
74507457 };
74517458 const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
74527459 fatal("unable to find self exe path: {s}", .{@errorName(err)});
74537460 };
7454 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
7461 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, io, cwd_path, self_exe_path) catch |err| {
74557462 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
74567463 };
74577464
src/print_targets.zig+2-1
......@@ -12,6 +12,7 @@ const introspect = @import("introspect.zig");
1212
1313pub fn cmdTargets(
1414 allocator: Allocator,
15 io: Io,
1516 args: []const []const u8,
1617 out: *std.Io.Writer,
1718 native_target: *const Target,
......@@ -20,7 +21,7 @@ pub fn cmdTargets(
2021 var zig_lib_directory = introspect.findZigLibDir(allocator) catch |err| {
2122 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
2223 };
23 defer zig_lib_directory.handle.close();
24 defer zig_lib_directory.handle.close(io);
2425 defer allocator.free(zig_lib_directory.path.?);
2526
2627 const abilists_contents = zig_lib_directory.handle.readFileAlloc(