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 {...@@ -1604,12 +1604,12 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
1604 b.build_root, @errorName(err),1604 b.build_root, @errorName(err),
1605 });1605 });
1606 };1606 };
1607 defer dir.close();1607 defer dir.close(io);
16081608
1609 var wf = b.addWriteFiles();1609 var wf = b.addWriteFiles();
16101610
1611 var it = dir.iterateAssumeFirstIteration();1611 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| {
1613 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)1613 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)
1614 continue;1614 continue;
16151615
lib/compiler/aro/aro/Compilation.zig+6-2
...@@ -1639,8 +1639,10 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin...@@ -1639,8 +1639,10 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin
1639 return error.FileNotFound;1639 return error.FileNotFound;
1640 }1640 }
16411641
1642 const io = comp.io;
1643
1642 const file = try comp.cwd.openFile(path, .{});1644 const file = try comp.cwd.openFile(path, .{});
1643 defer file.close();1645 defer file.close(io);
1644 return comp.addSourceFromFile(file, path, kind);1646 return comp.addSourceFromFile(file, path, kind);
1645}1647}
16461648
...@@ -1971,8 +1973,10 @@ fn getPathContents(comp: *Compilation, path: []const u8, limit: Io.Limit) ![]u8...@@ -1971,8 +1973,10 @@ fn getPathContents(comp: *Compilation, path: []const u8, limit: Io.Limit) ![]u8
1971 return error.FileNotFound;1973 return error.FileNotFound;
1972 }1974 }
19731975
1976 const io = comp.io;
1977
1974 const file = try comp.cwd.openFile(path, .{});1978 const file = try comp.cwd.openFile(path, .{});
1975 defer file.close();1979 defer file.close(io);
1976 return comp.getFileContents(file, limit);1980 return comp.getFileContents(file, limit);
1977}1981}
19781982
lib/compiler/aro/aro/Driver.zig+7-5
...@@ -1286,6 +1286,8 @@ fn processSource(...@@ -1286,6 +1286,8 @@ fn processSource(
1286 d.comp.generated_buf.items.len = 0;1286 d.comp.generated_buf.items.len = 0;
1287 const prev_total = d.diagnostics.errors;1287 const prev_total = d.diagnostics.errors;
12881288
1289 const io = d.comp.io;
1290
1289 var pp = try Preprocessor.initDefault(d.comp);1291 var pp = try Preprocessor.initDefault(d.comp);
1290 defer pp.deinit();1292 defer pp.deinit();
12911293
...@@ -1328,7 +1330,7 @@ fn processSource(...@@ -1328,7 +1330,7 @@ fn processSource(
1328 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, errorDescription(er) })1330 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, errorDescription(er) })
1329 else1331 else
1330 std.fs.File.stdout();1332 std.fs.File.stdout();
1331 defer if (dep_file_name != null) file.close();1333 defer if (dep_file_name != null) file.close(io);
13321334
1333 var file_writer = file.writer(&writer_buf);1335 var file_writer = file.writer(&writer_buf);
1334 dep_file.write(&file_writer.interface) catch1336 dep_file.write(&file_writer.interface) catch
...@@ -1353,7 +1355,7 @@ fn processSource(...@@ -1353,7 +1355,7 @@ fn processSource(
1353 return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })1355 return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })
1354 else1356 else
1355 std.fs.File.stdout();1357 std.fs.File.stdout();
1356 defer if (d.output_name != null) file.close();1358 defer if (d.output_name != null) file.close(io);
13571359
1358 var file_writer = file.writer(&writer_buf);1360 var file_writer = file.writer(&writer_buf);
1359 pp.prettyPrintTokens(&file_writer.interface, dump_mode) catch1361 pp.prettyPrintTokens(&file_writer.interface, dump_mode) catch
...@@ -1404,7 +1406,7 @@ fn processSource(...@@ -1404,7 +1406,7 @@ fn processSource(
1404 if (d.only_preprocess_and_compile) {1406 if (d.only_preprocess_and_compile) {
1405 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|1407 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|
1406 return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });1408 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
1409 assembly.writeToFile(out_file) catch |er|1411 assembly.writeToFile(out_file) catch |er|
1410 return d.fatal("unable to write to output file '{s}': {s}", .{ out_file_name, errorDescription(er) });1412 return d.fatal("unable to write to output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
...@@ -1418,7 +1420,7 @@ fn processSource(...@@ -1418,7 +1420,7 @@ fn processSource(
1418 const assembly_out_file_name = try d.getRandomFilename(&assembly_name_buf, ".s");1420 const assembly_out_file_name = try d.getRandomFilename(&assembly_name_buf, ".s");
1419 const out_file = d.comp.cwd.createFile(assembly_out_file_name, .{}) catch |er|1421 const out_file = d.comp.cwd.createFile(assembly_out_file_name, .{}) catch |er|
1420 return d.fatal("unable to create output file '{s}': {s}", .{ assembly_out_file_name, errorDescription(er) });1422 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);
1422 assembly.writeToFile(out_file) catch |er|1424 assembly.writeToFile(out_file) catch |er|
1423 return d.fatal("unable to write to output file '{s}': {s}", .{ assembly_out_file_name, errorDescription(er) });1425 return d.fatal("unable to write to output file '{s}': {s}", .{ assembly_out_file_name, errorDescription(er) });
1424 try d.invokeAssembler(tc, assembly_out_file_name, out_file_name);1426 try d.invokeAssembler(tc, assembly_out_file_name, out_file_name);
...@@ -1454,7 +1456,7 @@ fn processSource(...@@ -1454,7 +1456,7 @@ fn processSource(
14541456
1455 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|1457 const out_file = d.comp.cwd.createFile(out_file_name, .{}) catch |er|
1456 return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });1458 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
1459 var file_writer = out_file.writer(&writer_buf);1461 var file_writer = out_file.writer(&writer_buf);
1460 obj.finish(&file_writer.interface) catch1462 obj.finish(&file_writer.interface) catch
lib/compiler/aro/aro/Driver/Filesystem.zig+15-13
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1const std = @import("std");
2const mem = std.mem;
3const builtin = @import("builtin");1const builtin = @import("builtin");
4const is_windows = builtin.os.tag == .windows;2const is_windows = builtin.os.tag == .windows;
53
4const std = @import("std");
5const Io = std.Io;
6const mem = std.std.mem;
7
6fn readFileFake(entries: []const Filesystem.Entry, path: []const u8, buf: []u8) ?[]const u8 {8fn readFileFake(entries: []const Filesystem.Entry, path: []const u8, buf: []u8) ?[]const u8 {
7 @branchHint(.cold);9 @branchHint(.cold);
8 for (entries) |entry| {10 for (entries) |entry| {
...@@ -96,7 +98,7 @@ fn findProgramByNamePosix(name: []const u8, path: ?[]const u8, buf: []u8) ?[]con...@@ -96,7 +98,7 @@ fn findProgramByNamePosix(name: []const u8, path: ?[]const u8, buf: []u8) ?[]con
96}98}
9799
98pub const Filesystem = union(enum) {100pub const Filesystem = union(enum) {
99 real: std.fs.Dir,101 real: std.Io.Dir,
100 fake: []const Entry,102 fake: []const Entry,
101103
102 const Entry = struct {104 const Entry = struct {
...@@ -121,7 +123,7 @@ pub const Filesystem = union(enum) {...@@ -121,7 +123,7 @@ pub const Filesystem = union(enum) {
121 base: []const u8,123 base: []const u8,
122 i: usize = 0,124 i: usize = 0,
123125
124 fn next(self: *@This()) !?std.fs.Dir.Entry {126 fn next(self: *@This()) !?std.Io.Dir.Entry {
125 while (self.i < self.entries.len) {127 while (self.i < self.entries.len) {
126 const entry = self.entries[self.i];128 const entry = self.entries[self.i];
127 self.i += 1;129 self.i += 1;
...@@ -130,7 +132,7 @@ pub const Filesystem = union(enum) {...@@ -130,7 +132,7 @@ pub const Filesystem = union(enum) {
130 const remaining = entry.path[self.base.len + 1 ..];132 const remaining = entry.path[self.base.len + 1 ..];
131 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;133 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;
132 const extension = std.fs.path.extension(remaining);134 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;
134 return .{ .name = remaining, .kind = kind };136 return .{ .name = remaining, .kind = kind };
135 }137 }
136 }138 }
...@@ -140,7 +142,7 @@ pub const Filesystem = union(enum) {...@@ -140,7 +142,7 @@ pub const Filesystem = union(enum) {
140 };142 };
141143
142 const Dir = union(enum) {144 const Dir = union(enum) {
143 dir: std.fs.Dir,145 dir: std.Io.Dir,
144 fake: FakeDir,146 fake: FakeDir,
145147
146 pub fn iterate(self: Dir) Iterator {148 pub fn iterate(self: Dir) Iterator {
...@@ -150,19 +152,19 @@ pub const Filesystem = union(enum) {...@@ -150,19 +152,19 @@ pub const Filesystem = union(enum) {
150 };152 };
151 }153 }
152154
153 pub fn close(self: *Dir) void {155 pub fn close(self: *Dir, io: Io) void {
154 switch (self.*) {156 switch (self.*) {
155 .dir => |*d| d.close(),157 .dir => |*d| d.close(io),
156 .fake => {},158 .fake => {},
157 }159 }
158 }160 }
159 };161 };
160162
161 const Iterator = union(enum) {163 const Iterator = union(enum) {
162 iterator: std.fs.Dir.Iterator,164 iterator: std.Io.Dir.Iterator,
163 fake: FakeDir.Iterator,165 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 {
166 return switch (self.*) {168 return switch (self.*) {
167 .iterator => |*it| it.next(),169 .iterator => |*it| it.next(),
168 .fake => |*it| it.next(),170 .fake => |*it| it.next(),
...@@ -208,11 +210,11 @@ pub const Filesystem = union(enum) {...@@ -208,11 +210,11 @@ pub const Filesystem = union(enum) {
208 /// Read the file at `path` into `buf`.210 /// Read the file at `path` into `buf`.
209 /// Returns null if any errors are encountered211 /// Returns null if any errors are encountered
210 /// Otherwise returns a slice of `buf`. If the file is larger than `buf` partial contents are returned212 /// 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 {
212 return switch (fs) {214 return switch (fs) {
213 .real => |cwd| {215 .real => |cwd| {
214 const file = cwd.openFile(path, .{}) catch return null;216 const file = cwd.openFile(path, .{}) catch return null;
215 defer file.close();217 defer file.close(io);
216218
217 const bytes_read = file.readAll(buf) catch return null;219 const bytes_read = file.readAll(buf) catch return null;
218 return buf[0..bytes_read];220 return buf[0..bytes_read];
...@@ -221,7 +223,7 @@ pub const Filesystem = union(enum) {...@@ -221,7 +223,7 @@ pub const Filesystem = union(enum) {
221 };223 };
222 }224 }
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 {
225 return switch (fs) {227 return switch (fs) {
226 .real => |cwd| .{ .dir = try cwd.openDir(dir_name, .{ .access_sub_paths = false, .iterate = true }) },228 .real => |cwd| .{ .dir = try cwd.openDir(dir_name, .{ .access_sub_paths = false, .iterate = true }) },
227 .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } },229 .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 {...@@ -497,6 +497,7 @@ pub fn addBuiltinIncludeDir(tc: *const Toolchain) !void {
497 const comp = d.comp;497 const comp = d.comp;
498 const gpa = comp.gpa;498 const gpa = comp.gpa;
499 const arena = comp.arena;499 const arena = comp.arena;
500 const io = comp.io;
500 try d.includes.ensureUnusedCapacity(gpa, 1);501 try d.includes.ensureUnusedCapacity(gpa, 1);
501 if (d.resource_dir) |resource_dir| {502 if (d.resource_dir) |resource_dir| {
502 const path = try std.fs.path.join(arena, &.{ resource_dir, "include" });503 const path = try std.fs.path.join(arena, &.{ resource_dir, "include" });
...@@ -509,7 +510,7 @@ pub fn addBuiltinIncludeDir(tc: *const Toolchain) !void {...@@ -509,7 +510,7 @@ pub fn addBuiltinIncludeDir(tc: *const Toolchain) !void {
509 var search_path = d.aro_name;510 var search_path = d.aro_name;
510 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {511 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
511 var base_dir = d.comp.cwd.openDir(dirname, .{}) catch continue;512 var base_dir = d.comp.cwd.openDir(dirname, .{}) catch continue;
512 defer base_dir.close();513 defer base_dir.close(io);
513514
514 base_dir.access("include/stddef.h", .{}) catch continue;515 base_dir.access("include/stddef.h", .{}) catch continue;
515 const path = try std.fs.path.join(arena, &.{ dirname, "include" });516 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...@@ -152,7 +152,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
152 const io = threaded.io();152 const io = threaded.io();
153153
154 const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });154 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
157 const stat = input_file.stat() catch |err| fatal("failed to stat {s}: {t}", .{ input, err });157 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...@@ -180,7 +180,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
180 const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode;180 const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode;
181181
182 var output_file = try fs.cwd().createFile(output, .{ .mode = mode });182 var output_file = try fs.cwd().createFile(output, .{ .mode = mode });
183 defer output_file.close();183 defer output_file.close(io);
184184
185 var out = output_file.writer(&output_buffer);185 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" {...@@ -1991,6 +1991,8 @@ test "parse: input and output formats" {
1991}1991}
19921992
1993test "maybeAppendRC" {1993test "maybeAppendRC" {
1994 const io = std.testing.io;
1995
1994 var tmp = std.testing.tmpDir(.{});1996 var tmp = std.testing.tmpDir(.{});
1995 defer tmp.cleanup();1997 defer tmp.cleanup();
19961998
...@@ -2001,7 +2003,7 @@ test "maybeAppendRC" {...@@ -2001,7 +2003,7 @@ test "maybeAppendRC" {
2001 // Create the file so that it's found. In this scenario, .rc should not get2003 // Create the file so that it's found. In this scenario, .rc should not get
2002 // appended.2004 // appended.
2003 var file = try tmp.dir.createFile("foo", .{});2005 var file = try tmp.dir.createFile("foo", .{});
2004 file.close();2006 file.close(io);
2005 try options.maybeAppendRC(tmp.dir);2007 try options.maybeAppendRC(tmp.dir);
2006 try std.testing.expectEqualStrings("foo", options.input_source.filename);2008 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");...@@ -34,7 +34,7 @@ const code_pages = @import("code_pages.zig");
34const errors = @import("errors.zig");34const errors = @import("errors.zig");
3535
36pub const CompileOptions = struct {36pub const CompileOptions = struct {
37 cwd: std.fs.Dir,37 cwd: std.Io.Dir,
38 diagnostics: *Diagnostics,38 diagnostics: *Diagnostics,
39 source_mappings: ?*SourceMappings = null,39 source_mappings: ?*SourceMappings = null,
40 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.40 /// 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...@@ -107,7 +107,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
107 // the cwd so we don't need to add it as a distinct search path.107 // the cwd so we don't need to add it as a distinct search path.
108 if (std.fs.path.dirname(root_path)) |root_dir_path| {108 if (std.fs.path.dirname(root_path)) |root_dir_path| {
109 var root_dir = try options.cwd.openDir(root_dir_path, .{});109 var root_dir = try options.cwd.openDir(root_dir_path, .{});
110 errdefer root_dir.close();110 errdefer root_dir.close(io);
111 try search_dirs.append(allocator, .{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });111 try search_dirs.append(allocator, .{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });
112 }112 }
113 }113 }
...@@ -136,7 +136,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io...@@ -136,7 +136,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
136 // TODO: maybe a warning that the search path is skipped?136 // TODO: maybe a warning that the search path is skipped?
137 continue;137 continue;
138 };138 };
139 errdefer dir.close();139 errdefer dir.close(io);
140 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });140 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });
141 }141 }
142 for (options.system_include_paths) |system_include_path| {142 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...@@ -144,7 +144,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
144 // TODO: maybe a warning that the search path is skipped?144 // TODO: maybe a warning that the search path is skipped?
145 continue;145 continue;
146 };146 };
147 errdefer dir.close();147 errdefer dir.close(io);
148 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });148 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });
149 }149 }
150 if (!options.ignore_include_env_var) {150 if (!options.ignore_include_env_var) {
...@@ -160,7 +160,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io...@@ -160,7 +160,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io
160 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);160 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
161 while (it.next()) |search_path| {161 while (it.next()) |search_path| {
162 var dir = openSearchPathDir(options.cwd, search_path) catch continue;162 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
163 errdefer dir.close();163 errdefer dir.close(io);
164 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, search_path) });164 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, search_path) });
165 }165 }
166 }166 }
...@@ -196,7 +196,7 @@ pub const Compiler = struct {...@@ -196,7 +196,7 @@ pub const Compiler = struct {
196 arena: Allocator,196 arena: Allocator,
197 allocator: Allocator,197 allocator: Allocator,
198 io: Io,198 io: Io,
199 cwd: std.fs.Dir,199 cwd: std.Io.Dir,
200 state: State = .{},200 state: State = .{},
201 diagnostics: *Diagnostics,201 diagnostics: *Diagnostics,
202 dependencies: ?*Dependencies,202 dependencies: ?*Dependencies,
...@@ -388,7 +388,9 @@ pub const Compiler = struct {...@@ -388,7 +388,9 @@ pub const Compiler = struct {
388 /// matching file is invalid. That is, it does not do the `cmd` PATH searching388 /// matching file is invalid. That is, it does not do the `cmd` PATH searching
389 /// thing of continuing to look for matching files until it finds a valid389 /// thing of continuing to look for matching files until it finds a valid
390 /// one if a matching file is invalid.390 /// 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
392 // If the path is absolute, then it is not resolved relative to any search394 // If the path is absolute, then it is not resolved relative to any search
393 // paths, so there's no point in checking them.395 // paths, so there's no point in checking them.
394 //396 //
...@@ -405,7 +407,7 @@ pub const Compiler = struct {...@@ -405,7 +407,7 @@ pub const Compiler = struct {
405 // an absolute path.407 // an absolute path.
406 if (std.fs.path.isAbsolute(path)) {408 if (std.fs.path.isAbsolute(path)) {
407 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});409 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});
408 errdefer file.close();410 errdefer file.close(io);
409411
410 if (self.dependencies) |dependencies| {412 if (self.dependencies) |dependencies| {
411 const duped_path = try dependencies.allocator.dupe(u8, path);413 const duped_path = try dependencies.allocator.dupe(u8, path);
...@@ -414,10 +416,10 @@ pub const Compiler = struct {...@@ -414,10 +416,10 @@ pub const Compiler = struct {
414 }416 }
415 }417 }
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;
418 for (self.search_dirs) |search_dir| {420 for (self.search_dirs) |search_dir| {
419 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {421 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {
420 errdefer file.close();422 errdefer file.close(io);
421423
422 if (self.dependencies) |dependencies| {424 if (self.dependencies) |dependencies| {
423 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{425 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{
...@@ -587,7 +589,7 @@ pub const Compiler = struct {...@@ -587,7 +589,7 @@ pub const Compiler = struct {
587 });589 });
588 },590 },
589 };591 };
590 defer file_handle.close();592 defer file_handle.close(io);
591 var file_buffer: [2048]u8 = undefined;593 var file_buffer: [2048]u8 = undefined;
592 var file_reader = file_handle.reader(io, &file_buffer);594 var file_reader = file_handle.reader(io, &file_buffer);
593595
...@@ -2892,9 +2894,9 @@ pub const Compiler = struct {...@@ -2892,9 +2894,9 @@ pub const Compiler = struct {
2892 }2894 }
2893};2895};
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 {
2898 // Validate the search path to avoid possible unreachable on invalid paths,2900 // Validate the search path to avoid possible unreachable on invalid paths,
2899 // see https://github.com/ziglang/zig/issues/15607 for why this is currently necessary.2901 // see https://github.com/ziglang/zig/issues/15607 for why this is currently necessary.
2900 try validateSearchPath(path);2902 try validateSearchPath(path);
...@@ -2927,11 +2929,11 @@ fn validateSearchPath(path: []const u8) error{BadPathName}!void {...@@ -2927,11 +2929,11 @@ fn validateSearchPath(path: []const u8) error{BadPathName}!void {
2927}2929}
29282930
2929pub const SearchDir = struct {2931pub const SearchDir = struct {
2930 dir: std.fs.Dir,2932 dir: std.Io.Dir,
2931 path: ?[]const u8,2933 path: ?[]const u8,
29322934
2933 pub fn deinit(self: *SearchDir, allocator: Allocator) void {2935 pub fn deinit(self: *SearchDir, allocator: Allocator, io: Io) void {
2934 self.dir.close();2936 self.dir.close(io);
2935 if (self.path) |path| {2937 if (self.path) |path| {
2936 allocator.free(path);2938 allocator.free(path);
2937 }2939 }
lib/compiler/resinator/errors.zig+2-2
...@@ -1221,8 +1221,8 @@ const CorrespondingLines = struct {...@@ -1221,8 +1221,8 @@ const CorrespondingLines = struct {
1221 };1221 };
1222 }1222 }
12231223
1224 pub fn deinit(self: *CorrespondingLines) void {1224 pub fn deinit(self: *CorrespondingLines, io: Io) void {
1225 self.file.close();1225 self.file.close(io);
1226 }1226 }
1227};1227};
12281228
lib/compiler/resinator/main.zig+7-7
...@@ -296,7 +296,7 @@ pub fn main() !void {...@@ -296,7 +296,7 @@ pub fn main() !void {
296 error.ParseError, error.CompileError => {296 error.ParseError, error.CompileError => {
297 try error_handler.emitDiagnostics(gpa, std.fs.cwd(), final_input, &diagnostics, mapping_results.mappings);297 try error_handler.emitDiagnostics(gpa, std.fs.cwd(), final_input, &diagnostics, mapping_results.mappings);
298 // Delete the output file on error298 // Delete the output file on error
299 res_stream.cleanupAfterError();299 res_stream.cleanupAfterError(io);
300 std.process.exit(1);300 std.process.exit(1);
301 },301 },
302 else => |e| return e,302 else => |e| return e,
...@@ -315,7 +315,7 @@ pub fn main() !void {...@@ -315,7 +315,7 @@ pub fn main() !void {
315 try error_handler.emitMessage(gpa, .err, "unable to create depfile '{s}': {s}", .{ depfile_path, @errorName(err) });315 try error_handler.emitMessage(gpa, .err, "unable to create depfile '{s}': {s}", .{ depfile_path, @errorName(err) });
316 std.process.exit(1);316 std.process.exit(1);
317 };317 };
318 defer depfile.close();318 defer depfile.close(io);
319319
320 var depfile_buffer: [1024]u8 = undefined;320 var depfile_buffer: [1024]u8 = undefined;
321 var depfile_writer = depfile.writer(&depfile_buffer);321 var depfile_writer = depfile.writer(&depfile_buffer);
...@@ -402,7 +402,7 @@ pub fn main() !void {...@@ -402,7 +402,7 @@ pub fn main() !void {
402 },402 },
403 }403 }
404 // Delete the output file on error404 // Delete the output file on error
405 coff_stream.cleanupAfterError();405 coff_stream.cleanupAfterError(io);
406 std.process.exit(1);406 std.process.exit(1);
407 };407 };
408408
...@@ -434,11 +434,11 @@ const IoStream = struct {...@@ -434,11 +434,11 @@ const IoStream = struct {
434 self.source.deinit(allocator);434 self.source.deinit(allocator);
435 }435 }
436436
437 pub fn cleanupAfterError(self: *IoStream) void {437 pub fn cleanupAfterError(self: *IoStream, io: Io) void {
438 switch (self.source) {438 switch (self.source) {
439 .file => |file| {439 .file => |file| {
440 // Delete the output file on error440 // Delete the output file on error
441 file.close();441 file.close(io);
442 // Failing to delete is not really a big deal, so swallow any errors442 // Failing to delete is not really a big deal, so swallow any errors
443 std.fs.cwd().deleteFile(self.name) catch {};443 std.fs.cwd().deleteFile(self.name) catch {};
444 },444 },
...@@ -465,9 +465,9 @@ const IoStream = struct {...@@ -465,9 +465,9 @@ const IoStream = struct {
465 }465 }
466 }466 }
467467
468 pub fn deinit(self: *Source, allocator: Allocator) void {468 pub fn deinit(self: *Source, allocator: Allocator, io: Io) void {
469 switch (self.*) {469 switch (self.*) {
470 .file => |file| file.close(),470 .file => |file| file.close(io),
471 .stdio => {},471 .stdio => {},
472 .memory => |*list| list.deinit(allocator),472 .memory => |*list| list.deinit(allocator),
473 .closed => {},473 .closed => {},
lib/compiler/resinator/utils.zig+6-3
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const std = @import("std");
2const builtin = @import("builtin");1const builtin = @import("builtin");
32
3const std = @import("std");
4const Io = std.Io;
5
4pub const UncheckedSliceWriter = struct {6pub const UncheckedSliceWriter = struct {
5 const Self = @This();7 const Self = @This();
68
...@@ -28,11 +30,12 @@ pub const UncheckedSliceWriter = struct {...@@ -28,11 +30,12 @@ pub const UncheckedSliceWriter = struct {
28/// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed.30/// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed.
29pub fn openFileNotDir(31pub fn openFileNotDir(
30 cwd: std.fs.Dir,32 cwd: std.fs.Dir,
33 io: Io,
31 path: []const u8,34 path: []const u8,
32 flags: std.fs.File.OpenFlags,35 flags: std.fs.File.OpenFlags,
33) (std.fs.File.OpenError || std.fs.File.StatError)!std.fs.File {36) (std.fs.File.OpenError || std.fs.File.StatError)!std.fs.File {
34 const file = try cwd.openFile(path, flags);37 const file = try cwd.openFile(io, path, flags);
35 errdefer file.close();38 errdefer file.close(io);
36 // https://github.com/ziglang/zig/issues/573239 // https://github.com/ziglang/zig/issues/5732
37 if (builtin.os.tag != .windows) {40 if (builtin.os.tag != .windows) {
38 const stat = try file.stat();41 const stat = try file.stat();
lib/compiler/std-docs.zig+22-11
...@@ -1,12 +1,14 @@...@@ -1,12 +1,14 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2
2const std = @import("std");3const std = @import("std");
4const Io = std.Io;
3const mem = std.mem;5const mem = std.mem;
4const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
5const assert = std.debug.assert;7const assert = std.debug.assert;
6const Cache = std.Build.Cache;8const Cache = std.Build.Cache;
79
8fn usage() noreturn {10fn usage() noreturn {
9 std.fs.File.stdout().writeAll(11 std.Io.File.stdout().writeAll(
10 \\Usage: zig std [options]12 \\Usage: zig std [options]
11 \\13 \\
12 \\Options:14 \\Options:
...@@ -27,6 +29,10 @@ pub fn main() !void {...@@ -27,6 +29,10 @@ pub fn main() !void {
27 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .init;29 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .init;
28 const gpa = general_purpose_allocator.allocator();30 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
30 var argv = try std.process.argsWithAllocator(arena);36 var argv = try std.process.argsWithAllocator(arena);
31 defer argv.deinit();37 defer argv.deinit();
32 assert(argv.skip());38 assert(argv.skip());
...@@ -35,7 +41,7 @@ pub fn main() !void {...@@ -35,7 +41,7 @@ pub fn main() !void {
35 const global_cache_path = argv.next().?;41 const global_cache_path = argv.next().?;
3642
37 var lib_dir = try std.fs.cwd().openDir(zig_lib_directory, .{});43 var lib_dir = try std.fs.cwd().openDir(zig_lib_directory, .{});
38 defer lib_dir.close();44 defer lib_dir.close(io);
3945
40 var listen_port: u16 = 0;46 var listen_port: u16 = 0;
41 var force_open_browser: ?bool = null;47 var force_open_browser: ?bool = null;
...@@ -64,7 +70,7 @@ pub fn main() !void {...@@ -64,7 +70,7 @@ pub fn main() !void {
64 });70 });
65 const port = http_server.listen_address.in.getPort();71 const port = http_server.listen_address.in.getPort();
66 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});72 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
67 std.fs.File.stdout().writeAll(url_with_newline) catch {};73 std.Io.File.stdout().writeAll(url_with_newline) catch {};
68 if (should_open_browser) {74 if (should_open_browser) {
69 openBrowserTab(gpa, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {75 openBrowserTab(gpa, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {
70 std.log.err("unable to open browser: {s}", .{@errorName(err)});76 std.log.err("unable to open browser: {s}", .{@errorName(err)});
...@@ -73,6 +79,7 @@ pub fn main() !void {...@@ -73,6 +79,7 @@ pub fn main() !void {
7379
74 var context: Context = .{80 var context: Context = .{
75 .gpa = gpa,81 .gpa = gpa,
82 .io = io,
76 .zig_exe_path = zig_exe_path,83 .zig_exe_path = zig_exe_path,
77 .global_cache_path = global_cache_path,84 .global_cache_path = global_cache_path,
78 .lib_dir = lib_dir,85 .lib_dir = lib_dir,
...@@ -83,14 +90,15 @@ pub fn main() !void {...@@ -83,14 +90,15 @@ pub fn main() !void {
83 const connection = try http_server.accept();90 const connection = try http_server.accept();
84 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {91 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {
85 std.log.err("unable to accept connection: {s}", .{@errorName(err)});92 std.log.err("unable to accept connection: {s}", .{@errorName(err)});
86 connection.stream.close();93 connection.stream.close(io);
87 continue;94 continue;
88 };95 };
89 }96 }
90}97}
9198
92fn accept(context: *Context, connection: std.net.Server.Connection) void {99fn 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
95 var recv_buffer: [4000]u8 = undefined;103 var recv_buffer: [4000]u8 = undefined;
96 var send_buffer: [4000]u8 = undefined;104 var send_buffer: [4000]u8 = undefined;
...@@ -124,6 +132,7 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {...@@ -124,6 +132,7 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {
124132
125const Context = struct {133const Context = struct {
126 gpa: Allocator,134 gpa: Allocator,
135 io: Io,
127 lib_dir: std.fs.Dir,136 lib_dir: std.fs.Dir,
128 zig_lib_directory: []const u8,137 zig_lib_directory: []const u8,
129 zig_exe_path: []const u8,138 zig_exe_path: []const u8,
...@@ -185,6 +194,7 @@ fn serveDocsFile(...@@ -185,6 +194,7 @@ fn serveDocsFile(
185194
186fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {195fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
187 const gpa = context.gpa;196 const gpa = context.gpa;
197 const io = context.io;
188198
189 var send_buffer: [0x4000]u8 = undefined;199 var send_buffer: [0x4000]u8 = undefined;
190 var response = try request.respondStreaming(&send_buffer, .{200 var response = try request.respondStreaming(&send_buffer, .{
...@@ -197,7 +207,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {...@@ -197,7 +207,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
197 });207 });
198208
199 var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });209 var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });
200 defer std_dir.close();210 defer std_dir.close(io);
201211
202 var walker = try std_dir.walk(gpa);212 var walker = try std_dir.walk(gpa);
203 defer walker.deinit();213 defer walker.deinit();
...@@ -216,11 +226,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {...@@ -216,11 +226,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
216 else => continue,226 else => continue,
217 }227 }
218 var file = try entry.dir.openFile(entry.basename, .{});228 var file = try entry.dir.openFile(entry.basename, .{});
219 defer file.close();229 defer file.close(io);
220 const stat = try file.stat();230 const stat = try file.stat();
221 var file_reader: std.fs.File.Reader = .{231 var file_reader: std.Io.File.Reader = .{
222 .file = file,232 .file = file,
223 .interface = std.fs.File.Reader.initInterface(&.{}),233 .interface = std.Io.File.Reader.initInterface(&.{}),
224 .size = stat.size,234 .size = stat.size,
225 };235 };
226 try archiver.writeFile(entry.path, &file_reader, stat.mtime);236 try archiver.writeFile(entry.path, &file_reader, stat.mtime);
...@@ -283,6 +293,7 @@ fn buildWasmBinary(...@@ -283,6 +293,7 @@ fn buildWasmBinary(
283 optimize_mode: std.builtin.OptimizeMode,293 optimize_mode: std.builtin.OptimizeMode,
284) !Cache.Path {294) !Cache.Path {
285 const gpa = context.gpa;295 const gpa = context.gpa;
296 const io = context.io;
286297
287 var argv: std.ArrayList([]const u8) = .empty;298 var argv: std.ArrayList([]const u8) = .empty;
288299
...@@ -371,7 +382,7 @@ fn buildWasmBinary(...@@ -371,7 +382,7 @@ fn buildWasmBinary(
371 }382 }
372383
373 // Send EOF to stdin.384 // Send EOF to stdin.
374 child.stdin.?.close();385 child.stdin.?.close(io);
375 child.stdin = null;386 child.stdin = null;
376387
377 switch (try child.wait()) {388 switch (try child.wait()) {
...@@ -410,7 +421,7 @@ fn buildWasmBinary(...@@ -410,7 +421,7 @@ fn buildWasmBinary(
410 };421 };
411}422}
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 {
414 const header: std.zig.Client.Message.Header = .{425 const header: std.zig.Client.Message.Header = .{
415 .tag = tag,426 .tag = tag,
416 .bytes_len = 0,427 .bytes_len = 0,
lib/compiler/translate-c/main.zig+3-2
...@@ -121,6 +121,7 @@ pub const usage =...@@ -121,6 +121,7 @@ pub const usage =
121121
122fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration: bool) !void {122fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration: bool) !void {
123 const gpa = d.comp.gpa;123 const gpa = d.comp.gpa;
124 const io = d.comp.io;
124125
125 const aro_args = args: {126 const aro_args = args: {
126 var i: usize = 0;127 var i: usize = 0;
...@@ -228,7 +229,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration...@@ -228,7 +229,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration
228 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, aro.Driver.errorDescription(er) })229 return d.fatal("unable to create dependency file '{s}': {s}", .{ path, aro.Driver.errorDescription(er) })
229 else230 else
230 std.fs.File.stdout();231 std.fs.File.stdout();
231 defer if (dep_file_name != null) file.close();232 defer if (dep_file_name != null) file.close(io);
232233
233 var file_writer = file.writer(&out_buf);234 var file_writer = file.writer(&out_buf);
234 dep_file.write(&file_writer.interface) catch235 dep_file.write(&file_writer.interface) catch
...@@ -246,7 +247,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration...@@ -246,7 +247,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration
246 var close_out_file = false;247 var close_out_file = false;
247 var out_file_path: []const u8 = "<stdout>";248 var out_file_path: []const u8 = "<stdout>";
248 var out_file: std.fs.File = .stdout();249 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
251 if (d.output_name) |path| blk: {252 if (d.output_name) |path| blk: {
252 if (std.mem.eql(u8, path, "-")) break :blk;253 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) !...@@ -52,8 +52,8 @@ pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) !
52/// Whether or not the handle should be closed, or the path should be freed52/// Whether or not the handle should be closed, or the path should be freed
53/// is determined by usage, however this function is provided for convenience53/// is determined by usage, however this function is provided for convenience
54/// if it happens to be what the caller needs.54/// if it happens to be what the caller needs.
55pub fn closeAndFree(self: *Directory, gpa: Allocator) void {55pub fn closeAndFree(self: *Directory, gpa: Allocator, io: Io) void {
56 self.handle.close();56 self.handle.close(io);
57 if (self.path) |p| gpa.free(p);57 if (self.path) |p| gpa.free(p);
58 self.* = undefined;58 self.* = undefined;
59}59}
lib/std/Build/Fuzz.zig+2-2
...@@ -411,7 +411,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO...@@ -411,7 +411,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
411 });411 });
412 return error.AlreadyReported;412 return error.AlreadyReported;
413 };413 };
414 defer coverage_file.close();414 defer coverage_file.close(io);
415415
416 const file_size = coverage_file.getEndPos() catch |err| {416 const file_size = coverage_file.getEndPos() catch |err| {
417 log.err("unable to check len of coverage file '{f}': {t}", .{ coverage_file_path, err });417 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 {...@@ -533,7 +533,7 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) void {
533 cov.run.step.name, coverage_file_path, err,533 cov.run.step.name, coverage_file_path, err,
534 });534 });
535 };535 };
536 defer coverage_file.close();536 defer coverage_file.close(io);
537537
538 const fuzz_abi = std.Build.abi.fuzz;538 const fuzz_abi = std.Build.abi.fuzz;
539 var rbuf: [0x1000]u8 = undefined;539 var rbuf: [0x1000]u8 = undefined;
lib/std/Build/Step.zig+2-1
...@@ -441,6 +441,7 @@ pub fn evalZigProcess(...@@ -441,6 +441,7 @@ pub fn evalZigProcess(
441 assert(argv.len != 0);441 assert(argv.len != 0);
442 const b = s.owner;442 const b = s.owner;
443 const arena = b.allocator;443 const arena = b.allocator;
444 const io = b.graph.io;
444445
445 try handleChildProcUnsupported(s);446 try handleChildProcUnsupported(s);
446 try handleVerbose(s.owner, null, argv);447 try handleVerbose(s.owner, null, argv);
...@@ -474,7 +475,7 @@ pub fn evalZigProcess(...@@ -474,7 +475,7 @@ pub fn evalZigProcess(
474475
475 if (!watch) {476 if (!watch) {
476 // Send EOF to stdin.477 // Send EOF to stdin.
477 zp.child.stdin.?.close();478 zp.child.stdin.?.close(io);
478 zp.child.stdin = null;479 zp.child.stdin = null;
479480
480 const term = zp.child.wait() catch |err| {481 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 {...@@ -119,6 +119,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
119 _ = options;119 _ = options;
120 const install_artifact: *InstallArtifact = @fieldParentPtr("step", step);120 const install_artifact: *InstallArtifact = @fieldParentPtr("step", step);
121 const b = step.owner;121 const b = step.owner;
122 const io = b.graph.io;
122123
123 var all_cached = true;124 var all_cached = true;
124125
...@@ -168,7 +169,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -168,7 +169,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
168 src_dir_path, @errorName(err),169 src_dir_path, @errorName(err),
169 });170 });
170 };171 };
171 defer src_dir.close();172 defer src_dir.close(io);
172173
173 var it = try src_dir.walk(b.allocator);174 var it = try src_dir.walk(b.allocator);
174 next_entry: while (try it.next()) |entry| {175 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 {...@@ -68,7 +68,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
68 var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {68 var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
69 return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err });69 return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err });
70 };70 };
71 defer src_dir.close();71 defer src_dir.close(io);
72 var it = try src_dir.walk(arena);72 var it = try src_dir.walk(arena);
73 var all_cached = true;73 var all_cached = true;
74 next_entry: while (try it.next()) |entry| {74 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 {...@@ -851,7 +851,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
851 .{ file_path, err },851 .{ file_path, err },
852 );852 );
853 };853 };
854 defer file.close();854 defer file.close(io);
855855
856 var buf: [1024]u8 = undefined;856 var buf: [1024]u8 = undefined;
857 var file_reader = file.reader(io, &buf);857 var file_reader = file.reader(io, &buf);
...@@ -1111,7 +1111,7 @@ pub fn rerunInFuzzMode(...@@ -1111,7 +1111,7 @@ pub fn rerunInFuzzMode(
1111 result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory;1111 result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory;
11121112
1113 const file = try file_path.root_dir.handle.openFile(file_path.subPathOrDot(), .{});1113 const file = try file_path.root_dir.handle.openFile(file_path.subPathOrDot(), .{});
1114 defer file.close();1114 defer file.close(io);
11151115
1116 var buf: [1024]u8 = undefined;1116 var buf: [1024]u8 = undefined;
1117 var file_reader = file.reader(io, &buf);1117 var file_reader = file.reader(io, &buf);
...@@ -1671,8 +1671,10 @@ fn evalZigTest(...@@ -1671,8 +1671,10 @@ fn evalZigTest(
1671 options: Step.MakeOptions,1671 options: Step.MakeOptions,
1672 fuzz_context: ?FuzzContext,1672 fuzz_context: ?FuzzContext,
1673) !EvalZigTestResult {1673) !EvalZigTestResult {
1674 const gpa = run.step.owner.allocator;1674 const step_owner = run.step.owner;
1675 const arena = run.step.owner.allocator;1675 const gpa = step_owner.allocator;
1676 const arena = step_owner.allocator;
1677 const io = step_owner.graph.io;
16761678
1677 // We will update this every time a child runs.1679 // We will update this every time a child runs.
1678 run.step.result_peak_rss = 0;1680 run.step.result_peak_rss = 0;
...@@ -1724,7 +1726,7 @@ fn evalZigTest(...@@ -1724,7 +1726,7 @@ fn evalZigTest(
1724 run.step.result_stderr = try arena.dupe(u8, poller.reader(.stderr).buffered());1726 run.step.result_stderr = try arena.dupe(u8, poller.reader(.stderr).buffered());
17251727
1726 // Clean up everything and wait for the child to exit.1728 // Clean up everything and wait for the child to exit.
1727 child.stdin.?.close();1729 child.stdin.?.close(io);
1728 child.stdin = null;1730 child.stdin = null;
1729 poller.deinit();1731 poller.deinit();
1730 child_killed = true;1732 child_killed = true;
...@@ -1744,7 +1746,7 @@ fn evalZigTest(...@@ -1744,7 +1746,7 @@ fn evalZigTest(
1744 poller.reader(.stderr).tossBuffered();1746 poller.reader(.stderr).tossBuffered();
17451747
1746 // Clean up everything and wait for the child to exit.1748 // Clean up everything and wait for the child to exit.
1747 child.stdin.?.close();1749 child.stdin.?.close(io);
1748 child.stdin = null;1750 child.stdin = null;
1749 poller.deinit();1751 poller.deinit();
1750 child_killed = true;1752 child_killed = true;
...@@ -2177,7 +2179,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {...@@ -2177,7 +2179,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
2177 child.stdin.?.writeAll(bytes) catch |err| {2179 child.stdin.?.writeAll(bytes) catch |err| {
2178 return run.step.fail("unable to write stdin: {s}", .{@errorName(err)});2180 return run.step.fail("unable to write stdin: {s}", .{@errorName(err)});
2179 };2181 };
2180 child.stdin.?.close();2182 child.stdin.?.close(io);
2181 child.stdin = null;2183 child.stdin = null;
2182 },2184 },
2183 .lazy_path => |lazy_path| {2185 .lazy_path => |lazy_path| {
...@@ -2185,7 +2187,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {...@@ -2185,7 +2187,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
2185 const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {2187 const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
2186 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});2188 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
2187 };2189 };
2188 defer file.close();2190 defer file.close(io);
2189 // TODO https://github.com/ziglang/zig/issues/239552191 // TODO https://github.com/ziglang/zig/issues/23955
2190 var read_buffer: [1024]u8 = undefined;2192 var read_buffer: [1024]u8 = undefined;
2191 var file_reader = file.reader(io, &read_buffer);2193 var file_reader = file.reader(io, &read_buffer);
...@@ -2204,7 +2206,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {...@@ -2204,7 +2206,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
2204 stdin_writer.err.?,2206 stdin_writer.err.?,
2205 }),2207 }),
2206 };2208 };
2207 child.stdin.?.close();2209 child.stdin.?.close(io);
2208 child.stdin = null;2210 child.stdin = null;
2209 },2211 },
2210 .none => {},2212 .none => {},
lib/std/Build/Step/WriteFile.zig+6-4
...@@ -206,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -206,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
206 }206 }
207 }207 }
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);
210 var open_dirs_count: usize = 0;210 var open_dirs_count: usize = 0;
211 defer closeDirs(open_dir_cache[0..open_dirs_count]);211 defer closeDirs(open_dir_cache[0..open_dirs_count]);
212212
...@@ -264,7 +264,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -264,7 +264,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
264 b.cache_root, cache_path, @errorName(err),264 b.cache_root, cache_path, @errorName(err),
265 });265 });
266 };266 };
267 defer cache_dir.close();267 defer cache_dir.close(io);
268268
269 for (write_file.files.items) |file| {269 for (write_file.files.items) |file| {
270 if (fs.path.dirname(file.sub_path)) |dirname| {270 if (fs.path.dirname(file.sub_path)) |dirname| {
...@@ -342,6 +342,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -342,6 +342,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
342 try step.writeManifest(&man);342 try step.writeManifest(&man);
343}343}
344344
345fn closeDirs(dirs: []fs.Dir) void {345fn closeDirs(io: Io, dirs: []Io.Dir) void {
346 for (dirs) |*d| d.close();346 var group: Io.Group = .init;
347 defer group.wait();
348 for (dirs) |d| group.async(Io.Dir.close, .{ d, io });
347}349}
lib/std/Build/Watch/FsEvents.zig+5-4
...@@ -78,10 +78,10 @@ const ResolvedSymbols = struct {...@@ -78,10 +78,10 @@ const ResolvedSymbols = struct {
78 kCFAllocatorUseContext: *const CFAllocatorRef,78 kCFAllocatorUseContext: *const CFAllocatorRef,
79};79};
8080
81pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {81pub fn init(io: Io) error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
82 var core_services = std.DynLib.open("/System/Library/Frameworks/CoreServices.framework/CoreServices") catch82 var core_services = std.DynLib.open("/System/Library/Frameworks/CoreServices.framework/CoreServices") catch
83 return error.OpenFrameworkFailed;83 return error.OpenFrameworkFailed;
84 errdefer core_services.close();84 errdefer core_services.close(io);
8585
86 var resolved_symbols: ResolvedSymbols = undefined;86 var resolved_symbols: ResolvedSymbols = undefined;
87 inline for (@typeInfo(ResolvedSymbols).@"struct".fields) |f| {87 inline for (@typeInfo(ResolvedSymbols).@"struct".fields) |f| {
...@@ -102,10 +102,10 @@ pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {...@@ -102,10 +102,10 @@ pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
102 };102 };
103}103}
104104
105pub fn deinit(fse: *FsEvents, gpa: Allocator) void {105pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void {
106 dispatch_release(fse.waiting_semaphore);106 dispatch_release(fse.waiting_semaphore);
107 dispatch_release(fse.dispatch_queue);107 dispatch_release(fse.dispatch_queue);
108 fse.core_services.close();108 fse.core_services.close(io);
109109
110 gpa.free(fse.watch_roots);110 gpa.free(fse.watch_roots);
111 fse.watch_paths.deinit(gpa);111 fse.watch_paths.deinit(gpa);
...@@ -487,6 +487,7 @@ const FSEventStreamEventFlags = packed struct(u32) {...@@ -487,6 +487,7 @@ const FSEventStreamEventFlags = packed struct(u32) {
487};487};
488488
489const std = @import("std");489const std = @import("std");
490const Io = std.Io;
490const assert = std.debug.assert;491const assert = std.debug.assert;
491const Allocator = std.mem.Allocator;492const Allocator = std.mem.Allocator;
492const watch_log = std.log.scoped(.watch);493const watch_log = std.log.scoped(.watch);
lib/std/Build/WebServer.zig+4-3
...@@ -129,6 +129,7 @@ pub fn init(opts: Options) WebServer {...@@ -129,6 +129,7 @@ pub fn init(opts: Options) WebServer {
129}129}
130pub fn deinit(ws: *WebServer) void {130pub fn deinit(ws: *WebServer) void {
131 const gpa = ws.gpa;131 const gpa = ws.gpa;
132 const io = ws.graph.io;
132133
133 gpa.free(ws.step_names_trailing);134 gpa.free(ws.step_names_trailing);
134 gpa.free(ws.step_status_bits);135 gpa.free(ws.step_status_bits);
...@@ -139,7 +140,7 @@ pub fn deinit(ws: *WebServer) void {...@@ -139,7 +140,7 @@ pub fn deinit(ws: *WebServer) void {
139 gpa.free(ws.time_report_update_times);140 gpa.free(ws.time_report_update_times);
140141
141 if (ws.serve_thread) |t| {142 if (ws.serve_thread) |t| {
142 if (ws.tcp_server) |*s| s.stream.close();143 if (ws.tcp_server) |*s| s.stream.close(io);
143 t.join();144 t.join();
144 }145 }
145 if (ws.tcp_server) |*s| s.deinit();146 if (ws.tcp_server) |*s| s.deinit();
...@@ -507,7 +508,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons...@@ -507,7 +508,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons
507 log.err("failed to open '{f}': {s}", .{ path, @errorName(err) });508 log.err("failed to open '{f}': {s}", .{ path, @errorName(err) });
508 continue;509 continue;
509 };510 };
510 defer file.close();511 defer file.close(io);
511 const stat = try file.stat();512 const stat = try file.stat();
512 var read_buffer: [1024]u8 = undefined;513 var read_buffer: [1024]u8 = undefined;
513 var file_reader: Io.File.Reader = .initSize(file.adaptToNewApi(), io, &read_buffer, stat.size);514 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...@@ -634,7 +635,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
634 }635 }
635636
636 // Send EOF to stdin.637 // Send EOF to stdin.
637 child.stdin.?.close();638 child.stdin.?.close(io);
638 child.stdin = null;639 child.stdin = null;
639640
640 switch (try child.wait()) {641 switch (try child.wait()) {
lib/std/Io/Dir.zig+25-16
...@@ -131,7 +131,7 @@ pub const SelectiveWalker = struct {...@@ -131,7 +131,7 @@ pub const SelectiveWalker = struct {
131 /// After each call to this function, and on deinit(), the memory returned131 /// After each call to this function, and on deinit(), the memory returned
132 /// from this function becomes invalid. A copy must be made in order to keep132 /// from this function becomes invalid. A copy must be made in order to keep
133 /// a reference to the path.133 /// 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 {
135 while (self.stack.items.len > 0) {135 while (self.stack.items.len > 0) {
136 const top = &self.stack.items[self.stack.items.len - 1];136 const top = &self.stack.items[self.stack.items.len - 1];
137 var dirname_len = top.dirname_len;137 var dirname_len = top.dirname_len;
...@@ -142,7 +142,7 @@ pub const SelectiveWalker = struct {...@@ -142,7 +142,7 @@ pub const SelectiveWalker = struct {
142 // likely just fail with the same error.142 // likely just fail with the same error.
143 var item = self.stack.pop().?;143 var item = self.stack.pop().?;
144 if (self.stack.items.len != 0) {144 if (self.stack.items.len != 0) {
145 item.iter.dir.close();145 item.iter.dir.close(io);
146 }146 }
147 return err;147 return err;
148 }) |entry| {148 }) |entry| {
...@@ -164,7 +164,7 @@ pub const SelectiveWalker = struct {...@@ -164,7 +164,7 @@ pub const SelectiveWalker = struct {
164 } else {164 } else {
165 var item = self.stack.pop().?;165 var item = self.stack.pop().?;
166 if (self.stack.items.len != 0) {166 if (self.stack.items.len != 0) {
167 item.iter.dir.close();167 item.iter.dir.close(io);
168 }168 }
169 }169 }
170 }170 }
...@@ -172,7 +172,7 @@ pub const SelectiveWalker = struct {...@@ -172,7 +172,7 @@ pub const SelectiveWalker = struct {
172 }172 }
173173
174 /// Traverses into the directory, continuing walking one level down.174 /// 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 {
176 if (entry.kind != .directory) {176 if (entry.kind != .directory) {
177 @branchHint(.cold);177 @branchHint(.cold);
178 return;178 return;
...@@ -184,7 +184,7 @@ pub const SelectiveWalker = struct {...@@ -184,7 +184,7 @@ pub const SelectiveWalker = struct {
184 else => |e| return e,184 else => |e| return e,
185 }185 }
186 };186 };
187 errdefer new_dir.close();187 errdefer new_dir.close(io);
188188
189 try self.stack.append(self.allocator, .{189 try self.stack.append(self.allocator, .{
190 .iter = new_dir.iterateAssumeFirstIteration(),190 .iter = new_dir.iterateAssumeFirstIteration(),
...@@ -200,11 +200,11 @@ pub const SelectiveWalker = struct {...@@ -200,11 +200,11 @@ pub const SelectiveWalker = struct {
200 /// Leaves the current directory, continuing walking one level up.200 /// Leaves the current directory, continuing walking one level up.
201 /// If the current entry is a directory entry, then the "current directory"201 /// If the current entry is a directory entry, then the "current directory"
202 /// will pertain to that entry if `enter` is called before `leave`.202 /// 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 {
204 var item = self.stack.pop().?;204 var item = self.stack.pop().?;
205 if (self.stack.items.len != 0) {205 if (self.stack.items.len != 0) {
206 @branchHint(.likely);206 @branchHint(.likely);
207 item.iter.dir.close();207 item.iter.dir.close(io);
208 }208 }
209 }209 }
210};210};
...@@ -558,7 +558,8 @@ pub fn makeDir(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions)...@@ -558,7 +558,8 @@ pub fn makeDir(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions)
558558
559pub const MakePathError = MakeError || StatPathError;559pub 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.
562///563///
563/// Returns success if the path already exists and is a directory.564/// Returns success if the path already exists and is a directory.
564///565///
...@@ -579,8 +580,11 @@ pub const MakePathError = MakeError || StatPathError;...@@ -579,8 +580,11 @@ pub const MakePathError = MakeError || StatPathError;
579/// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`,580/// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`,
580/// meaning a `sub_path` like "first/../second" will create both a `./first`581/// meaning a `sub_path` like "first/../second" will create both a `./first`
581/// and a `./second` directory.582/// and a `./second` directory.
582pub fn makePath(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions) MakePathError!void {583///
583 _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, permissions);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);
584}588}
585589
586pub const MakePathStatus = enum { existed, created };590pub const MakePathStatus = enum { existed, created };
...@@ -593,6 +597,11 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8, permissions: Permi...@@ -593,6 +597,11 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8, permissions: Permi
593597
594pub const MakeOpenPathError = MakeError || OpenError || StatPathError;598pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
595599
600pub const MakeOpenPathOptions = struct {
601 open_options: OpenOptions = .{},
602 permissions: Permissions = .default_dir,
603};
604
596/// Performs the equivalent of `makePath` followed by `openDir`, atomically if possible.605/// Performs the equivalent of `makePath` followed by `openDir`, atomically if possible.
597///606///
598/// When this operation is canceled, it may leave the file system in a607/// When this operation is canceled, it may leave the file system in a
...@@ -601,8 +610,8 @@ pub const MakeOpenPathError = MakeError || OpenError || StatPathError;...@@ -601,8 +610,8 @@ pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
601/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).610/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
602/// On WASI, `sub_path` should be encoded as valid UTF-8.611/// On WASI, `sub_path` should be encoded as valid UTF-8.
603/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.612/// 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 {613pub fn makeOpenPath(dir: Dir, io: Io, sub_path: []const u8, options: MakeOpenPathOptions) MakeOpenPathError!Dir {
605 return io.vtable.dirMakeOpenPath(io.userdata, dir, sub_path, permissions, options);614 return io.vtable.dirMakeOpenPath(io.userdata, dir, sub_path, options.permissions, options.open_options);
606}615}
607616
608pub const Stat = File.Stat;617pub const Stat = File.Stat;
...@@ -1266,10 +1275,10 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,...@@ -1266,10 +1275,10 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
1266 start_over: while (true) {1275 start_over: while (true) {
1267 var dir = (try parent.deleteTreeOpenInitialSubpath(io, sub_path, kind_hint)) orelse return;1276 var dir = (try parent.deleteTreeOpenInitialSubpath(io, sub_path, kind_hint)) orelse return;
1268 var cleanup_dir_parent: ?Dir = null;1277 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
1271 var cleanup_dir = true;1280 var cleanup_dir = true;
1272 defer if (cleanup_dir) dir.close();1281 defer if (cleanup_dir) dir.close(io);
12731282
1274 // Valid use of max_path_bytes because dir_name_buf will only1283 // Valid use of max_path_bytes because dir_name_buf will only
1275 // ever store a single path component that was returned from the1284 // 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,...@@ -1315,7 +1324,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
1315 error.Canceled,1324 error.Canceled,
1316 => |e| return e,1325 => |e| return e,
1317 };1326 };
1318 if (cleanup_dir_parent) |*d| d.close();1327 if (cleanup_dir_parent) |*d| d.close(io);
1319 cleanup_dir_parent = dir;1328 cleanup_dir_parent = dir;
1320 dir = new_dir;1329 dir = new_dir;
1321 const result = dir_name_buf[0..entry.name.len];1330 const result = dir_name_buf[0..entry.name.len];
...@@ -1354,7 +1363,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,...@@ -1354,7 +1363,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8,
1354 }1363 }
1355 // Reached the end of the directory entries, which means we successfully deleted all of them.1364 // Reached the end of the directory entries, which means we successfully deleted all of them.
1356 // Now to remove the directory itself.1365 // Now to remove the directory itself.
1357 dir.close();1366 dir.close(io);
1358 cleanup_dir = false;1367 cleanup_dir = false;
13591368
1360 if (cleanup_dir_parent) |d| {1369 if (cleanup_dir_parent) |d| {
lib/std/Io/Writer.zig+3-3
...@@ -2835,7 +2835,7 @@ test "discarding sendFile" {...@@ -2835,7 +2835,7 @@ test "discarding sendFile" {
2835 defer tmp_dir.cleanup();2835 defer tmp_dir.cleanup();
28362836
2837 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });2837 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2838 defer file.close();2838 defer file.close(io);
2839 var r_buffer: [256]u8 = undefined;2839 var r_buffer: [256]u8 = undefined;
2840 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);2840 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2841 try file_writer.interface.writeByte('h');2841 try file_writer.interface.writeByte('h');
...@@ -2857,7 +2857,7 @@ test "allocating sendFile" {...@@ -2857,7 +2857,7 @@ test "allocating sendFile" {
2857 defer tmp_dir.cleanup();2857 defer tmp_dir.cleanup();
28582858
2859 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });2859 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2860 defer file.close();2860 defer file.close(io);
2861 var r_buffer: [2]u8 = undefined;2861 var r_buffer: [2]u8 = undefined;
2862 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);2862 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2863 try file_writer.interface.writeAll("abcd");2863 try file_writer.interface.writeAll("abcd");
...@@ -2881,7 +2881,7 @@ test sendFileReading {...@@ -2881,7 +2881,7 @@ test sendFileReading {
2881 defer tmp_dir.cleanup();2881 defer tmp_dir.cleanup();
28822882
2883 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });2883 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2884 defer file.close();2884 defer file.close(io);
2885 var r_buffer: [2]u8 = undefined;2885 var r_buffer: [2]u8 = undefined;
2886 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);2886 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2887 try file_writer.interface.writeAll("abcd");2887 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" {...@@ -232,8 +232,10 @@ test "listen on an in use port" {
232fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void {232fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void {
233 if (builtin.os.tag == .wasi) return error.SkipZigTest;233 if (builtin.os.tag == .wasi) return error.SkipZigTest;
234234
235 const io = testing.io;
236
235 const connection = try net.tcpConnectToHost(allocator, name, port);237 const connection = try net.tcpConnectToHost(allocator, name, port);
236 defer connection.close();238 defer connection.close(io);
237239
238 var buf: [100]u8 = undefined;240 var buf: [100]u8 = undefined;
239 const len = try connection.read(&buf);241 const len = try connection.read(&buf);
...@@ -244,8 +246,10 @@ fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyer...@@ -244,8 +246,10 @@ fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyer
244fn testClient(addr: net.IpAddress) anyerror!void {246fn testClient(addr: net.IpAddress) anyerror!void {
245 if (builtin.os.tag == .wasi) return error.SkipZigTest;247 if (builtin.os.tag == .wasi) return error.SkipZigTest;
246248
249 const io = testing.io;
250
247 const socket_file = try net.tcpConnectToAddress(addr);251 const socket_file = try net.tcpConnectToAddress(addr);
248 defer socket_file.close();252 defer socket_file.close(io);
249253
250 var buf: [100]u8 = undefined;254 var buf: [100]u8 = undefined;
251 const len = try socket_file.read(&buf);255 const len = try socket_file.read(&buf);
...@@ -330,7 +334,7 @@ test "non-blocking tcp server" {...@@ -330,7 +334,7 @@ test "non-blocking tcp server" {
330 try testing.expectError(error.WouldBlock, accept_err);334 try testing.expectError(error.WouldBlock, accept_err);
331335
332 const socket_file = try net.tcpConnectToAddress(server.socket.address);336 const socket_file = try net.tcpConnectToAddress(server.socket.address);
333 defer socket_file.close();337 defer socket_file.close(io);
334338
335 var stream = try server.accept(io);339 var stream = try server.accept(io);
336 defer stream.close(io);340 defer stream.close(io);
lib/std/Io/test.zig+11-5
...@@ -28,7 +28,7 @@ test "write a file, read it, then delete it" {...@@ -28,7 +28,7 @@ test "write a file, read it, then delete it" {
28 const tmp_file_name = "temp_test_file.txt";28 const tmp_file_name = "temp_test_file.txt";
29 {29 {
30 var file = try tmp.dir.createFile(tmp_file_name, .{});30 var file = try tmp.dir.createFile(tmp_file_name, .{});
31 defer file.close();31 defer file.close(io);
3232
33 var file_writer = file.writer(&.{});33 var file_writer = file.writer(&.{});
34 const st = &file_writer.interface;34 const st = &file_writer.interface;
...@@ -45,7 +45,7 @@ test "write a file, read it, then delete it" {...@@ -45,7 +45,7 @@ test "write a file, read it, then delete it" {
4545
46 {46 {
47 var file = try tmp.dir.openFile(tmp_file_name, .{});47 var file = try tmp.dir.openFile(tmp_file_name, .{});
48 defer file.close();48 defer file.close(io);
4949
50 const file_size = try file.getEndPos();50 const file_size = try file.getEndPos();
51 const expected_file_size: u64 = "begin".len + data.len + "end".len;51 const expected_file_size: u64 = "begin".len + data.len + "end".len;
...@@ -67,9 +67,11 @@ test "File seek ops" {...@@ -67,9 +67,11 @@ test "File seek ops" {
67 var tmp = tmpDir(.{});67 var tmp = tmpDir(.{});
68 defer tmp.cleanup();68 defer tmp.cleanup();
6969
70 const io = testing.io;
71
70 const tmp_file_name = "temp_test_file.txt";72 const tmp_file_name = "temp_test_file.txt";
71 var file = try tmp.dir.createFile(tmp_file_name, .{});73 var file = try tmp.dir.createFile(tmp_file_name, .{});
72 defer file.close();74 defer file.close(io);
7375
74 try file.writeAll(&([_]u8{0x55} ** 8192));76 try file.writeAll(&([_]u8{0x55} ** 8192));
7577
...@@ -88,12 +90,14 @@ test "File seek ops" {...@@ -88,12 +90,14 @@ test "File seek ops" {
88}90}
8991
90test "setEndPos" {92test "setEndPos" {
93 const io = testing.io;
94
91 var tmp = tmpDir(.{});95 var tmp = tmpDir(.{});
92 defer tmp.cleanup();96 defer tmp.cleanup();
9397
94 const tmp_file_name = "temp_test_file.txt";98 const tmp_file_name = "temp_test_file.txt";
95 var file = try tmp.dir.createFile(tmp_file_name, .{});99 var file = try tmp.dir.createFile(tmp_file_name, .{});
96 defer file.close();100 defer file.close(io);
97101
98 // Verify that the file size changes and the file offset is not moved102 // Verify that the file size changes and the file offset is not moved
99 try expect((try file.getEndPos()) == 0);103 try expect((try file.getEndPos()) == 0);
...@@ -111,12 +115,14 @@ test "setEndPos" {...@@ -111,12 +115,14 @@ test "setEndPos" {
111}115}
112116
113test "updateTimes" {117test "updateTimes" {
118 const io = testing.io;
119
114 var tmp = tmpDir(.{});120 var tmp = tmpDir(.{});
115 defer tmp.cleanup();121 defer tmp.cleanup();
116122
117 const tmp_file_name = "just_a_temporary_file.txt";123 const tmp_file_name = "just_a_temporary_file.txt";
118 var file = try tmp.dir.createFile(tmp_file_name, .{ .read = true });124 var file = try tmp.dir.createFile(tmp_file_name, .{ .read = true });
119 defer file.close();125 defer file.close(io);
120126
121 const stat_old = try file.stat();127 const stat_old = try file.stat();
122 // Set atime and mtime to 5s before128 // Set atime and mtime to 5s before
lib/std/Thread.zig+4-3
...@@ -7,6 +7,7 @@ const target = builtin.target;...@@ -7,6 +7,7 @@ const target = builtin.target;
7const native_os = builtin.os.tag;7const native_os = builtin.os.tag;
88
9const std = @import("std.zig");9const std = @import("std.zig");
10const Io = std.Io;
10const math = std.math;11const math = std.math;
11const assert = std.debug.assert;12const assert = std.debug.assert;
12const posix = std.posix;13const posix = std.posix;
...@@ -176,7 +177,7 @@ pub const SetNameError = error{...@@ -176,7 +177,7 @@ pub const SetNameError = error{
176 InvalidWtf8,177 InvalidWtf8,
177} || posix.PrctlError || posix.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;178} || 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 {
180 if (name.len > max_name_len) return error.NameTooLong;181 if (name.len > max_name_len) return error.NameTooLong;
181182
182 const name_with_terminator = blk: {183 const name_with_terminator = blk: {
...@@ -208,7 +209,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {...@@ -208,7 +209,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
208 const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});209 const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
209210
210 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });211 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });
211 defer file.close();212 defer file.close(io);
212213
213 try file.writeAll(name);214 try file.writeAll(name);
214 return;215 return;
...@@ -325,7 +326,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co...@@ -325,7 +326,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
325 const io = threaded.ioBasic();326 const io = threaded.ioBasic();
326327
327 const file = try std.fs.cwd().openFile(path, .{});328 const file = try std.fs.cwd().openFile(path, .{});
328 defer file.close();329 defer file.close(io);
329330
330 var file_reader = file.readerStreaming(io, &.{});331 var file_reader = file.readerStreaming(io, &.{});
331 const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) {332 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(...@@ -181,7 +181,7 @@ pub fn addCertsFromDirPath(
181 sub_dir_path: []const u8,181 sub_dir_path: []const u8,
182) AddCertsFromDirPathError!void {182) AddCertsFromDirPathError!void {
183 var iterable_dir = try dir.openDir(sub_dir_path, .{ .iterate = true });183 var iterable_dir = try dir.openDir(sub_dir_path, .{ .iterate = true });
184 defer iterable_dir.close();184 defer iterable_dir.close(io);
185 return addCertsFromDir(cb, gpa, io, iterable_dir);185 return addCertsFromDir(cb, gpa, io, iterable_dir);
186}186}
187187
...@@ -194,7 +194,7 @@ pub fn addCertsFromDirPathAbsolute(...@@ -194,7 +194,7 @@ pub fn addCertsFromDirPathAbsolute(
194) AddCertsFromDirPathError!void {194) AddCertsFromDirPathError!void {
195 assert(fs.path.isAbsolute(abs_dir_path));195 assert(fs.path.isAbsolute(abs_dir_path));
196 var iterable_dir = try fs.openDirAbsolute(abs_dir_path, .{ .iterate = true });196 var iterable_dir = try fs.openDirAbsolute(abs_dir_path, .{ .iterate = true });
197 defer iterable_dir.close();197 defer iterable_dir.close(io);
198 return addCertsFromDir(cb, gpa, io, now, iterable_dir);198 return addCertsFromDir(cb, gpa, io, now, iterable_dir);
199}199}
200200
...@@ -222,7 +222,7 @@ pub fn addCertsFromFilePathAbsolute(...@@ -222,7 +222,7 @@ pub fn addCertsFromFilePathAbsolute(
222 abs_file_path: []const u8,222 abs_file_path: []const u8,
223) AddCertsFromFilePathError!void {223) AddCertsFromFilePathError!void {
224 var file = try fs.openFileAbsolute(abs_file_path, .{});224 var file = try fs.openFileAbsolute(abs_file_path, .{});
225 defer file.close();225 defer file.close(io);
226 var file_reader = file.reader(io, &.{});226 var file_reader = file.reader(io, &.{});
227 return addCertsFromFile(cb, gpa, &file_reader, now.toSeconds());227 return addCertsFromFile(cb, gpa, &file_reader, now.toSeconds());
228}228}
lib/std/crypto/codecs/asn1/test.zig+1-1
...@@ -75,6 +75,6 @@ test AllTypes {...@@ -75,6 +75,6 @@ test AllTypes {
75 // Use this to update test file.75 // Use this to update test file.
76 // const dir = try std.fs.cwd().openDir("lib/std/crypto/asn1", .{});76 // const dir = try std.fs.cwd().openDir("lib/std/crypto/asn1", .{});
77 // var file = try dir.createFile(path, .{});77 // var file = try dir.createFile(path, .{});
78 // defer file.close();78 // defer file.close(io);
79 // try file.writeAll(buf);79 // try file.writeAll(buf);
80}80}
lib/std/debug.zig+4-4
...@@ -1298,7 +1298,7 @@ test printLineFromFile {...@@ -1298,7 +1298,7 @@ test printLineFromFile {
1298 }1298 }
1299 {1299 {
1300 const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});1300 const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});
1301 defer file.close();1301 defer file.close(io);
1302 const path = try fs.path.join(gpa, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });1302 const path = try fs.path.join(gpa, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });
1303 defer gpa.free(path);1303 defer gpa.free(path);
13041304
...@@ -1317,7 +1317,7 @@ test printLineFromFile {...@@ -1317,7 +1317,7 @@ test printLineFromFile {
1317 }1317 }
1318 {1318 {
1319 const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});1319 const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});
1320 defer file.close();1320 defer file.close(io);
1321 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });1321 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
1322 defer gpa.free(path);1322 defer gpa.free(path);
13231323
...@@ -1331,7 +1331,7 @@ test printLineFromFile {...@@ -1331,7 +1331,7 @@ test printLineFromFile {
1331 }1331 }
1332 {1332 {
1333 const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});1333 const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});
1334 defer file.close();1334 defer file.close(io);
1335 const path = try fs.path.join(gpa, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });1335 const path = try fs.path.join(gpa, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
1336 defer gpa.free(path);1336 defer gpa.free(path);
13371337
...@@ -1357,7 +1357,7 @@ test printLineFromFile {...@@ -1357,7 +1357,7 @@ test printLineFromFile {
1357 }1357 }
1358 {1358 {
1359 const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});1359 const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});
1360 defer file.close();1360 defer file.close(io);
1361 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_of_newlines.zig" });1361 const path = try fs.path.join(gpa, &.{ test_dir_path, "file_of_newlines.zig" });
1362 defer gpa.free(path);1362 defer gpa.free(path);
13631363
lib/std/debug/ElfFile.zig+17-9
...@@ -1,5 +1,13 @@...@@ -1,5 +1,13 @@
1//! A helper type for loading an ELF file and collecting its DWARF debug information, unwind1//! A helper type for loading an ELF file and collecting its DWARF debug information, unwind
2//! information, and symbol table.2//! 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
4is_64: bool,12is_64: bool,
5endian: Endian,13endian: Endian,
...@@ -358,10 +366,17 @@ const Section = struct {...@@ -358,10 +366,17 @@ const Section = struct {
358 const Array = std.enums.EnumArray(Section.Id, ?Section);366 const Array = std.enums.EnumArray(Section.Id, ?Section);
359};367};
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 {
362 const path = try std.fmt.allocPrint(arena, fmt, args);377 const path = try std.fmt.allocPrint(arena, fmt, args);
363 const elf_file = std.fs.cwd().openFile(path, .{}) catch return null;378 const elf_file = std.fs.cwd().openFile(path, .{}) catch return null;
364 defer elf_file.close();379 defer elf_file.close(io);
365380
366 const result = loadInner(arena, elf_file, opt_crc) catch |err| switch (err) {381 const result = loadInner(arena, elf_file, opt_crc) catch |err| switch (err) {
367 error.OutOfMemory => |e| return e,382 error.OutOfMemory => |e| return e,
...@@ -529,10 +544,3 @@ fn loadInner(...@@ -529,10 +544,3 @@ fn loadInner(
529 .mapped_mem = mapped_mem,544 .mapped_mem = mapped_mem,
530 };545 };
531}546}
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 @@...@@ -5,19 +5,18 @@
5//! Unlike `std.debug.SelfInfo`, this API does not assume the debug information5//! Unlike `std.debug.SelfInfo`, this API does not assume the debug information
6//! in question happens to match the host CPU architecture, OS, or other target6//! in question happens to match the host CPU architecture, OS, or other target
7//! properties.7//! properties.
8const Info = @This();
89
9const std = @import("../std.zig");10const std = @import("../std.zig");
11const Io = std.Io;
10const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
11const Path = std.Build.Cache.Path;13const Path = std.Build.Cache.Path;
12const assert = std.debug.assert;14const assert = std.debug.assert;
13const Coverage = std.debug.Coverage;15const Coverage = std.debug.Coverage;
14const SourceLocation = std.debug.Coverage.SourceLocation;16const SourceLocation = std.debug.Coverage.SourceLocation;
15
16const ElfFile = std.debug.ElfFile;17const ElfFile = std.debug.ElfFile;
17const MachOFile = std.debug.MachOFile;18const MachOFile = std.debug.MachOFile;
1819
19const Info = @This();
20
21impl: union(enum) {20impl: union(enum) {
22 elf: ElfFile,21 elf: ElfFile,
23 macho: MachOFile,22 macho: MachOFile,
...@@ -25,13 +24,23 @@ impl: union(enum) {...@@ -25,13 +24,23 @@ impl: union(enum) {
25/// Externally managed, outlives this `Info` instance.24/// Externally managed, outlives this `Info` instance.
26coverage: *Coverage,25coverage: *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 {
31 switch (format) {40 switch (format) {
32 .elf => {41 .elf => {
33 var file = try path.root_dir.handle.openFile(path.sub_path, .{});42 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
34 defer file.close();43 defer file.close(io);
3544
36 var elf_file: ElfFile = try .load(gpa, file, null, &.none);45 var elf_file: ElfFile = try .load(gpa, file, null, &.none);
37 errdefer elf_file.deinit(gpa);46 errdefer elf_file.deinit(gpa);
lib/std/debug/MachOFile.zig+9-9
...@@ -27,13 +27,13 @@ pub fn deinit(mf: *MachOFile, gpa: Allocator) void {...@@ -27,13 +27,13 @@ pub fn deinit(mf: *MachOFile, gpa: Allocator) void {
27 posix.munmap(mf.mapped_memory);27 posix.munmap(mf.mapped_memory);
28}28}
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 {
31 switch (arch) {31 switch (arch) {
32 .x86_64, .aarch64 => {},32 .x86_64, .aarch64 => {},
33 else => unreachable,33 else => unreachable,
34 }34 }
3535
36 const all_mapped_memory = try mapDebugInfoFile(path);36 const all_mapped_memory = try mapDebugInfoFile(io, path);
37 errdefer posix.munmap(all_mapped_memory);37 errdefer posix.munmap(all_mapped_memory);
3838
39 // In most cases, the file we just mapped is a Mach-O binary. However, it could be a "universal39 // 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...@@ -239,7 +239,7 @@ pub fn load(gpa: Allocator, path: []const u8, arch: std.Target.Cpu.Arch) Error!M
239 .text_vmaddr = text_vmaddr,239 .text_vmaddr = text_vmaddr,
240 };240 };
241}241}
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 } {
243 const symbol = Symbol.find(mf.symbols, vaddr) orelse return error.MissingDebugInfo;243 const symbol = Symbol.find(mf.symbols, vaddr) orelse return error.MissingDebugInfo;
244244
245 if (symbol.ofile == Symbol.unknown_ofile) return error.MissingDebugInfo;245 if (symbol.ofile == Symbol.unknown_ofile) return error.MissingDebugInfo;
...@@ -254,7 +254,7 @@ pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, vaddr: u64) !struct {...@@ -254,7 +254,7 @@ pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, vaddr: u64) !struct {
254 const gop = try mf.ofiles.getOrPut(gpa, symbol.ofile);254 const gop = try mf.ofiles.getOrPut(gpa, symbol.ofile);
255 if (!gop.found_existing) {255 if (!gop.found_existing) {
256 const name = mem.sliceTo(mf.strings[symbol.ofile..], 0);256 const name = mem.sliceTo(mf.strings[symbol.ofile..], 0);
257 gop.value_ptr.* = loadOFile(gpa, name);257 gop.value_ptr.* = loadOFile(gpa, io, name);
258 }258 }
259 const of = &(gop.value_ptr.* catch |err| return err);259 const of = &(gop.value_ptr.* catch |err| return err);
260260
...@@ -356,7 +356,7 @@ test {...@@ -356,7 +356,7 @@ test {
356 _ = Symbol;356 _ = Symbol;
357}357}
358358
359fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {359fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile {
360 const all_mapped_memory, const mapped_ofile = map: {360 const all_mapped_memory, const mapped_ofile = map: {
361 const open_paren = paren: {361 const open_paren = paren: {
362 if (std.mem.endsWith(u8, o_file_name, ")")) {362 if (std.mem.endsWith(u8, o_file_name, ")")) {
...@@ -365,7 +365,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {...@@ -365,7 +365,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
365 }365 }
366 }366 }
367 // Not an archive, just a normal path to a .o file367 // 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);
369 break :map .{ m, m };369 break :map .{ m, m };
370 };370 };
371371
...@@ -373,7 +373,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {...@@ -373,7 +373,7 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
373373
374 const archive_path = o_file_name[0..open_paren];374 const archive_path = o_file_name[0..open_paren];
375 const target_name_in_archive = o_file_name[open_paren + 1 .. o_file_name.len - 1];375 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);
377 errdefer posix.munmap(mapped_archive);377 errdefer posix.munmap(mapped_archive);
378378
379 var ar_reader: Io.Reader = .fixed(mapped_archive);379 var ar_reader: Io.Reader = .fixed(mapped_archive);
...@@ -511,12 +511,12 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {...@@ -511,12 +511,12 @@ fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
511}511}
512512
513/// Uses `mmap` to map the file at `path` into memory.513/// 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 {
515 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {515 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
516 error.FileNotFound => return error.MissingDebugInfo,516 error.FileNotFound => return error.MissingDebugInfo,
517 else => return error.ReadFailed,517 else => return error.ReadFailed,
518 };518 };
519 defer file.close();519 defer file.close(io);
520520
521 const file_len = std.math.cast(521 const file_len = std.math.cast(
522 usize,522 usize,
lib/std/debug/SelfInfo/Elf.zig+5-5
...@@ -319,14 +319,14 @@ const Module = struct {...@@ -319,14 +319,14 @@ const Module = struct {
319 }319 }
320320
321 /// Assumes we already hold an exclusive lock.321 /// Assumes we already hold an exclusive lock.
322 fn getLoadedElf(mod: *Module, gpa: Allocator) Error!*LoadedElf {322 fn getLoadedElf(mod: *Module, gpa: Allocator, io: Io) Error!*LoadedElf {
323 if (mod.loaded_elf == null) mod.loaded_elf = loadElf(mod, gpa);323 if (mod.loaded_elf == null) mod.loaded_elf = loadElf(mod, gpa, io);
324 return if (mod.loaded_elf.?) |*elf| elf else |err| err;324 return if (mod.loaded_elf.?) |*elf| elf else |err| err;
325 }325 }
326 fn loadElf(mod: *Module, gpa: Allocator) Error!LoadedElf {326 fn loadElf(mod: *Module, gpa: Allocator, io: Io) Error!LoadedElf {
327 const load_result = if (mod.name.len > 0) res: {327 const load_result = if (mod.name.len > 0) res: {
328 var file = std.fs.cwd().openFile(mod.name, .{}) catch return error.MissingDebugInfo;328 var file = std.fs.cwd().openFile(mod.name, .{}) catch return error.MissingDebugInfo;
329 defer file.close();329 defer file.close(io);
330 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(mod.name));330 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(mod.name));
331 } else res: {331 } else res: {
332 const path = std.fs.selfExePathAlloc(gpa) catch |err| switch (err) {332 const path = std.fs.selfExePathAlloc(gpa) catch |err| switch (err) {
...@@ -335,7 +335,7 @@ const Module = struct {...@@ -335,7 +335,7 @@ const Module = struct {
335 };335 };
336 defer gpa.free(path);336 defer gpa.free(path);
337 var file = std.fs.cwd().openFile(path, .{}) catch return error.MissingDebugInfo;337 var file = std.fs.cwd().openFile(path, .{}) catch return error.MissingDebugInfo;
338 defer file.close();338 defer file.close(io);
339 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(path));339 break :res std.debug.ElfFile.load(gpa, file, mod.build_id, &.native(path));
340 };340 };
341341
lib/std/debug/SelfInfo/MachO.zig+2-2
...@@ -615,12 +615,12 @@ test {...@@ -615,12 +615,12 @@ test {
615}615}
616616
617/// Uses `mmap` to map the file at `path` into memory.617/// 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 {
619 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {619 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
620 error.FileNotFound => return error.MissingDebugInfo,620 error.FileNotFound => return error.MissingDebugInfo,
621 else => return error.ReadFailed,621 else => return error.ReadFailed,
622 };622 };
623 defer file.close();623 defer file.close(io);
624624
625 const file_end_pos = file.getEndPos() catch |err| switch (err) {625 const file_end_pos = file.getEndPos() catch |err| switch (err) {
626 error.Unexpected => |e| return e,626 error.Unexpected => |e| return e,
lib/std/debug/SelfInfo/Windows.zig+3-3
...@@ -207,11 +207,11 @@ const Module = struct {...@@ -207,11 +207,11 @@ const Module = struct {
207 file: fs.File,207 file: fs.File,
208 section_handle: windows.HANDLE,208 section_handle: windows.HANDLE,
209 section_view: []const u8,209 section_view: []const u8,
210 fn deinit(mf: *const MappedFile) void {210 fn deinit(mf: *const MappedFile, io: Io) void {
211 const process_handle = windows.GetCurrentProcess();211 const process_handle = windows.GetCurrentProcess();
212 assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mf.section_view.ptr)) == .SUCCESS);212 assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mf.section_view.ptr)) == .SUCCESS);
213 windows.CloseHandle(mf.section_handle);213 windows.CloseHandle(mf.section_handle);
214 mf.file.close();214 mf.file.close(io);
215 }215 }
216 };216 };
217217
...@@ -447,7 +447,7 @@ const Module = struct {...@@ -447,7 +447,7 @@ const Module = struct {
447 error.FileNotFound, error.IsDir => break :pdb null,447 error.FileNotFound, error.IsDir => break :pdb null,
448 else => return error.ReadFailed,448 else => return error.ReadFailed,
449 };449 };
450 errdefer pdb_file.close();450 errdefer pdb_file.close(io);
451451
452 const pdb_reader = try arena.create(Io.File.Reader);452 const pdb_reader = try arena.create(Io.File.Reader);
453 pdb_reader.* = pdb_file.reader(io, try arena.alloc(u8, 4096));453 pdb_reader.* = pdb_file.reader(io, try arena.alloc(u8, 4096));
lib/std/dynamic_library.zig+18-16
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");1const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("std.zig");
5const Io = std.Io;
3const mem = std.mem;6const mem = std.mem;
4const testing = std.testing;7const testing = std.testing;
5const elf = std.elf;8const elf = std.elf;
6const windows = std.os.windows;9const windows = std.os.windows;
7const native_os = builtin.os.tag;
8const posix = std.posix;10const posix = std.posix;
911
10/// Cross-platform dynamic library loading and symbol lookup.12/// Cross-platform dynamic library loading and symbol lookup.
...@@ -38,8 +40,8 @@ pub const DynLib = struct {...@@ -38,8 +40,8 @@ pub const DynLib = struct {
38 }40 }
3941
40 /// Trusts the file.42 /// Trusts the file.
41 pub fn close(self: *DynLib) void {43 pub fn close(self: *DynLib, io: Io) void {
42 return self.inner.close();44 return self.inner.close(io);
43 }45 }
4446
45 pub fn lookup(self: *DynLib, comptime T: type, name: [:0]const u8) ?T {47 pub fn lookup(self: *DynLib, comptime T: type, name: [:0]const u8) ?T {
...@@ -155,23 +157,23 @@ pub const ElfDynLib = struct {...@@ -155,23 +157,23 @@ pub const ElfDynLib = struct {
155 dt_gnu_hash: *elf.gnu_hash.Header,157 dt_gnu_hash: *elf.gnu_hash.Header,
156 };158 };
157159
158 fn openPath(path: []const u8) !std.fs.Dir {160 fn openPath(path: []const u8, io: Io) !std.fs.Dir {
159 if (path.len == 0) return error.NotDir;161 if (path.len == 0) return error.NotDir;
160 var parts = std.mem.tokenizeScalar(u8, path, '/');162 var parts = std.mem.tokenizeScalar(u8, path, '/');
161 var parent = if (path[0] == '/') try std.fs.cwd().openDir("/", .{}) else std.fs.cwd();163 var parent = if (path[0] == '/') try std.fs.cwd().openDir("/", .{}) else std.fs.cwd();
162 while (parts.next()) |part| {164 while (parts.next()) |part| {
163 const child = try parent.openDir(part, .{});165 const child = try parent.openDir(part, .{});
164 parent.close();166 parent.close(io);
165 parent = child;167 parent = child;
166 }168 }
167 return parent;169 return parent;
168 }170 }
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 {
171 var paths = std.mem.tokenizeScalar(u8, search_path, delim);173 var paths = std.mem.tokenizeScalar(u8, search_path, delim);
172 while (paths.next()) |p| {174 while (paths.next()) |p| {
173 var dir = openPath(p) catch continue;175 var dir = openPath(p) catch continue;
174 defer dir.close();176 defer dir.close(io);
175 const fd = posix.openat(dir.fd, file_name, .{177 const fd = posix.openat(dir.fd, file_name, .{
176 .ACCMODE = .RDONLY,178 .ACCMODE = .RDONLY,
177 .CLOEXEC = true,179 .CLOEXEC = true,
...@@ -181,9 +183,9 @@ pub const ElfDynLib = struct {...@@ -181,9 +183,9 @@ pub const ElfDynLib = struct {
181 return null;183 return null;
182 }184 }
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 {
185 var dir = std.fs.cwd().openDir(dir_path, .{}) catch return null;187 var dir = std.fs.cwd().openDir(dir_path, .{}) catch return null;
186 defer dir.close();188 defer dir.close(io);
187 return posix.openat(dir.fd, file_name, .{189 return posix.openat(dir.fd, file_name, .{
188 .ACCMODE = .RDONLY,190 .ACCMODE = .RDONLY,
189 .CLOEXEC = true,191 .CLOEXEC = true,
...@@ -195,7 +197,7 @@ pub const ElfDynLib = struct {...@@ -195,7 +197,7 @@ pub const ElfDynLib = struct {
195 // - DT_RPATH of the calling binary is not used as a search path197 // - DT_RPATH of the calling binary is not used as a search path
196 // - DT_RUNPATH of the calling binary is not used as a search path198 // - DT_RUNPATH of the calling binary is not used as a search path
197 // - /etc/ld.so.cache is not read199 // - /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 {
199 // If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname201 // If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname
200 if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {202 if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {
201 return posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);203 return posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
...@@ -206,21 +208,21 @@ pub const ElfDynLib = struct {...@@ -206,21 +208,21 @@ pub const ElfDynLib = struct {
206 std.os.linux.getegid() == std.os.linux.getgid())208 std.os.linux.getegid() == std.os.linux.getgid())
207 {209 {
208 if (posix.getenvZ("LD_LIBRARY_PATH")) |ld_library_path| {210 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| {
210 return fd;212 return fd;
211 }213 }
212 }214 }
213 }215 }
214216
215 // Lastly the directories /lib and /usr/lib are searched (in this exact order)217 // Lastly the directories /lib and /usr/lib are searched (in this exact order)
216 if (resolveFromParent("/lib", path_or_name)) |fd| return fd;218 if (resolveFromParent(io, "/lib", path_or_name)) |fd| return fd;
217 if (resolveFromParent("/usr/lib", path_or_name)) |fd| return fd;219 if (resolveFromParent(io, "/usr/lib", path_or_name)) |fd| return fd;
218 return error.FileNotFound;220 return error.FileNotFound;
219 }221 }
220222
221 /// Trusts the file. Malicious file will be able to execute arbitrary code.223 /// Trusts the file. Malicious file will be able to execute arbitrary code.
222 pub fn open(path: []const u8) Error!ElfDynLib {224 pub fn open(io: Io, path: []const u8) Error!ElfDynLib {
223 const fd = try resolveFromName(path);225 const fd = try resolveFromName(io, path);
224 defer posix.close(fd);226 defer posix.close(fd);
225227
226 const file: std.fs.File = .{ .handle = fd };228 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 {...@@ -227,7 +227,7 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void {
227/// On Windows, `absolute_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).227/// On Windows, `absolute_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
228/// On WASI, `absolute_path` should be encoded as valid UTF-8.228/// On WASI, `absolute_path` should be encoded as valid UTF-8.
229/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.229/// 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 {
231 assert(path.isAbsolute(absolute_path));231 assert(path.isAbsolute(absolute_path));
232 const dirname = path.dirname(absolute_path) orelse return error{232 const dirname = path.dirname(absolute_path) orelse return error{
233 /// Attempt to remove the root file system path.233 /// Attempt to remove the root file system path.
...@@ -236,7 +236,7 @@ pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {...@@ -236,7 +236,7 @@ pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
236 }.CannotDeleteRootDirectory;236 }.CannotDeleteRootDirectory;
237237
238 var dir = try cwd().openDir(dirname, .{});238 var dir = try cwd().openDir(dirname, .{});
239 defer dir.close();239 defer dir.close(io);
240240
241 return dir.deleteTree(path.basename(absolute_path));241 return dir.deleteTree(path.basename(absolute_path));
242}242}
lib/std/fs/test.zig+171-99
...@@ -178,6 +178,8 @@ fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlag...@@ -178,6 +178,8 @@ fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlag
178}178}
179179
180test "Dir.readLink" {180test "Dir.readLink" {
181 const io = testing.io;
182
181 try testWithAllSupportedPathTypes(struct {183 try testWithAllSupportedPathTypes(struct {
182 fn impl(ctx: *TestContext) !void {184 fn impl(ctx: *TestContext) !void {
183 // Create some targets185 // Create some targets
...@@ -208,7 +210,7 @@ test "Dir.readLink" {...@@ -208,7 +210,7 @@ test "Dir.readLink" {
208 const parent_file = ".." ++ fs.path.sep_str ++ "target.txt";210 const parent_file = ".." ++ fs.path.sep_str ++ "target.txt";
209 const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file);211 const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file);
210 var subdir = try ctx.dir.makeOpenPath("subdir", .{});212 var subdir = try ctx.dir.makeOpenPath("subdir", .{});
211 defer subdir.close();213 defer subdir.close(io);
212 try setupSymlink(subdir, canonical_parent_file, "relative-link.txt", .{});214 try setupSymlink(subdir, canonical_parent_file, "relative-link.txt", .{});
213 try testReadLink(subdir, canonical_parent_file, "relative-link.txt");215 try testReadLink(subdir, canonical_parent_file, "relative-link.txt");
214 if (builtin.os.tag == .windows) {216 if (builtin.os.tag == .windows) {
...@@ -268,6 +270,8 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void...@@ -268,6 +270,8 @@ fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void
268}270}
269271
270test "File.stat on a File that is a symlink returns Kind.sym_link" {272test "File.stat on a File that is a symlink returns Kind.sym_link" {
273 const io = testing.io;
274
271 // This test requires getting a file descriptor of a symlink which275 // This test requires getting a file descriptor of a symlink which
272 // is not possible on all targets276 // is not possible on all targets
273 switch (builtin.target.os.tag) {277 switch (builtin.target.os.tag) {
...@@ -302,7 +306,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {...@@ -302,7 +306,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
302 .SecurityDescriptor = null,306 .SecurityDescriptor = null,
303 .SecurityQualityOfService = null,307 .SecurityQualityOfService = null,
304 };308 };
305 var io: windows.IO_STATUS_BLOCK = undefined;309 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
306 const rc = windows.ntdll.NtCreateFile(310 const rc = windows.ntdll.NtCreateFile(
307 &handle,311 &handle,
308 .{312 .{
...@@ -317,7 +321,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {...@@ -317,7 +321,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
317 },321 },
318 },322 },
319 &attr,323 &attr,
320 &io,324 &io_status_block,
321 null,325 null,
322 .{ .NORMAL = true },326 .{ .NORMAL = true },
323 .VALID_FLAGS,327 .VALID_FLAGS,
...@@ -352,7 +356,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {...@@ -352,7 +356,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
352 },356 },
353 else => unreachable,357 else => unreachable,
354 };358 };
355 defer symlink.close();359 defer symlink.close(io);
356360
357 const stat = try symlink.stat();361 const stat = try symlink.stat();
358 try testing.expectEqual(File.Kind.sym_link, stat.kind);362 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" {...@@ -361,6 +365,8 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
361}365}
362366
363test "openDir" {367test "openDir" {
368 const io = testing.io;
369
364 try testWithAllSupportedPathTypes(struct {370 try testWithAllSupportedPathTypes(struct {
365 fn impl(ctx: *TestContext) !void {371 fn impl(ctx: *TestContext) !void {
366 const allocator = ctx.arena.allocator();372 const allocator = ctx.arena.allocator();
...@@ -370,7 +376,7 @@ test "openDir" {...@@ -370,7 +376,7 @@ test "openDir" {
370 for ([_][]const u8{ "", ".", ".." }) |sub_path| {376 for ([_][]const u8{ "", ".", ".." }) |sub_path| {
371 const dir_path = try fs.path.join(allocator, &.{ subdir_path, sub_path });377 const dir_path = try fs.path.join(allocator, &.{ subdir_path, sub_path });
372 var dir = try ctx.dir.openDir(dir_path, .{});378 var dir = try ctx.dir.openDir(dir_path, .{});
373 defer dir.close();379 defer dir.close(io);
374 }380 }
375 }381 }
376 }.impl);382 }.impl);
...@@ -393,6 +399,8 @@ test "openDirAbsolute" {...@@ -393,6 +399,8 @@ test "openDirAbsolute" {
393 if (native_os == .wasi) return error.SkipZigTest;399 if (native_os == .wasi) return error.SkipZigTest;
394 if (native_os == .openbsd) return error.SkipZigTest;400 if (native_os == .openbsd) return error.SkipZigTest;
395401
402 const io = testing.io;
403
396 var tmp = tmpDir(.{});404 var tmp = tmpDir(.{});
397 defer tmp.cleanup();405 defer tmp.cleanup();
398406
...@@ -404,7 +412,7 @@ test "openDirAbsolute" {...@@ -404,7 +412,7 @@ test "openDirAbsolute" {
404412
405 // Can open sub_path413 // Can open sub_path
406 var tmp_sub = try fs.openDirAbsolute(sub_path, .{});414 var tmp_sub = try fs.openDirAbsolute(sub_path, .{});
407 defer tmp_sub.close();415 defer tmp_sub.close(io);
408416
409 const sub_ino = (try tmp_sub.stat()).inode;417 const sub_ino = (try tmp_sub.stat()).inode;
410418
...@@ -414,7 +422,7 @@ test "openDirAbsolute" {...@@ -414,7 +422,7 @@ test "openDirAbsolute" {
414 defer testing.allocator.free(dir_path);422 defer testing.allocator.free(dir_path);
415423
416 var dir = try fs.openDirAbsolute(dir_path, .{});424 var dir = try fs.openDirAbsolute(dir_path, .{});
417 defer dir.close();425 defer dir.close(io);
418426
419 const ino = (try dir.stat()).inode;427 const ino = (try dir.stat()).inode;
420 try testing.expectEqual(tmp_ino, ino);428 try testing.expectEqual(tmp_ino, ino);
...@@ -426,7 +434,7 @@ test "openDirAbsolute" {...@@ -426,7 +434,7 @@ test "openDirAbsolute" {
426 defer testing.allocator.free(dir_path);434 defer testing.allocator.free(dir_path);
427435
428 var dir = try fs.openDirAbsolute(dir_path, .{});436 var dir = try fs.openDirAbsolute(dir_path, .{});
429 defer dir.close();437 defer dir.close(io);
430438
431 const ino = (try dir.stat()).inode;439 const ino = (try dir.stat()).inode;
432 try testing.expectEqual(sub_ino, ino);440 try testing.expectEqual(sub_ino, ino);
...@@ -438,7 +446,7 @@ test "openDirAbsolute" {...@@ -438,7 +446,7 @@ test "openDirAbsolute" {
438 defer testing.allocator.free(dir_path);446 defer testing.allocator.free(dir_path);
439447
440 var dir = try fs.openDirAbsolute(dir_path, .{});448 var dir = try fs.openDirAbsolute(dir_path, .{});
441 defer dir.close();449 defer dir.close(io);
442450
443 const ino = (try dir.stat()).inode;451 const ino = (try dir.stat()).inode;
444 try testing.expectEqual(tmp_ino, ino);452 try testing.expectEqual(tmp_ino, ino);
...@@ -446,13 +454,15 @@ test "openDirAbsolute" {...@@ -446,13 +454,15 @@ test "openDirAbsolute" {
446}454}
447455
448test "openDir cwd parent '..'" {456test "openDir cwd parent '..'" {
457 const io = testing.io;
458
449 var dir = fs.cwd().openDir("..", .{}) catch |err| {459 var dir = fs.cwd().openDir("..", .{}) catch |err| {
450 if (native_os == .wasi and err == error.PermissionDenied) {460 if (native_os == .wasi and err == error.PermissionDenied) {
451 return; // This is okay. WASI disallows escaping from the fs sandbox461 return; // This is okay. WASI disallows escaping from the fs sandbox
452 }462 }
453 return err;463 return err;
454 };464 };
455 defer dir.close();465 defer dir.close(io);
456}466}
457467
458test "openDir non-cwd parent '..'" {468test "openDir non-cwd parent '..'" {
...@@ -461,14 +471,16 @@ test "openDir non-cwd parent '..'" {...@@ -461,14 +471,16 @@ test "openDir non-cwd parent '..'" {
461 else => {},471 else => {},
462 }472 }
463473
474 const io = testing.io;
475
464 var tmp = tmpDir(.{});476 var tmp = tmpDir(.{});
465 defer tmp.cleanup();477 defer tmp.cleanup();
466478
467 var subdir = try tmp.dir.makeOpenPath("subdir", .{});479 var subdir = try tmp.dir.makeOpenPath("subdir", .{});
468 defer subdir.close();480 defer subdir.close(io);
469481
470 var dir = try subdir.openDir("..", .{});482 var dir = try subdir.openDir("..", .{});
471 defer dir.close();483 defer dir.close(io);
472484
473 const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");485 const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
474 defer testing.allocator.free(expected_path);486 defer testing.allocator.free(expected_path);
...@@ -516,12 +528,14 @@ test "readLinkAbsolute" {...@@ -516,12 +528,14 @@ test "readLinkAbsolute" {
516}528}
517529
518test "Dir.Iterator" {530test "Dir.Iterator" {
531 const io = testing.io;
532
519 var tmp_dir = tmpDir(.{ .iterate = true });533 var tmp_dir = tmpDir(.{ .iterate = true });
520 defer tmp_dir.cleanup();534 defer tmp_dir.cleanup();
521535
522 // First, create a couple of entries to iterate over.536 // First, create a couple of entries to iterate over.
523 const file = try tmp_dir.dir.createFile("some_file", .{});537 const file = try tmp_dir.dir.createFile("some_file", .{});
524 file.close();538 file.close(io);
525539
526 try tmp_dir.dir.makeDir("some_dir");540 try tmp_dir.dir.makeDir("some_dir");
527541
...@@ -546,6 +560,8 @@ test "Dir.Iterator" {...@@ -546,6 +560,8 @@ test "Dir.Iterator" {
546}560}
547561
548test "Dir.Iterator many entries" {562test "Dir.Iterator many entries" {
563 const io = testing.io;
564
549 var tmp_dir = tmpDir(.{ .iterate = true });565 var tmp_dir = tmpDir(.{ .iterate = true });
550 defer tmp_dir.cleanup();566 defer tmp_dir.cleanup();
551567
...@@ -555,7 +571,7 @@ test "Dir.Iterator many entries" {...@@ -555,7 +571,7 @@ test "Dir.Iterator many entries" {
555 while (i < num) : (i += 1) {571 while (i < num) : (i += 1) {
556 const name = try std.fmt.bufPrint(&buf, "{}", .{i});572 const name = try std.fmt.bufPrint(&buf, "{}", .{i});
557 const file = try tmp_dir.dir.createFile(name, .{});573 const file = try tmp_dir.dir.createFile(name, .{});
558 file.close();574 file.close(io);
559 }575 }
560576
561 var arena = ArenaAllocator.init(testing.allocator);577 var arena = ArenaAllocator.init(testing.allocator);
...@@ -581,12 +597,14 @@ test "Dir.Iterator many entries" {...@@ -581,12 +597,14 @@ test "Dir.Iterator many entries" {
581}597}
582598
583test "Dir.Iterator twice" {599test "Dir.Iterator twice" {
600 const io = testing.io;
601
584 var tmp_dir = tmpDir(.{ .iterate = true });602 var tmp_dir = tmpDir(.{ .iterate = true });
585 defer tmp_dir.cleanup();603 defer tmp_dir.cleanup();
586604
587 // First, create a couple of entries to iterate over.605 // First, create a couple of entries to iterate over.
588 const file = try tmp_dir.dir.createFile("some_file", .{});606 const file = try tmp_dir.dir.createFile("some_file", .{});
589 file.close();607 file.close(io);
590608
591 try tmp_dir.dir.makeDir("some_dir");609 try tmp_dir.dir.makeDir("some_dir");
592610
...@@ -614,12 +632,14 @@ test "Dir.Iterator twice" {...@@ -614,12 +632,14 @@ test "Dir.Iterator twice" {
614}632}
615633
616test "Dir.Iterator reset" {634test "Dir.Iterator reset" {
635 const io = testing.io;
636
617 var tmp_dir = tmpDir(.{ .iterate = true });637 var tmp_dir = tmpDir(.{ .iterate = true });
618 defer tmp_dir.cleanup();638 defer tmp_dir.cleanup();
619639
620 // First, create a couple of entries to iterate over.640 // First, create a couple of entries to iterate over.
621 const file = try tmp_dir.dir.createFile("some_file", .{});641 const file = try tmp_dir.dir.createFile("some_file", .{});
622 file.close();642 file.close(io);
623643
624 try tmp_dir.dir.makeDir("some_dir");644 try tmp_dir.dir.makeDir("some_dir");
625645
...@@ -650,12 +670,14 @@ test "Dir.Iterator reset" {...@@ -650,12 +670,14 @@ test "Dir.Iterator reset" {
650}670}
651671
652test "Dir.Iterator but dir is deleted during iteration" {672test "Dir.Iterator but dir is deleted during iteration" {
673 const io = testing.io;
674
653 var tmp = std.testing.tmpDir(.{});675 var tmp = std.testing.tmpDir(.{});
654 defer tmp.cleanup();676 defer tmp.cleanup();
655677
656 // Create directory and setup an iterator for it678 // Create directory and setup an iterator for it
657 var subdir = try tmp.dir.makeOpenPath("subdir", .{ .iterate = true });679 var subdir = try tmp.dir.makeOpenPath("subdir", .{ .iterate = true });
658 defer subdir.close();680 defer subdir.close(io);
659681
660 var iterator = subdir.iterate();682 var iterator = subdir.iterate();
661683
...@@ -742,11 +764,13 @@ test "Dir.realpath smoke test" {...@@ -742,11 +764,13 @@ test "Dir.realpath smoke test" {
742}764}
743765
744test "readFileAlloc" {766test "readFileAlloc" {
767 const io = testing.io;
768
745 var tmp_dir = tmpDir(.{});769 var tmp_dir = tmpDir(.{});
746 defer tmp_dir.cleanup();770 defer tmp_dir.cleanup();
747771
748 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });772 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
749 defer file.close();773 defer file.close(io);
750774
751 const buf1 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(1024));775 const buf1 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(1024));
752 defer testing.allocator.free(buf1);776 defer testing.allocator.free(buf1);
...@@ -815,10 +839,12 @@ test "statFile on dangling symlink" {...@@ -815,10 +839,12 @@ test "statFile on dangling symlink" {
815test "directory operations on files" {839test "directory operations on files" {
816 try testWithAllSupportedPathTypes(struct {840 try testWithAllSupportedPathTypes(struct {
817 fn impl(ctx: *TestContext) !void {841 fn impl(ctx: *TestContext) !void {
842 const io = ctx.io;
843
818 const test_file_name = try ctx.transformPath("test_file");844 const test_file_name = try ctx.transformPath("test_file");
819845
820 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });846 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });
821 file.close();847 file.close(io);
822848
823 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(test_file_name));849 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(test_file_name));
824 try testing.expectError(error.NotDir, ctx.dir.openDir(test_file_name, .{}));850 try testing.expectError(error.NotDir, ctx.dir.openDir(test_file_name, .{}));
...@@ -833,7 +859,7 @@ test "directory operations on files" {...@@ -833,7 +859,7 @@ test "directory operations on files" {
833 file = try ctx.dir.openFile(test_file_name, .{});859 file = try ctx.dir.openFile(test_file_name, .{});
834 const stat = try file.stat();860 const stat = try file.stat();
835 try testing.expectEqual(File.Kind.file, stat.kind);861 try testing.expectEqual(File.Kind.file, stat.kind);
836 file.close();862 file.close(io);
837 }863 }
838 }.impl);864 }.impl);
839}865}
...@@ -842,6 +868,8 @@ test "file operations on directories" {...@@ -842,6 +868,8 @@ test "file operations on directories" {
842 // TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759868 // TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
843 if (native_os == .freebsd) return error.SkipZigTest;869 if (native_os == .freebsd) return error.SkipZigTest;
844870
871 const io = testing.io;
872
845 try testWithAllSupportedPathTypes(struct {873 try testWithAllSupportedPathTypes(struct {
846 fn impl(ctx: *TestContext) !void {874 fn impl(ctx: *TestContext) !void {
847 const test_dir_name = try ctx.transformPath("test_dir");875 const test_dir_name = try ctx.transformPath("test_dir");
...@@ -869,7 +897,7 @@ test "file operations on directories" {...@@ -869,7 +897,7 @@ test "file operations on directories" {
869 if (native_os == .wasi and builtin.link_libc) {897 if (native_os == .wasi and builtin.link_libc) {
870 // wasmtime unexpectedly succeeds here, see https://github.com/ziglang/zig/issues/20747898 // wasmtime unexpectedly succeeds here, see https://github.com/ziglang/zig/issues/20747
871 const handle = try ctx.dir.openFile(test_dir_name, .{ .mode = .read_write });899 const handle = try ctx.dir.openFile(test_dir_name, .{ .mode = .read_write });
872 handle.close();900 handle.close(io);
873 } else {901 } else {
874 // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.902 // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.
875 // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732903 // 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" {...@@ -883,21 +911,23 @@ test "file operations on directories" {
883911
884 // ensure the directory still exists as a sanity check912 // ensure the directory still exists as a sanity check
885 var dir = try ctx.dir.openDir(test_dir_name, .{});913 var dir = try ctx.dir.openDir(test_dir_name, .{});
886 dir.close();914 dir.close(io);
887 }915 }
888 }.impl);916 }.impl);
889}917}
890918
891test "makeOpenPath parent dirs do not exist" {919test "makeOpenPath parent dirs do not exist" {
920 const io = testing.io;
921
892 var tmp_dir = tmpDir(.{});922 var tmp_dir = tmpDir(.{});
893 defer tmp_dir.cleanup();923 defer tmp_dir.cleanup();
894924
895 var dir = try tmp_dir.dir.makeOpenPath("root_dir/parent_dir/some_dir", .{});925 var dir = try tmp_dir.dir.makeOpenPath("root_dir/parent_dir/some_dir", .{});
896 dir.close();926 dir.close(io);
897927
898 // double check that the full directory structure was created928 // double check that the full directory structure was created
899 var dir_verification = try tmp_dir.dir.openDir("root_dir/parent_dir/some_dir", .{});929 var dir_verification = try tmp_dir.dir.openDir("root_dir/parent_dir/some_dir", .{});
900 dir_verification.close();930 dir_verification.close(io);
901}931}
902932
903test "deleteDir" {933test "deleteDir" {
...@@ -924,6 +954,7 @@ test "deleteDir" {...@@ -924,6 +954,7 @@ test "deleteDir" {
924test "Dir.rename files" {954test "Dir.rename files" {
925 try testWithAllSupportedPathTypes(struct {955 try testWithAllSupportedPathTypes(struct {
926 fn impl(ctx: *TestContext) !void {956 fn impl(ctx: *TestContext) !void {
957 const io = ctx.io;
927 // Rename on Windows can hit intermittent AccessDenied errors958 // Rename on Windows can hit intermittent AccessDenied errors
928 // when certain conditions are true about the host system.959 // when certain conditions are true about the host system.
929 // For now, skip this test when the path type is UNC to avoid them.960 // For now, skip this test when the path type is UNC to avoid them.
...@@ -939,13 +970,13 @@ test "Dir.rename files" {...@@ -939,13 +970,13 @@ test "Dir.rename files" {
939 const test_file_name = try ctx.transformPath("test_file");970 const test_file_name = try ctx.transformPath("test_file");
940 const renamed_test_file_name = try ctx.transformPath("test_file_renamed");971 const renamed_test_file_name = try ctx.transformPath("test_file_renamed");
941 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });972 var file = try ctx.dir.createFile(test_file_name, .{ .read = true });
942 file.close();973 file.close(io);
943 try ctx.dir.rename(test_file_name, renamed_test_file_name);974 try ctx.dir.rename(test_file_name, renamed_test_file_name);
944975
945 // Ensure the file was renamed976 // Ensure the file was renamed
946 try testing.expectError(error.FileNotFound, ctx.dir.openFile(test_file_name, .{}));977 try testing.expectError(error.FileNotFound, ctx.dir.openFile(test_file_name, .{}));
947 file = try ctx.dir.openFile(renamed_test_file_name, .{});978 file = try ctx.dir.openFile(renamed_test_file_name, .{});
948 file.close();979 file.close(io);
949980
950 // Rename to self succeeds981 // Rename to self succeeds
951 try ctx.dir.rename(renamed_test_file_name, renamed_test_file_name);982 try ctx.dir.rename(renamed_test_file_name, renamed_test_file_name);
...@@ -953,12 +984,12 @@ test "Dir.rename files" {...@@ -953,12 +984,12 @@ test "Dir.rename files" {
953 // Rename to existing file succeeds984 // Rename to existing file succeeds
954 const existing_file_path = try ctx.transformPath("existing_file");985 const existing_file_path = try ctx.transformPath("existing_file");
955 var existing_file = try ctx.dir.createFile(existing_file_path, .{ .read = true });986 var existing_file = try ctx.dir.createFile(existing_file_path, .{ .read = true });
956 existing_file.close();987 existing_file.close(io);
957 try ctx.dir.rename(renamed_test_file_name, existing_file_path);988 try ctx.dir.rename(renamed_test_file_name, existing_file_path);
958989
959 try testing.expectError(error.FileNotFound, ctx.dir.openFile(renamed_test_file_name, .{}));990 try testing.expectError(error.FileNotFound, ctx.dir.openFile(renamed_test_file_name, .{}));
960 file = try ctx.dir.openFile(existing_file_path, .{});991 file = try ctx.dir.openFile(existing_file_path, .{});
961 file.close();992 file.close(io);
962 }993 }
963 }.impl);994 }.impl);
964}995}
...@@ -966,6 +997,8 @@ test "Dir.rename files" {...@@ -966,6 +997,8 @@ test "Dir.rename files" {
966test "Dir.rename directories" {997test "Dir.rename directories" {
967 try testWithAllSupportedPathTypes(struct {998 try testWithAllSupportedPathTypes(struct {
968 fn impl(ctx: *TestContext) !void {999 fn impl(ctx: *TestContext) !void {
1000 const io = ctx.io;
1001
969 // Rename on Windows can hit intermittent AccessDenied errors1002 // Rename on Windows can hit intermittent AccessDenied errors
970 // when certain conditions are true about the host system.1003 // when certain conditions are true about the host system.
971 // For now, skip this test when the path type is UNC to avoid them.1004 // For now, skip this test when the path type is UNC to avoid them.
...@@ -985,8 +1018,8 @@ test "Dir.rename directories" {...@@ -985,8 +1018,8 @@ test "Dir.rename directories" {
9851018
986 // Put a file in the directory1019 // Put a file in the directory
987 var file = try dir.createFile("test_file", .{ .read = true });1020 var file = try dir.createFile("test_file", .{ .read = true });
988 file.close();1021 file.close(io);
989 dir.close();1022 dir.close(io);
9901023
991 const test_dir_renamed_again_path = try ctx.transformPath("test_dir_renamed_again");1024 const test_dir_renamed_again_path = try ctx.transformPath("test_dir_renamed_again");
992 try ctx.dir.rename(test_dir_renamed_path, test_dir_renamed_again_path);1025 try ctx.dir.rename(test_dir_renamed_path, test_dir_renamed_again_path);
...@@ -995,8 +1028,8 @@ test "Dir.rename directories" {...@@ -995,8 +1028,8 @@ test "Dir.rename directories" {
995 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_renamed_path, .{}));1028 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_renamed_path, .{}));
996 dir = try ctx.dir.openDir(test_dir_renamed_again_path, .{});1029 dir = try ctx.dir.openDir(test_dir_renamed_again_path, .{});
997 file = try dir.openFile("test_file", .{});1030 file = try dir.openFile("test_file", .{});
998 file.close();1031 file.close(io);
999 dir.close();1032 dir.close(io);
1000 }1033 }
1001 }.impl);1034 }.impl);
1002}1035}
...@@ -1007,6 +1040,8 @@ test "Dir.rename directory onto empty dir" {...@@ -1007,6 +1040,8 @@ test "Dir.rename directory onto empty dir" {
10071040
1008 try testWithAllSupportedPathTypes(struct {1041 try testWithAllSupportedPathTypes(struct {
1009 fn impl(ctx: *TestContext) !void {1042 fn impl(ctx: *TestContext) !void {
1043 const io = ctx.io;
1044
1010 const test_dir_path = try ctx.transformPath("test_dir");1045 const test_dir_path = try ctx.transformPath("test_dir");
1011 const target_dir_path = try ctx.transformPath("target_dir_path");1046 const target_dir_path = try ctx.transformPath("target_dir_path");
10121047
...@@ -1017,7 +1052,7 @@ test "Dir.rename directory onto empty dir" {...@@ -1017,7 +1052,7 @@ test "Dir.rename directory onto empty dir" {
1017 // Ensure the directory was renamed1052 // Ensure the directory was renamed
1018 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_path, .{}));1053 try testing.expectError(error.FileNotFound, ctx.dir.openDir(test_dir_path, .{}));
1019 var dir = try ctx.dir.openDir(target_dir_path, .{});1054 var dir = try ctx.dir.openDir(target_dir_path, .{});
1020 dir.close();1055 dir.close(io);
1021 }1056 }
1022 }.impl);1057 }.impl);
1023}1058}
...@@ -1028,6 +1063,7 @@ test "Dir.rename directory onto non-empty dir" {...@@ -1028,6 +1063,7 @@ test "Dir.rename directory onto non-empty dir" {
10281063
1029 try testWithAllSupportedPathTypes(struct {1064 try testWithAllSupportedPathTypes(struct {
1030 fn impl(ctx: *TestContext) !void {1065 fn impl(ctx: *TestContext) !void {
1066 const io = ctx.io;
1031 const test_dir_path = try ctx.transformPath("test_dir");1067 const test_dir_path = try ctx.transformPath("test_dir");
1032 const target_dir_path = try ctx.transformPath("target_dir_path");1068 const target_dir_path = try ctx.transformPath("target_dir_path");
10331069
...@@ -1035,15 +1071,15 @@ test "Dir.rename directory onto non-empty dir" {...@@ -1035,15 +1071,15 @@ test "Dir.rename directory onto non-empty dir" {
10351071
1036 var target_dir = try ctx.dir.makeOpenPath(target_dir_path, .{});1072 var target_dir = try ctx.dir.makeOpenPath(target_dir_path, .{});
1037 var file = try target_dir.createFile("test_file", .{ .read = true });1073 var file = try target_dir.createFile("test_file", .{ .read = true });
1038 file.close();1074 file.close(io);
1039 target_dir.close();1075 target_dir.close(io);
10401076
1041 // Rename should fail with PathAlreadyExists if target_dir is non-empty1077 // Rename should fail with PathAlreadyExists if target_dir is non-empty
1042 try testing.expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, target_dir_path));1078 try testing.expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, target_dir_path));
10431079
1044 // Ensure the directory was not renamed1080 // Ensure the directory was not renamed
1045 var dir = try ctx.dir.openDir(test_dir_path, .{});1081 var dir = try ctx.dir.openDir(test_dir_path, .{});
1046 dir.close();1082 dir.close(io);
1047 }1083 }
1048 }.impl);1084 }.impl);
1049}1085}
...@@ -1054,11 +1090,12 @@ test "Dir.rename file <-> dir" {...@@ -1054,11 +1090,12 @@ test "Dir.rename file <-> dir" {
10541090
1055 try testWithAllSupportedPathTypes(struct {1091 try testWithAllSupportedPathTypes(struct {
1056 fn impl(ctx: *TestContext) !void {1092 fn impl(ctx: *TestContext) !void {
1093 const io = ctx.io;
1057 const test_file_path = try ctx.transformPath("test_file");1094 const test_file_path = try ctx.transformPath("test_file");
1058 const test_dir_path = try ctx.transformPath("test_dir");1095 const test_dir_path = try ctx.transformPath("test_dir");
10591096
1060 var file = try ctx.dir.createFile(test_file_path, .{ .read = true });1097 var file = try ctx.dir.createFile(test_file_path, .{ .read = true });
1061 file.close();1098 file.close(io);
1062 try ctx.dir.makeDir(test_dir_path);1099 try ctx.dir.makeDir(test_dir_path);
1063 try testing.expectError(error.IsDir, ctx.dir.rename(test_file_path, test_dir_path));1100 try testing.expectError(error.IsDir, ctx.dir.rename(test_file_path, test_dir_path));
1064 try testing.expectError(error.NotDir, ctx.dir.rename(test_dir_path, test_file_path));1101 try testing.expectError(error.NotDir, ctx.dir.rename(test_dir_path, test_file_path));
...@@ -1067,6 +1104,8 @@ test "Dir.rename file <-> dir" {...@@ -1067,6 +1104,8 @@ test "Dir.rename file <-> dir" {
1067}1104}
10681105
1069test "rename" {1106test "rename" {
1107 const io = testing.io;
1108
1070 var tmp_dir1 = tmpDir(.{});1109 var tmp_dir1 = tmpDir(.{});
1071 defer tmp_dir1.cleanup();1110 defer tmp_dir1.cleanup();
10721111
...@@ -1077,19 +1116,21 @@ test "rename" {...@@ -1077,19 +1116,21 @@ test "rename" {
1077 const test_file_name = "test_file";1116 const test_file_name = "test_file";
1078 const renamed_test_file_name = "test_file_renamed";1117 const renamed_test_file_name = "test_file_renamed";
1079 var file = try tmp_dir1.dir.createFile(test_file_name, .{ .read = true });1118 var file = try tmp_dir1.dir.createFile(test_file_name, .{ .read = true });
1080 file.close();1119 file.close(io);
1081 try fs.rename(tmp_dir1.dir, test_file_name, tmp_dir2.dir, renamed_test_file_name);1120 try fs.rename(tmp_dir1.dir, test_file_name, tmp_dir2.dir, renamed_test_file_name);
10821121
1083 // ensure the file was renamed1122 // ensure the file was renamed
1084 try testing.expectError(error.FileNotFound, tmp_dir1.dir.openFile(test_file_name, .{}));1123 try testing.expectError(error.FileNotFound, tmp_dir1.dir.openFile(test_file_name, .{}));
1085 file = try tmp_dir2.dir.openFile(renamed_test_file_name, .{});1124 file = try tmp_dir2.dir.openFile(renamed_test_file_name, .{});
1086 file.close();1125 file.close(io);
1087}1126}
10881127
1089test "renameAbsolute" {1128test "renameAbsolute" {
1090 if (native_os == .wasi) return error.SkipZigTest;1129 if (native_os == .wasi) return error.SkipZigTest;
1091 if (native_os == .openbsd) return error.SkipZigTest;1130 if (native_os == .openbsd) return error.SkipZigTest;
10921131
1132 const io = testing.io;
1133
1093 var tmp_dir = tmpDir(.{});1134 var tmp_dir = tmpDir(.{});
1094 defer tmp_dir.cleanup();1135 defer tmp_dir.cleanup();
10951136
...@@ -1109,7 +1150,7 @@ test "renameAbsolute" {...@@ -1109,7 +1150,7 @@ test "renameAbsolute" {
1109 const test_file_name = "test_file";1150 const test_file_name = "test_file";
1110 const renamed_test_file_name = "test_file_renamed";1151 const renamed_test_file_name = "test_file_renamed";
1111 var file = try tmp_dir.dir.createFile(test_file_name, .{ .read = true });1152 var file = try tmp_dir.dir.createFile(test_file_name, .{ .read = true });
1112 file.close();1153 file.close(io);
1113 try fs.renameAbsolute(1154 try fs.renameAbsolute(
1114 try fs.path.join(allocator, &.{ base_path, test_file_name }),1155 try fs.path.join(allocator, &.{ base_path, test_file_name }),
1115 try fs.path.join(allocator, &.{ base_path, renamed_test_file_name }),1156 try fs.path.join(allocator, &.{ base_path, renamed_test_file_name }),
...@@ -1120,7 +1161,7 @@ test "renameAbsolute" {...@@ -1120,7 +1161,7 @@ test "renameAbsolute" {
1120 file = try tmp_dir.dir.openFile(renamed_test_file_name, .{});1161 file = try tmp_dir.dir.openFile(renamed_test_file_name, .{});
1121 const stat = try file.stat();1162 const stat = try file.stat();
1122 try testing.expectEqual(File.Kind.file, stat.kind);1163 try testing.expectEqual(File.Kind.file, stat.kind);
1123 file.close();1164 file.close(io);
11241165
1125 // Renaming directories1166 // Renaming directories
1126 const test_dir_name = "test_dir";1167 const test_dir_name = "test_dir";
...@@ -1134,14 +1175,16 @@ test "renameAbsolute" {...@@ -1134,14 +1175,16 @@ test "renameAbsolute" {
1134 // ensure the directory was renamed1175 // ensure the directory was renamed
1135 try testing.expectError(error.FileNotFound, tmp_dir.dir.openDir(test_dir_name, .{}));1176 try testing.expectError(error.FileNotFound, tmp_dir.dir.openDir(test_dir_name, .{}));
1136 var dir = try tmp_dir.dir.openDir(renamed_test_dir_name, .{});1177 var dir = try tmp_dir.dir.openDir(renamed_test_dir_name, .{});
1137 dir.close();1178 dir.close(io);
1138}1179}
11391180
1140test "openSelfExe" {1181test "openSelfExe" {
1141 if (native_os == .wasi) return error.SkipZigTest;1182 if (native_os == .wasi) return error.SkipZigTest;
11421183
1184 const io = testing.io;
1185
1143 const self_exe_file = try std.fs.openSelfExe(.{});1186 const self_exe_file = try std.fs.openSelfExe(.{});
1144 self_exe_file.close();1187 self_exe_file.close(io);
1145}1188}
11461189
1147test "selfExePath" {1190test "selfExePath" {
...@@ -1155,13 +1198,15 @@ test "selfExePath" {...@@ -1155,13 +1198,15 @@ test "selfExePath" {
1155}1198}
11561199
1157test "deleteTree does not follow symlinks" {1200test "deleteTree does not follow symlinks" {
1201 const io = testing.io;
1202
1158 var tmp = tmpDir(.{});1203 var tmp = tmpDir(.{});
1159 defer tmp.cleanup();1204 defer tmp.cleanup();
11601205
1161 try tmp.dir.makePath("b");1206 try tmp.dir.makePath("b");
1162 {1207 {
1163 var a = try tmp.dir.makeOpenPath("a", .{});1208 var a = try tmp.dir.makeOpenPath("a", .{});
1164 defer a.close();1209 defer a.close(io);
11651210
1166 try setupSymlink(a, "../b", "b", .{ .is_directory = true });1211 try setupSymlink(a, "../b", "b", .{ .is_directory = true });
1167 }1212 }
...@@ -1257,27 +1302,31 @@ test "makePath but sub_path contains pre-existing file" {...@@ -1257,27 +1302,31 @@ test "makePath but sub_path contains pre-existing file" {
1257 try testing.expectError(error.NotDir, tmp.dir.makePath("foo/bar/baz"));1302 try testing.expectError(error.NotDir, tmp.dir.makePath("foo/bar/baz"));
1258}1303}
12591304
1260fn expectDir(dir: Dir, path: []const u8) !void {1305fn expectDir(io: Io, dir: Dir, path: []const u8) !void {
1261 var d = try dir.openDir(path, .{});1306 var d = try dir.openDir(path, .{});
1262 d.close();1307 d.close(io);
1263}1308}
12641309
1265test "makepath existing directories" {1310test "makepath existing directories" {
1311 const io = testing.io;
1312
1266 var tmp = tmpDir(.{});1313 var tmp = tmpDir(.{});
1267 defer tmp.cleanup();1314 defer tmp.cleanup();
12681315
1269 try tmp.dir.makeDir("A");1316 try tmp.dir.makeDir("A");
1270 var tmpA = try tmp.dir.openDir("A", .{});1317 var tmpA = try tmp.dir.openDir("A", .{});
1271 defer tmpA.close();1318 defer tmpA.close(io);
1272 try tmpA.makeDir("B");1319 try tmpA.makeDir("B");
12731320
1274 const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";1321 const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";
1275 try tmp.dir.makePath(testPath);1322 try tmp.dir.makePath(testPath);
12761323
1277 try expectDir(tmp.dir, testPath);1324 try expectDir(io, tmp.dir, testPath);
1278}1325}
12791326
1280test "makepath through existing valid symlink" {1327test "makepath through existing valid symlink" {
1328 const io = testing.io;
1329
1281 var tmp = tmpDir(.{});1330 var tmp = tmpDir(.{});
1282 defer tmp.cleanup();1331 defer tmp.cleanup();
12831332
...@@ -1286,10 +1335,12 @@ test "makepath through existing valid symlink" {...@@ -1286,10 +1335,12 @@ test "makepath through existing valid symlink" {
12861335
1287 try tmp.dir.makePath("working-symlink" ++ fs.path.sep_str ++ "in-realfolder");1336 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");
1290}1339}
12911340
1292test "makepath relative walks" {1341test "makepath relative walks" {
1342 const io = testing.io;
1343
1293 var tmp = tmpDir(.{});1344 var tmp = tmpDir(.{});
1294 defer tmp.cleanup();1345 defer tmp.cleanup();
12951346
...@@ -1305,21 +1356,23 @@ test "makepath relative walks" {...@@ -1305,21 +1356,23 @@ test "makepath relative walks" {
1305 .windows => {1356 .windows => {
1306 // On Windows, .. is resolved before passing the path to NtCreateFile,1357 // On Windows, .. is resolved before passing the path to NtCreateFile,
1307 // meaning everything except `first/C` drops out.1358 // 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");
1309 try testing.expectError(error.FileNotFound, tmp.dir.access("second", .{}));1360 try testing.expectError(error.FileNotFound, tmp.dir.access("second", .{}));
1310 try testing.expectError(error.FileNotFound, tmp.dir.access("third", .{}));1361 try testing.expectError(error.FileNotFound, tmp.dir.access("third", .{}));
1311 },1362 },
1312 else => {1363 else => {
1313 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "A");1364 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "A");
1314 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "B");1365 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "B");
1315 try expectDir(tmp.dir, "first" ++ fs.path.sep_str ++ "C");1366 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
1316 try expectDir(tmp.dir, "second");1367 try expectDir(io, tmp.dir, "second");
1317 try expectDir(tmp.dir, "third");1368 try expectDir(io, tmp.dir, "third");
1318 },1369 },
1319 }1370 }
1320}1371}
13211372
1322test "makepath ignores '.'" {1373test "makepath ignores '.'" {
1374 const io = testing.io;
1375
1323 var tmp = tmpDir(.{});1376 var tmp = tmpDir(.{});
1324 defer tmp.cleanup();1377 defer tmp.cleanup();
13251378
...@@ -1337,14 +1390,14 @@ test "makepath ignores '.'" {...@@ -1337,14 +1390,14 @@ test "makepath ignores '.'" {
13371390
1338 try tmp.dir.makePath(dotPath);1391 try tmp.dir.makePath(dotPath);
13391392
1340 try expectDir(tmp.dir, expectedPath);1393 try expectDir(io, tmp.dir, expectedPath);
1341}1394}
13421395
1343fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {1396fn testFilenameLimits(io: Io, iterable_dir: Dir, maxed_filename: []const u8) !void {
1344 // setup, create a dir and a nested file both with maxed filenames, and walk the dir1397 // setup, create a dir and a nested file both with maxed filenames, and walk the dir
1345 {1398 {
1346 var maxed_dir = try iterable_dir.makeOpenPath(maxed_filename, .{});1399 var maxed_dir = try iterable_dir.makeOpenPath(maxed_filename, .{});
1347 defer maxed_dir.close();1400 defer maxed_dir.close(io);
13481401
1349 try maxed_dir.writeFile(.{ .sub_path = maxed_filename, .data = "" });1402 try maxed_dir.writeFile(.{ .sub_path = maxed_filename, .data = "" });
13501403
...@@ -1364,6 +1417,8 @@ fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {...@@ -1364,6 +1417,8 @@ fn testFilenameLimits(iterable_dir: Dir, maxed_filename: []const u8) !void {
1364}1417}
13651418
1366test "max file name component lengths" {1419test "max file name component lengths" {
1420 const io = testing.io;
1421
1367 var tmp = tmpDir(.{ .iterate = true });1422 var tmp = tmpDir(.{ .iterate = true });
1368 defer tmp.cleanup();1423 defer tmp.cleanup();
13691424
...@@ -1371,16 +1426,16 @@ test "max file name component lengths" {...@@ -1371,16 +1426,16 @@ test "max file name component lengths" {
1371 // U+FFFF is the character with the largest code point that is encoded as a single1426 // U+FFFF is the character with the largest code point that is encoded as a single
1372 // UTF-16 code unit, so Windows allows for NAME_MAX of them.1427 // UTF-16 code unit, so Windows allows for NAME_MAX of them.
1373 const maxed_windows_filename = ("\u{FFFF}".*) ** windows.NAME_MAX;1428 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);
1375 } else if (native_os == .wasi) {1430 } else if (native_os == .wasi) {
1376 // On WASI, the maxed filename depends on the host OS, so in order for this test to1431 // On WASI, the maxed filename depends on the host OS, so in order for this test to
1377 // work on any host, we need to use a length that will work for all platforms1432 // work on any host, we need to use a length that will work for all platforms
1378 // (i.e. the minimum max_name_bytes of all supported platforms).1433 // (i.e. the minimum max_name_bytes of all supported platforms).
1379 const maxed_wasi_filename = [_]u8{'1'} ** 255;1434 const maxed_wasi_filename = [_]u8{'1'} ** 255;
1380 try testFilenameLimits(tmp.dir, &maxed_wasi_filename);1435 try testFilenameLimits(io, tmp.dir, &maxed_wasi_filename);
1381 } else {1436 } else {
1382 const maxed_ascii_filename = [_]u8{'1'} ** std.fs.max_name_bytes;1437 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);
1384 }1439 }
1385}1440}
13861441
...@@ -1399,7 +1454,7 @@ test "writev, readv" {...@@ -1399,7 +1454,7 @@ test "writev, readv" {
1399 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };1454 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };
14001455
1401 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });1456 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
1402 defer src_file.close();1457 defer src_file.close(io);
14031458
1404 var writer = src_file.writerStreaming(&.{});1459 var writer = src_file.writerStreaming(&.{});
14051460
...@@ -1429,7 +1484,7 @@ test "pwritev, preadv" {...@@ -1429,7 +1484,7 @@ test "pwritev, preadv" {
1429 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };1484 var read_vecs: [2][]u8 = .{ &buf2, &buf1 };
14301485
1431 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });1486 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
1432 defer src_file.close();1487 defer src_file.close(io);
14331488
1434 var writer = src_file.writer(&.{});1489 var writer = src_file.writer(&.{});
14351490
...@@ -1459,7 +1514,7 @@ test "setEndPos" {...@@ -1459,7 +1514,7 @@ test "setEndPos" {
1459 const file_name = "afile.txt";1514 const file_name = "afile.txt";
1460 try tmp.dir.writeFile(.{ .sub_path = file_name, .data = "ninebytes" });1515 try tmp.dir.writeFile(.{ .sub_path = file_name, .data = "ninebytes" });
1461 const f = try tmp.dir.openFile(file_name, .{ .mode = .read_write });1516 const f = try tmp.dir.openFile(file_name, .{ .mode = .read_write });
1462 defer f.close();1517 defer f.close(io);
14631518
1464 const initial_size = try f.getEndPos();1519 const initial_size = try f.getEndPos();
1465 var buffer: [32]u8 = undefined;1520 var buffer: [32]u8 = undefined;
...@@ -1522,21 +1577,21 @@ test "sendfile" {...@@ -1522,21 +1577,21 @@ test "sendfile" {
1522 try tmp.dir.makePath("os_test_tmp");1577 try tmp.dir.makePath("os_test_tmp");
15231578
1524 var dir = try tmp.dir.openDir("os_test_tmp", .{});1579 var dir = try tmp.dir.openDir("os_test_tmp", .{});
1525 defer dir.close();1580 defer dir.close(io);
15261581
1527 const line1 = "line1\n";1582 const line1 = "line1\n";
1528 const line2 = "second line\n";1583 const line2 = "second line\n";
1529 var vecs = [_][]const u8{ line1, line2 };1584 var vecs = [_][]const u8{ line1, line2 };
15301585
1531 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });1586 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });
1532 defer src_file.close();1587 defer src_file.close(io);
1533 {1588 {
1534 var fw = src_file.writer(&.{});1589 var fw = src_file.writer(&.{});
1535 try fw.interface.writeVecAll(&vecs);1590 try fw.interface.writeVecAll(&vecs);
1536 }1591 }
15371592
1538 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });1593 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });
1539 defer dest_file.close();1594 defer dest_file.close(io);
15401595
1541 const header1 = "header1\n";1596 const header1 = "header1\n";
1542 const header2 = "second header\n";1597 const header2 = "second header\n";
...@@ -1569,15 +1624,15 @@ test "sendfile with buffered data" {...@@ -1569,15 +1624,15 @@ test "sendfile with buffered data" {
1569 try tmp.dir.makePath("os_test_tmp");1624 try tmp.dir.makePath("os_test_tmp");
15701625
1571 var dir = try tmp.dir.openDir("os_test_tmp", .{});1626 var dir = try tmp.dir.openDir("os_test_tmp", .{});
1572 defer dir.close();1627 defer dir.close(io);
15731628
1574 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });1629 var src_file = try dir.createFile("sendfile1.txt", .{ .read = true });
1575 defer src_file.close();1630 defer src_file.close(io);
15761631
1577 try src_file.writeAll("AAAABBBB");1632 try src_file.writeAll("AAAABBBB");
15781633
1579 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });1634 var dest_file = try dir.createFile("sendfile2.txt", .{ .read = true });
1580 defer dest_file.close();1635 defer dest_file.close(io);
15811636
1582 var src_buffer: [32]u8 = undefined;1637 var src_buffer: [32]u8 = undefined;
1583 var file_reader = src_file.reader(io, &src_buffer);1638 var file_reader = src_file.reader(io, &src_buffer);
...@@ -1659,10 +1714,11 @@ test "open file with exclusive nonblocking lock twice" {...@@ -1659,10 +1714,11 @@ test "open file with exclusive nonblocking lock twice" {
16591714
1660 try testWithAllSupportedPathTypes(struct {1715 try testWithAllSupportedPathTypes(struct {
1661 fn impl(ctx: *TestContext) !void {1716 fn impl(ctx: *TestContext) !void {
1717 const io = ctx.io;
1662 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");1718 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16631719
1664 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });1720 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1665 defer file1.close();1721 defer file1.close(io);
16661722
1667 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });1723 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1668 try testing.expectError(error.WouldBlock, file2);1724 try testing.expectError(error.WouldBlock, file2);
...@@ -1675,10 +1731,11 @@ test "open file with shared and exclusive nonblocking lock" {...@@ -1675,10 +1731,11 @@ test "open file with shared and exclusive nonblocking lock" {
16751731
1676 try testWithAllSupportedPathTypes(struct {1732 try testWithAllSupportedPathTypes(struct {
1677 fn impl(ctx: *TestContext) !void {1733 fn impl(ctx: *TestContext) !void {
1734 const io = ctx.io;
1678 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");1735 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16791736
1680 const file1 = try ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });1737 const file1 = try ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });
1681 defer file1.close();1738 defer file1.close(io);
16821739
1683 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });1740 const file2 = ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1684 try testing.expectError(error.WouldBlock, file2);1741 try testing.expectError(error.WouldBlock, file2);
...@@ -1691,10 +1748,11 @@ test "open file with exclusive and shared nonblocking lock" {...@@ -1691,10 +1748,11 @@ test "open file with exclusive and shared nonblocking lock" {
16911748
1692 try testWithAllSupportedPathTypes(struct {1749 try testWithAllSupportedPathTypes(struct {
1693 fn impl(ctx: *TestContext) !void {1750 fn impl(ctx: *TestContext) !void {
1751 const io = ctx.io;
1694 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");1752 const filename = try ctx.transformPath("file_nonblocking_lock_test.txt");
16951753
1696 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });1754 const file1 = try ctx.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1697 defer file1.close();1755 defer file1.close(io);
16981756
1699 const file2 = ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });1757 const file2 = ctx.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true });
1700 try testing.expectError(error.WouldBlock, file2);1758 try testing.expectError(error.WouldBlock, file2);
...@@ -1707,10 +1765,11 @@ test "open file with exclusive lock twice, make sure second lock waits" {...@@ -1707,10 +1765,11 @@ test "open file with exclusive lock twice, make sure second lock waits" {
17071765
1708 try testWithAllSupportedPathTypes(struct {1766 try testWithAllSupportedPathTypes(struct {
1709 fn impl(ctx: *TestContext) !void {1767 fn impl(ctx: *TestContext) !void {
1768 const io = ctx.io;
1710 const filename = try ctx.transformPath("file_lock_test.txt");1769 const filename = try ctx.transformPath("file_lock_test.txt");
17111770
1712 const file = try ctx.dir.createFile(filename, .{ .lock = .exclusive });1771 const file = try ctx.dir.createFile(filename, .{ .lock = .exclusive });
1713 errdefer file.close();1772 errdefer file.close(io);
17141773
1715 const S = struct {1774 const S = struct {
1716 fn checkFn(dir: *fs.Dir, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {1775 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" {...@@ -1718,7 +1777,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
1718 const file1 = try dir.createFile(path, .{ .lock = .exclusive });1777 const file1 = try dir.createFile(path, .{ .lock = .exclusive });
17191778
1720 locked.set();1779 locked.set();
1721 file1.close();1780 file1.close(io);
1722 }1781 }
1723 };1782 };
17241783
...@@ -1739,7 +1798,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {...@@ -1739,7 +1798,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
1739 try testing.expectError(error.Timeout, locked.timedWait(10 * std.time.ns_per_ms));1798 try testing.expectError(error.Timeout, locked.timedWait(10 * std.time.ns_per_ms));
17401799
1741 // Release the file lock which should unlock the thread to lock it and set the locked event.1800 // Release the file lock which should unlock the thread to lock it and set the locked event.
1742 file.close();1801 file.close(io);
1743 locked.wait();1802 locked.wait();
1744 }1803 }
1745 }.impl);1804 }.impl);
...@@ -1748,6 +1807,8 @@ test "open file with exclusive lock twice, make sure second lock waits" {...@@ -1748,6 +1807,8 @@ test "open file with exclusive lock twice, make sure second lock waits" {
1748test "open file with exclusive nonblocking lock twice (absolute paths)" {1807test "open file with exclusive nonblocking lock twice (absolute paths)" {
1749 if (native_os == .wasi) return error.SkipZigTest;1808 if (native_os == .wasi) return error.SkipZigTest;
17501809
1810 const io = testing.io;
1811
1751 var random_bytes: [12]u8 = undefined;1812 var random_bytes: [12]u8 = undefined;
1752 std.crypto.random.bytes(&random_bytes);1813 std.crypto.random.bytes(&random_bytes);
17531814
...@@ -1774,18 +1835,19 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {...@@ -1774,18 +1835,19 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
1774 .lock = .exclusive,1835 .lock = .exclusive,
1775 .lock_nonblocking = true,1836 .lock_nonblocking = true,
1776 });1837 });
1777 file1.close();1838 file1.close(io);
1778 try testing.expectError(error.WouldBlock, file2);1839 try testing.expectError(error.WouldBlock, file2);
1779}1840}
17801841
1781test "read from locked file" {1842test "read from locked file" {
1782 try testWithAllSupportedPathTypes(struct {1843 try testWithAllSupportedPathTypes(struct {
1783 fn impl(ctx: *TestContext) !void {1844 fn impl(ctx: *TestContext) !void {
1845 const io = ctx.io;
1784 const filename = try ctx.transformPath("read_lock_file_test.txt");1846 const filename = try ctx.transformPath("read_lock_file_test.txt");
17851847
1786 {1848 {
1787 const f = try ctx.dir.createFile(filename, .{ .read = true });1849 const f = try ctx.dir.createFile(filename, .{ .read = true });
1788 defer f.close();1850 defer f.close(io);
1789 var buffer: [1]u8 = undefined;1851 var buffer: [1]u8 = undefined;
1790 _ = try f.read(&buffer);1852 _ = try f.read(&buffer);
1791 }1853 }
...@@ -1794,9 +1856,9 @@ test "read from locked file" {...@@ -1794,9 +1856,9 @@ test "read from locked file" {
1794 .read = true,1856 .read = true,
1795 .lock = .exclusive,1857 .lock = .exclusive,
1796 });1858 });
1797 defer f.close();1859 defer f.close(io);
1798 const f2 = try ctx.dir.openFile(filename, .{});1860 const f2 = try ctx.dir.openFile(filename, .{});
1799 defer f2.close();1861 defer f2.close(io);
1800 var buffer: [1]u8 = undefined;1862 var buffer: [1]u8 = undefined;
1801 if (builtin.os.tag == .windows) {1863 if (builtin.os.tag == .windows) {
1802 try std.testing.expectError(error.LockViolation, f2.read(&buffer));1864 try std.testing.expectError(error.LockViolation, f2.read(&buffer));
...@@ -1809,6 +1871,8 @@ test "read from locked file" {...@@ -1809,6 +1871,8 @@ test "read from locked file" {
1809}1871}
18101872
1811test "walker" {1873test "walker" {
1874 const io = testing.io;
1875
1812 var tmp = tmpDir(.{ .iterate = true });1876 var tmp = tmpDir(.{ .iterate = true });
1813 defer tmp.cleanup();1877 defer tmp.cleanup();
18141878
...@@ -1857,13 +1921,15 @@ test "walker" {...@@ -1857,13 +1921,15 @@ test "walker" {
1857 };1921 };
1858 // make sure that the entry.dir is the containing dir1922 // make sure that the entry.dir is the containing dir
1859 var entry_dir = try entry.dir.openDir(entry.basename, .{});1923 var entry_dir = try entry.dir.openDir(entry.basename, .{});
1860 defer entry_dir.close();1924 defer entry_dir.close(io);
1861 num_walked += 1;1925 num_walked += 1;
1862 }1926 }
1863 try testing.expectEqual(expected_paths.kvs.len, num_walked);1927 try testing.expectEqual(expected_paths.kvs.len, num_walked);
1864}1928}
18651929
1866test "selective walker, skip entries that start with ." {1930test "selective walker, skip entries that start with ." {
1931 const io = testing.io;
1932
1867 var tmp = tmpDir(.{ .iterate = true });1933 var tmp = tmpDir(.{ .iterate = true });
1868 defer tmp.cleanup();1934 defer tmp.cleanup();
18691935
...@@ -1923,7 +1989,7 @@ test "selective walker, skip entries that start with ." {...@@ -1923,7 +1989,7 @@ test "selective walker, skip entries that start with ." {
19231989
1924 // make sure that the entry.dir is the containing dir1990 // make sure that the entry.dir is the containing dir
1925 var entry_dir = try entry.dir.openDir(entry.basename, .{});1991 var entry_dir = try entry.dir.openDir(entry.basename, .{});
1926 defer entry_dir.close();1992 defer entry_dir.close(io);
1927 num_walked += 1;1993 num_walked += 1;
1928 }1994 }
1929 try testing.expectEqual(expected_paths.kvs.len, num_walked);1995 try testing.expectEqual(expected_paths.kvs.len, num_walked);
...@@ -1968,16 +2034,16 @@ test "'.' and '..' in fs.Dir functions" {...@@ -1968,16 +2034,16 @@ test "'.' and '..' in fs.Dir functions" {
1968 try ctx.dir.makeDir(subdir_path);2034 try ctx.dir.makeDir(subdir_path);
1969 try ctx.dir.access(subdir_path, .{});2035 try ctx.dir.access(subdir_path, .{});
1970 var created_subdir = try ctx.dir.openDir(subdir_path, .{});2036 var created_subdir = try ctx.dir.openDir(subdir_path, .{});
1971 created_subdir.close();2037 created_subdir.close(io);
19722038
1973 const created_file = try ctx.dir.createFile(file_path, .{});2039 const created_file = try ctx.dir.createFile(file_path, .{});
1974 created_file.close();2040 created_file.close(io);
1975 try ctx.dir.access(file_path, .{});2041 try ctx.dir.access(file_path, .{});
19762042
1977 try ctx.dir.copyFile(file_path, ctx.dir, copy_path, .{});2043 try ctx.dir.copyFile(file_path, ctx.dir, copy_path, .{});
1978 try ctx.dir.rename(copy_path, rename_path);2044 try ctx.dir.rename(copy_path, rename_path);
1979 const renamed_file = try ctx.dir.openFile(rename_path, .{});2045 const renamed_file = try ctx.dir.openFile(rename_path, .{});
1980 renamed_file.close();2046 renamed_file.close(io);
1981 try ctx.dir.deleteFile(rename_path);2047 try ctx.dir.deleteFile(rename_path);
19822048
1983 try ctx.dir.writeFile(.{ .sub_path = update_path, .data = "something" });2049 try ctx.dir.writeFile(.{ .sub_path = update_path, .data = "something" });
...@@ -1994,6 +2060,8 @@ test "'.' and '..' in absolute functions" {...@@ -1994,6 +2060,8 @@ test "'.' and '..' in absolute functions" {
1994 if (native_os == .wasi) return error.SkipZigTest;2060 if (native_os == .wasi) return error.SkipZigTest;
1995 if (native_os == .openbsd) return error.SkipZigTest;2061 if (native_os == .openbsd) return error.SkipZigTest;
19962062
2063 const io = testing.io;
2064
1997 var tmp = tmpDir(.{});2065 var tmp = tmpDir(.{});
1998 defer tmp.cleanup();2066 defer tmp.cleanup();
19992067
...@@ -2007,11 +2075,11 @@ test "'.' and '..' in absolute functions" {...@@ -2007,11 +2075,11 @@ test "'.' and '..' in absolute functions" {
2007 try fs.makeDirAbsolute(subdir_path);2075 try fs.makeDirAbsolute(subdir_path);
2008 try fs.accessAbsolute(subdir_path, .{});2076 try fs.accessAbsolute(subdir_path, .{});
2009 var created_subdir = try fs.openDirAbsolute(subdir_path, .{});2077 var created_subdir = try fs.openDirAbsolute(subdir_path, .{});
2010 created_subdir.close();2078 created_subdir.close(io);
20112079
2012 const created_file_path = try fs.path.join(allocator, &.{ subdir_path, "../file" });2080 const created_file_path = try fs.path.join(allocator, &.{ subdir_path, "../file" });
2013 const created_file = try fs.createFileAbsolute(created_file_path, .{});2081 const created_file = try fs.createFileAbsolute(created_file_path, .{});
2014 created_file.close();2082 created_file.close(io);
2015 try fs.accessAbsolute(created_file_path, .{});2083 try fs.accessAbsolute(created_file_path, .{});
20162084
2017 const copied_file_path = try fs.path.join(allocator, &.{ subdir_path, "../copy" });2085 const copied_file_path = try fs.path.join(allocator, &.{ subdir_path, "../copy" });
...@@ -2019,7 +2087,7 @@ test "'.' and '..' in absolute functions" {...@@ -2019,7 +2087,7 @@ test "'.' and '..' in absolute functions" {
2019 const renamed_file_path = try fs.path.join(allocator, &.{ subdir_path, "../rename" });2087 const renamed_file_path = try fs.path.join(allocator, &.{ subdir_path, "../rename" });
2020 try fs.renameAbsolute(copied_file_path, renamed_file_path);2088 try fs.renameAbsolute(copied_file_path, renamed_file_path);
2021 const renamed_file = try fs.openFileAbsolute(renamed_file_path, .{});2089 const renamed_file = try fs.openFileAbsolute(renamed_file_path, .{});
2022 renamed_file.close();2090 renamed_file.close(io);
2023 try fs.deleteFileAbsolute(renamed_file_path);2091 try fs.deleteFileAbsolute(renamed_file_path);
20242092
2025 try fs.deleteDirAbsolute(subdir_path);2093 try fs.deleteDirAbsolute(subdir_path);
...@@ -2029,11 +2097,13 @@ test "chmod" {...@@ -2029,11 +2097,13 @@ test "chmod" {
2029 if (native_os == .windows or native_os == .wasi)2097 if (native_os == .windows or native_os == .wasi)
2030 return error.SkipZigTest;2098 return error.SkipZigTest;
20312099
2100 const io = testing.io;
2101
2032 var tmp = tmpDir(.{});2102 var tmp = tmpDir(.{});
2033 defer tmp.cleanup();2103 defer tmp.cleanup();
20342104
2035 const file = try tmp.dir.createFile("test_file", .{ .mode = 0o600 });2105 const file = try tmp.dir.createFile("test_file", .{ .mode = 0o600 });
2036 defer file.close();2106 defer file.close(io);
2037 try testing.expectEqual(@as(File.Mode, 0o600), (try file.stat()).mode & 0o7777);2107 try testing.expectEqual(@as(File.Mode, 0o600), (try file.stat()).mode & 0o7777);
20382108
2039 try file.chmod(0o644);2109 try file.chmod(0o644);
...@@ -2041,7 +2111,7 @@ test "chmod" {...@@ -2041,7 +2111,7 @@ test "chmod" {
20412111
2042 try tmp.dir.makeDir("test_dir");2112 try tmp.dir.makeDir("test_dir");
2043 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });2113 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
2044 defer dir.close();2114 defer dir.close(io);
20452115
2046 try dir.chmod(0o700);2116 try dir.chmod(0o700);
2047 try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat()).mode & 0o7777);2117 try testing.expectEqual(@as(File.Mode, 0o700), (try dir.stat()).mode & 0o7777);
...@@ -2051,17 +2121,19 @@ test "chown" {...@@ -2051,17 +2121,19 @@ test "chown" {
2051 if (native_os == .windows or native_os == .wasi)2121 if (native_os == .windows or native_os == .wasi)
2052 return error.SkipZigTest;2122 return error.SkipZigTest;
20532123
2124 const io = testing.io;
2125
2054 var tmp = tmpDir(.{});2126 var tmp = tmpDir(.{});
2055 defer tmp.cleanup();2127 defer tmp.cleanup();
20562128
2057 const file = try tmp.dir.createFile("test_file", .{});2129 const file = try tmp.dir.createFile("test_file", .{});
2058 defer file.close();2130 defer file.close(io);
2059 try file.chown(null, null);2131 try file.chown(null, null);
20602132
2061 try tmp.dir.makeDir("test_dir");2133 try tmp.dir.makeDir("test_dir");
20622134
2063 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });2135 var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
2064 defer dir.close();2136 defer dir.close(io);
2065 try dir.chown(null, null);2137 try dir.chown(null, null);
2066}2138}
20672139
...@@ -2157,7 +2229,7 @@ test "read file non vectored" {...@@ -2157,7 +2229,7 @@ test "read file non vectored" {
2157 const contents = "hello, world!\n";2229 const contents = "hello, world!\n";
21582230
2159 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });2231 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2160 defer file.close();2232 defer file.close(io);
2161 {2233 {
2162 var file_writer: std.fs.File.Writer = .init(file, &.{});2234 var file_writer: std.fs.File.Writer = .init(file, &.{});
2163 try file_writer.interface.writeAll(contents);2235 try file_writer.interface.writeAll(contents);
...@@ -2189,7 +2261,7 @@ test "seek keeping partial buffer" {...@@ -2189,7 +2261,7 @@ test "seek keeping partial buffer" {
2189 const contents = "0123456789";2261 const contents = "0123456789";
21902262
2191 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });2263 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2192 defer file.close();2264 defer file.close(io);
2193 {2265 {
2194 var file_writer: std.fs.File.Writer = .init(file, &.{});2266 var file_writer: std.fs.File.Writer = .init(file, &.{});
2195 try file_writer.interface.writeAll(contents);2267 try file_writer.interface.writeAll(contents);
...@@ -2231,7 +2303,7 @@ test "seekBy" {...@@ -2231,7 +2303,7 @@ test "seekBy" {
22312303
2232 try tmp_dir.dir.writeFile(.{ .sub_path = "blah.txt", .data = "let's test seekBy" });2304 try tmp_dir.dir.writeFile(.{ .sub_path = "blah.txt", .data = "let's test seekBy" });
2233 const f = try tmp_dir.dir.openFile("blah.txt", .{ .mode = .read_only });2305 const f = try tmp_dir.dir.openFile("blah.txt", .{ .mode = .read_only });
2234 defer f.close();2306 defer f.close(io);
2235 var reader = f.readerStreaming(io, &.{});2307 var reader = f.readerStreaming(io, &.{});
2236 try reader.seekBy(2);2308 try reader.seekBy(2);
22372309
...@@ -2250,7 +2322,7 @@ test "seekTo flushes buffered data" {...@@ -2250,7 +2322,7 @@ test "seekTo flushes buffered data" {
2250 const contents = "data";2322 const contents = "data";
22512323
2252 const file = try tmp.dir.createFile("seek.bin", .{ .read = true });2324 const file = try tmp.dir.createFile("seek.bin", .{ .read = true });
2253 defer file.close();2325 defer file.close(io);
2254 {2326 {
2255 var buf: [16]u8 = undefined;2327 var buf: [16]u8 = undefined;
2256 var file_writer = std.fs.File.writer(file, &buf);2328 var file_writer = std.fs.File.writer(file, &buf);
...@@ -2277,9 +2349,9 @@ test "File.Writer sendfile with buffered contents" {...@@ -2277,9 +2349,9 @@ test "File.Writer sendfile with buffered contents" {
2277 {2349 {
2278 try tmp_dir.dir.writeFile(.{ .sub_path = "a", .data = "bcd" });2350 try tmp_dir.dir.writeFile(.{ .sub_path = "a", .data = "bcd" });
2279 const in = try tmp_dir.dir.openFile("a", .{});2351 const in = try tmp_dir.dir.openFile("a", .{});
2280 defer in.close();2352 defer in.close(io);
2281 const out = try tmp_dir.dir.createFile("b", .{});2353 const out = try tmp_dir.dir.createFile("b", .{});
2282 defer out.close();2354 defer out.close(io);
22832355
2284 var in_buf: [2]u8 = undefined;2356 var in_buf: [2]u8 = undefined;
2285 var in_r = in.reader(io, &in_buf);2357 var in_r = in.reader(io, &in_buf);
...@@ -2294,7 +2366,7 @@ test "File.Writer sendfile with buffered contents" {...@@ -2294,7 +2366,7 @@ test "File.Writer sendfile with buffered contents" {
2294 }2366 }
22952367
2296 var check = try tmp_dir.dir.openFile("b", .{});2368 var check = try tmp_dir.dir.openFile("b", .{});
2297 defer check.close();2369 defer check.close(io);
2298 var check_buf: [4]u8 = undefined;2370 var check_buf: [4]u8 = undefined;
2299 var check_r = check.reader(io, &check_buf);2371 var check_r = check.reader(io, &check_buf);
2300 try testing.expectEqualStrings("abcd", try check_r.interface.take(4));2372 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...@@ -1473,6 +1473,8 @@ pub const ConnectUnixError = Allocator.Error || std.posix.SocketError || error{N
1473///1473///
1474/// This function is threadsafe.1474/// This function is threadsafe.
1475pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection {1475pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection {
1476 const io = client.io;
1477
1476 if (client.connection_pool.findConnection(.{1478 if (client.connection_pool.findConnection(.{
1477 .host = path,1479 .host = path,
1478 .port = 0,1480 .port = 0,
...@@ -1485,7 +1487,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti...@@ -1485,7 +1487,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti
1485 conn.* = .{ .data = undefined };1487 conn.* = .{ .data = undefined };
14861488
1487 const stream = try Io.net.connectUnixSocket(path);1489 const stream = try Io.net.connectUnixSocket(path);
1488 errdefer stream.close();1490 errdefer stream.close(io);
14891491
1490 conn.data = .{1492 conn.data = .{
1491 .stream = stream,1493 .stream = stream,
lib/std/os/linux/IoUring.zig+63-22
...@@ -1,13 +1,16 @@...@@ -1,13 +1,16 @@
1const IoUring = @This();1const IoUring = @This();
2const std = @import("std");2
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const is_linux = builtin.os.tag == .linux;
5
6const std = @import("std");
7const Io = std.Io;
4const assert = std.debug.assert;8const assert = std.debug.assert;
5const mem = std.mem;9const mem = std.mem;
6const net = std.Io.net;10const net = std.Io.net;
7const posix = std.posix;11const posix = std.posix;
8const linux = std.os.linux;12const linux = std.os.linux;
9const testing = std.testing;13const testing = std.testing;
10const is_linux = builtin.os.tag == .linux;
11const page_size_min = std.heap.page_size_min;14const page_size_min = std.heap.page_size_min;
1215
13fd: linux.fd_t = -1,16fd: linux.fd_t = -1,
...@@ -1975,6 +1978,8 @@ test "readv" {...@@ -1975,6 +1978,8 @@ test "readv" {
1975test "writev/fsync/readv" {1978test "writev/fsync/readv" {
1976 if (!is_linux) return error.SkipZigTest;1979 if (!is_linux) return error.SkipZigTest;
19771980
1981 const io = testing.io;
1982
1978 var ring = IoUring.init(4, 0) catch |err| switch (err) {1983 var ring = IoUring.init(4, 0) catch |err| switch (err) {
1979 error.SystemOutdated => return error.SkipZigTest,1984 error.SystemOutdated => return error.SkipZigTest,
1980 error.PermissionDenied => return error.SkipZigTest,1985 error.PermissionDenied => return error.SkipZigTest,
...@@ -1987,7 +1992,7 @@ test "writev/fsync/readv" {...@@ -1987,7 +1992,7 @@ test "writev/fsync/readv" {
19871992
1988 const path = "test_io_uring_writev_fsync_readv";1993 const path = "test_io_uring_writev_fsync_readv";
1989 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });1994 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
1990 defer file.close();1995 defer file.close(io);
1991 const fd = file.handle;1996 const fd = file.handle;
19921997
1993 const buffer_write = [_]u8{42} ** 128;1998 const buffer_write = [_]u8{42} ** 128;
...@@ -2045,6 +2050,8 @@ test "writev/fsync/readv" {...@@ -2045,6 +2050,8 @@ test "writev/fsync/readv" {
2045test "write/read" {2050test "write/read" {
2046 if (!is_linux) return error.SkipZigTest;2051 if (!is_linux) return error.SkipZigTest;
20472052
2053 const io = testing.io;
2054
2048 var ring = IoUring.init(2, 0) catch |err| switch (err) {2055 var ring = IoUring.init(2, 0) catch |err| switch (err) {
2049 error.SystemOutdated => return error.SkipZigTest,2056 error.SystemOutdated => return error.SkipZigTest,
2050 error.PermissionDenied => return error.SkipZigTest,2057 error.PermissionDenied => return error.SkipZigTest,
...@@ -2056,7 +2063,7 @@ test "write/read" {...@@ -2056,7 +2063,7 @@ test "write/read" {
2056 defer tmp.cleanup();2063 defer tmp.cleanup();
2057 const path = "test_io_uring_write_read";2064 const path = "test_io_uring_write_read";
2058 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });2065 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
2059 defer file.close();2066 defer file.close(io);
2060 const fd = file.handle;2067 const fd = file.handle;
20612068
2062 const buffer_write = [_]u8{97} ** 20;2069 const buffer_write = [_]u8{97} ** 20;
...@@ -2092,6 +2099,8 @@ test "write/read" {...@@ -2092,6 +2099,8 @@ test "write/read" {
2092test "splice/read" {2099test "splice/read" {
2093 if (!is_linux) return error.SkipZigTest;2100 if (!is_linux) return error.SkipZigTest;
20942101
2102 const io = testing.io;
2103
2095 var ring = IoUring.init(4, 0) catch |err| switch (err) {2104 var ring = IoUring.init(4, 0) catch |err| switch (err) {
2096 error.SystemOutdated => return error.SkipZigTest,2105 error.SystemOutdated => return error.SkipZigTest,
2097 error.PermissionDenied => return error.SkipZigTest,2106 error.PermissionDenied => return error.SkipZigTest,
...@@ -2102,12 +2111,12 @@ test "splice/read" {...@@ -2102,12 +2111,12 @@ test "splice/read" {
2102 var tmp = std.testing.tmpDir(.{});2111 var tmp = std.testing.tmpDir(.{});
2103 const path_src = "test_io_uring_splice_src";2112 const path_src = "test_io_uring_splice_src";
2104 const file_src = try tmp.dir.createFile(path_src, .{ .read = true, .truncate = true });2113 const file_src = try tmp.dir.createFile(path_src, .{ .read = true, .truncate = true });
2105 defer file_src.close();2114 defer file_src.close(io);
2106 const fd_src = file_src.handle;2115 const fd_src = file_src.handle;
21072116
2108 const path_dst = "test_io_uring_splice_dst";2117 const path_dst = "test_io_uring_splice_dst";
2109 const file_dst = try tmp.dir.createFile(path_dst, .{ .read = true, .truncate = true });2118 const file_dst = try tmp.dir.createFile(path_dst, .{ .read = true, .truncate = true });
2110 defer file_dst.close();2119 defer file_dst.close(io);
2111 const fd_dst = file_dst.handle;2120 const fd_dst = file_dst.handle;
21122121
2113 const buffer_write = [_]u8{97} ** 20;2122 const buffer_write = [_]u8{97} ** 20;
...@@ -2163,6 +2172,8 @@ test "splice/read" {...@@ -2163,6 +2172,8 @@ test "splice/read" {
2163test "write_fixed/read_fixed" {2172test "write_fixed/read_fixed" {
2164 if (!is_linux) return error.SkipZigTest;2173 if (!is_linux) return error.SkipZigTest;
21652174
2175 const io = testing.io;
2176
2166 var ring = IoUring.init(2, 0) catch |err| switch (err) {2177 var ring = IoUring.init(2, 0) catch |err| switch (err) {
2167 error.SystemOutdated => return error.SkipZigTest,2178 error.SystemOutdated => return error.SkipZigTest,
2168 error.PermissionDenied => return error.SkipZigTest,2179 error.PermissionDenied => return error.SkipZigTest,
...@@ -2175,7 +2186,7 @@ test "write_fixed/read_fixed" {...@@ -2175,7 +2186,7 @@ test "write_fixed/read_fixed" {
21752186
2176 const path = "test_io_uring_write_read_fixed";2187 const path = "test_io_uring_write_read_fixed";
2177 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });2188 const file = try tmp.dir.createFile(path, .{ .read = true, .truncate = true });
2178 defer file.close();2189 defer file.close(io);
2179 const fd = file.handle;2190 const fd = file.handle;
21802191
2181 var raw_buffers: [2][11]u8 = undefined;2192 var raw_buffers: [2][11]u8 = undefined;
...@@ -2282,6 +2293,8 @@ test "openat" {...@@ -2282,6 +2293,8 @@ test "openat" {
2282test "close" {2293test "close" {
2283 if (!is_linux) return error.SkipZigTest;2294 if (!is_linux) return error.SkipZigTest;
22842295
2296 const io = testing.io;
2297
2285 var ring = IoUring.init(1, 0) catch |err| switch (err) {2298 var ring = IoUring.init(1, 0) catch |err| switch (err) {
2286 error.SystemOutdated => return error.SkipZigTest,2299 error.SystemOutdated => return error.SkipZigTest,
2287 error.PermissionDenied => return error.SkipZigTest,2300 error.PermissionDenied => return error.SkipZigTest,
...@@ -2294,7 +2307,7 @@ test "close" {...@@ -2294,7 +2307,7 @@ test "close" {
22942307
2295 const path = "test_io_uring_close";2308 const path = "test_io_uring_close";
2296 const file = try tmp.dir.createFile(path, .{});2309 const file = try tmp.dir.createFile(path, .{});
2297 errdefer file.close();2310 errdefer file.close(io);
22982311
2299 const sqe_close = try ring.close(0x44444444, file.handle);2312 const sqe_close = try ring.close(0x44444444, file.handle);
2300 try testing.expectEqual(linux.IORING_OP.CLOSE, sqe_close.opcode);2313 try testing.expectEqual(linux.IORING_OP.CLOSE, sqe_close.opcode);
...@@ -2313,6 +2326,8 @@ test "close" {...@@ -2313,6 +2326,8 @@ test "close" {
2313test "accept/connect/send/recv" {2326test "accept/connect/send/recv" {
2314 if (!is_linux) return error.SkipZigTest;2327 if (!is_linux) return error.SkipZigTest;
23152328
2329 const io = testing.io;
2330
2316 var ring = IoUring.init(16, 0) catch |err| switch (err) {2331 var ring = IoUring.init(16, 0) catch |err| switch (err) {
2317 error.SystemOutdated => return error.SkipZigTest,2332 error.SystemOutdated => return error.SkipZigTest,
2318 error.PermissionDenied => return error.SkipZigTest,2333 error.PermissionDenied => return error.SkipZigTest,
...@@ -2321,7 +2336,7 @@ test "accept/connect/send/recv" {...@@ -2321,7 +2336,7 @@ test "accept/connect/send/recv" {
2321 defer ring.deinit();2336 defer ring.deinit();
23222337
2323 const socket_test_harness = try createSocketTestHarness(&ring);2338 const socket_test_harness = try createSocketTestHarness(&ring);
2324 defer socket_test_harness.close();2339 defer socket_test_harness.close(io);
23252340
2326 const buffer_send = [_]u8{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };2341 const buffer_send = [_]u8{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
2327 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };2342 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
...@@ -2573,6 +2588,8 @@ test "timeout_remove" {...@@ -2573,6 +2588,8 @@ test "timeout_remove" {
2573test "accept/connect/recv/link_timeout" {2588test "accept/connect/recv/link_timeout" {
2574 if (!is_linux) return error.SkipZigTest;2589 if (!is_linux) return error.SkipZigTest;
25752590
2591 const io = testing.io;
2592
2576 var ring = IoUring.init(16, 0) catch |err| switch (err) {2593 var ring = IoUring.init(16, 0) catch |err| switch (err) {
2577 error.SystemOutdated => return error.SkipZigTest,2594 error.SystemOutdated => return error.SkipZigTest,
2578 error.PermissionDenied => return error.SkipZigTest,2595 error.PermissionDenied => return error.SkipZigTest,
...@@ -2581,7 +2598,7 @@ test "accept/connect/recv/link_timeout" {...@@ -2581,7 +2598,7 @@ test "accept/connect/recv/link_timeout" {
2581 defer ring.deinit();2598 defer ring.deinit();
25822599
2583 const socket_test_harness = try createSocketTestHarness(&ring);2600 const socket_test_harness = try createSocketTestHarness(&ring);
2584 defer socket_test_harness.close();2601 defer socket_test_harness.close(io);
25852602
2586 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };2603 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
25872604
...@@ -2622,6 +2639,8 @@ test "accept/connect/recv/link_timeout" {...@@ -2622,6 +2639,8 @@ test "accept/connect/recv/link_timeout" {
2622test "fallocate" {2639test "fallocate" {
2623 if (!is_linux) return error.SkipZigTest;2640 if (!is_linux) return error.SkipZigTest;
26242641
2642 const io = testing.io;
2643
2625 var ring = IoUring.init(1, 0) catch |err| switch (err) {2644 var ring = IoUring.init(1, 0) catch |err| switch (err) {
2626 error.SystemOutdated => return error.SkipZigTest,2645 error.SystemOutdated => return error.SkipZigTest,
2627 error.PermissionDenied => return error.SkipZigTest,2646 error.PermissionDenied => return error.SkipZigTest,
...@@ -2634,7 +2653,7 @@ test "fallocate" {...@@ -2634,7 +2653,7 @@ test "fallocate" {
26342653
2635 const path = "test_io_uring_fallocate";2654 const path = "test_io_uring_fallocate";
2636 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });2655 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
2637 defer file.close();2656 defer file.close(io);
26382657
2639 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);2658 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);
26402659
...@@ -2668,6 +2687,8 @@ test "fallocate" {...@@ -2668,6 +2687,8 @@ test "fallocate" {
2668test "statx" {2687test "statx" {
2669 if (!is_linux) return error.SkipZigTest;2688 if (!is_linux) return error.SkipZigTest;
26702689
2690 const io = testing.io;
2691
2671 var ring = IoUring.init(1, 0) catch |err| switch (err) {2692 var ring = IoUring.init(1, 0) catch |err| switch (err) {
2672 error.SystemOutdated => return error.SkipZigTest,2693 error.SystemOutdated => return error.SkipZigTest,
2673 error.PermissionDenied => return error.SkipZigTest,2694 error.PermissionDenied => return error.SkipZigTest,
...@@ -2679,7 +2700,7 @@ test "statx" {...@@ -2679,7 +2700,7 @@ test "statx" {
2679 defer tmp.cleanup();2700 defer tmp.cleanup();
2680 const path = "test_io_uring_statx";2701 const path = "test_io_uring_statx";
2681 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });2702 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
2682 defer file.close();2703 defer file.close(io);
26832704
2684 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);2705 try testing.expectEqual(@as(u64, 0), (try file.stat()).size);
26852706
...@@ -2725,6 +2746,8 @@ test "statx" {...@@ -2725,6 +2746,8 @@ test "statx" {
2725test "accept/connect/recv/cancel" {2746test "accept/connect/recv/cancel" {
2726 if (!is_linux) return error.SkipZigTest;2747 if (!is_linux) return error.SkipZigTest;
27272748
2749 const io = testing.io;
2750
2728 var ring = IoUring.init(16, 0) catch |err| switch (err) {2751 var ring = IoUring.init(16, 0) catch |err| switch (err) {
2729 error.SystemOutdated => return error.SkipZigTest,2752 error.SystemOutdated => return error.SkipZigTest,
2730 error.PermissionDenied => return error.SkipZigTest,2753 error.PermissionDenied => return error.SkipZigTest,
...@@ -2733,7 +2756,7 @@ test "accept/connect/recv/cancel" {...@@ -2733,7 +2756,7 @@ test "accept/connect/recv/cancel" {
2733 defer ring.deinit();2756 defer ring.deinit();
27342757
2735 const socket_test_harness = try createSocketTestHarness(&ring);2758 const socket_test_harness = try createSocketTestHarness(&ring);
2736 defer socket_test_harness.close();2759 defer socket_test_harness.close(io);
27372760
2738 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };2761 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
27392762
...@@ -2929,6 +2952,8 @@ test "shutdown" {...@@ -2929,6 +2952,8 @@ test "shutdown" {
2929test "renameat" {2952test "renameat" {
2930 if (!is_linux) return error.SkipZigTest;2953 if (!is_linux) return error.SkipZigTest;
29312954
2955 const io = testing.io;
2956
2932 var ring = IoUring.init(1, 0) catch |err| switch (err) {2957 var ring = IoUring.init(1, 0) catch |err| switch (err) {
2933 error.SystemOutdated => return error.SkipZigTest,2958 error.SystemOutdated => return error.SkipZigTest,
2934 error.PermissionDenied => return error.SkipZigTest,2959 error.PermissionDenied => return error.SkipZigTest,
...@@ -2945,7 +2970,7 @@ test "renameat" {...@@ -2945,7 +2970,7 @@ test "renameat" {
2945 // Write old file with data2970 // Write old file with data
29462971
2947 const old_file = try tmp.dir.createFile(old_path, .{ .truncate = true, .mode = 0o666 });2972 const old_file = try tmp.dir.createFile(old_path, .{ .truncate = true, .mode = 0o666 });
2948 defer old_file.close();2973 defer old_file.close(io);
2949 try old_file.writeAll("hello");2974 try old_file.writeAll("hello");
29502975
2951 // Submit renameat2976 // Submit renameat
...@@ -2987,6 +3012,8 @@ test "renameat" {...@@ -2987,6 +3012,8 @@ test "renameat" {
2987test "unlinkat" {3012test "unlinkat" {
2988 if (!is_linux) return error.SkipZigTest;3013 if (!is_linux) return error.SkipZigTest;
29893014
3015 const io = testing.io;
3016
2990 var ring = IoUring.init(1, 0) catch |err| switch (err) {3017 var ring = IoUring.init(1, 0) catch |err| switch (err) {
2991 error.SystemOutdated => return error.SkipZigTest,3018 error.SystemOutdated => return error.SkipZigTest,
2992 error.PermissionDenied => return error.SkipZigTest,3019 error.PermissionDenied => return error.SkipZigTest,
...@@ -3002,7 +3029,7 @@ test "unlinkat" {...@@ -3002,7 +3029,7 @@ test "unlinkat" {
3002 // Write old file with data3029 // Write old file with data
30033030
3004 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });3031 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
3005 defer file.close();3032 defer file.close(io);
30063033
3007 // Submit unlinkat3034 // Submit unlinkat
30083035
...@@ -3083,6 +3110,8 @@ test "mkdirat" {...@@ -3083,6 +3110,8 @@ test "mkdirat" {
3083test "symlinkat" {3110test "symlinkat" {
3084 if (!is_linux) return error.SkipZigTest;3111 if (!is_linux) return error.SkipZigTest;
30853112
3113 const io = testing.io;
3114
3086 var ring = IoUring.init(1, 0) catch |err| switch (err) {3115 var ring = IoUring.init(1, 0) catch |err| switch (err) {
3087 error.SystemOutdated => return error.SkipZigTest,3116 error.SystemOutdated => return error.SkipZigTest,
3088 error.PermissionDenied => return error.SkipZigTest,3117 error.PermissionDenied => return error.SkipZigTest,
...@@ -3097,7 +3126,7 @@ test "symlinkat" {...@@ -3097,7 +3126,7 @@ test "symlinkat" {
3097 const link_path = "test_io_uring_symlinkat_link";3126 const link_path = "test_io_uring_symlinkat_link";
30983127
3099 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });3128 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
3100 defer file.close();3129 defer file.close(io);
31013130
3102 // Submit symlinkat3131 // Submit symlinkat
31033132
...@@ -3131,6 +3160,8 @@ test "symlinkat" {...@@ -3131,6 +3160,8 @@ test "symlinkat" {
3131test "linkat" {3160test "linkat" {
3132 if (!is_linux) return error.SkipZigTest;3161 if (!is_linux) return error.SkipZigTest;
31333162
3163 const io = testing.io;
3164
3134 var ring = IoUring.init(1, 0) catch |err| switch (err) {3165 var ring = IoUring.init(1, 0) catch |err| switch (err) {
3135 error.SystemOutdated => return error.SkipZigTest,3166 error.SystemOutdated => return error.SkipZigTest,
3136 error.PermissionDenied => return error.SkipZigTest,3167 error.PermissionDenied => return error.SkipZigTest,
...@@ -3147,7 +3178,7 @@ test "linkat" {...@@ -3147,7 +3178,7 @@ test "linkat" {
3147 // Write file with data3178 // Write file with data
31483179
3149 const first_file = try tmp.dir.createFile(first_path, .{ .truncate = true, .mode = 0o666 });3180 const first_file = try tmp.dir.createFile(first_path, .{ .truncate = true, .mode = 0o666 });
3150 defer first_file.close();3181 defer first_file.close(io);
3151 try first_file.writeAll("hello");3182 try first_file.writeAll("hello");
31523183
3153 // Submit linkat3184 // Submit linkat
...@@ -3407,6 +3438,8 @@ test "remove_buffers" {...@@ -3407,6 +3438,8 @@ test "remove_buffers" {
3407test "provide_buffers: accept/connect/send/recv" {3438test "provide_buffers: accept/connect/send/recv" {
3408 if (!is_linux) return error.SkipZigTest;3439 if (!is_linux) return error.SkipZigTest;
34093440
3441 const io = testing.io;
3442
3410 var ring = IoUring.init(16, 0) catch |err| switch (err) {3443 var ring = IoUring.init(16, 0) catch |err| switch (err) {
3411 error.SystemOutdated => return error.SkipZigTest,3444 error.SystemOutdated => return error.SkipZigTest,
3412 error.PermissionDenied => return error.SkipZigTest,3445 error.PermissionDenied => return error.SkipZigTest,
...@@ -3443,7 +3476,7 @@ test "provide_buffers: accept/connect/send/recv" {...@@ -3443,7 +3476,7 @@ test "provide_buffers: accept/connect/send/recv" {
3443 }3476 }
34443477
3445 const socket_test_harness = try createSocketTestHarness(&ring);3478 const socket_test_harness = try createSocketTestHarness(&ring);
3446 defer socket_test_harness.close();3479 defer socket_test_harness.close(io);
34473480
3448 // Do 4 send on the socket3481 // Do 4 send on the socket
34493482
...@@ -3696,6 +3729,8 @@ test "accept multishot" {...@@ -3696,6 +3729,8 @@ test "accept multishot" {
3696test "accept/connect/send_zc/recv" {3729test "accept/connect/send_zc/recv" {
3697 try skipKernelLessThan(.{ .major = 6, .minor = 0, .patch = 0 });3730 try skipKernelLessThan(.{ .major = 6, .minor = 0, .patch = 0 });
36983731
3732 const io = testing.io;
3733
3699 var ring = IoUring.init(16, 0) catch |err| switch (err) {3734 var ring = IoUring.init(16, 0) catch |err| switch (err) {
3700 error.SystemOutdated => return error.SkipZigTest,3735 error.SystemOutdated => return error.SkipZigTest,
3701 error.PermissionDenied => return error.SkipZigTest,3736 error.PermissionDenied => return error.SkipZigTest,
...@@ -3704,7 +3739,7 @@ test "accept/connect/send_zc/recv" {...@@ -3704,7 +3739,7 @@ test "accept/connect/send_zc/recv" {
3704 defer ring.deinit();3739 defer ring.deinit();
37053740
3706 const socket_test_harness = try createSocketTestHarness(&ring);3741 const socket_test_harness = try createSocketTestHarness(&ring);
3707 defer socket_test_harness.close();3742 defer socket_test_harness.close(io);
37083743
3709 const buffer_send = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };3744 const buffer_send = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };
3710 var buffer_recv = [_]u8{0} ** 10;3745 var buffer_recv = [_]u8{0} ** 10;
...@@ -4105,6 +4140,8 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {...@@ -4105,6 +4140,8 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
4105test BufferGroup {4140test BufferGroup {
4106 if (!is_linux) return error.SkipZigTest;4141 if (!is_linux) return error.SkipZigTest;
41074142
4143 const io = testing.io;
4144
4108 // Init IoUring4145 // Init IoUring
4109 var ring = IoUring.init(16, 0) catch |err| switch (err) {4146 var ring = IoUring.init(16, 0) catch |err| switch (err) {
4110 error.SystemOutdated => return error.SkipZigTest,4147 error.SystemOutdated => return error.SkipZigTest,
...@@ -4132,7 +4169,7 @@ test BufferGroup {...@@ -4132,7 +4169,7 @@ test BufferGroup {
41324169
4133 // Create client/server fds4170 // Create client/server fds
4134 const fds = try createSocketTestHarness(&ring);4171 const fds = try createSocketTestHarness(&ring);
4135 defer fds.close();4172 defer fds.close(io);
4136 const data = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };4173 const data = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };
41374174
4138 // Client sends data4175 // Client sends data
...@@ -4170,6 +4207,8 @@ test BufferGroup {...@@ -4170,6 +4207,8 @@ test BufferGroup {
4170test "ring mapped buffers recv" {4207test "ring mapped buffers recv" {
4171 if (!is_linux) return error.SkipZigTest;4208 if (!is_linux) return error.SkipZigTest;
41724209
4210 const io = testing.io;
4211
4173 var ring = IoUring.init(16, 0) catch |err| switch (err) {4212 var ring = IoUring.init(16, 0) catch |err| switch (err) {
4174 error.SystemOutdated => return error.SkipZigTest,4213 error.SystemOutdated => return error.SkipZigTest,
4175 error.PermissionDenied => return error.SkipZigTest,4214 error.PermissionDenied => return error.SkipZigTest,
...@@ -4196,7 +4235,7 @@ test "ring mapped buffers recv" {...@@ -4196,7 +4235,7 @@ test "ring mapped buffers recv" {
41964235
4197 // create client/server fds4236 // create client/server fds
4198 const fds = try createSocketTestHarness(&ring);4237 const fds = try createSocketTestHarness(&ring);
4199 defer fds.close();4238 defer fds.close(io);
42004239
4201 // for random user_data in sqe/cqe4240 // for random user_data in sqe/cqe
4202 var Rnd = std.Random.DefaultPrng.init(std.testing.random_seed);4241 var Rnd = std.Random.DefaultPrng.init(std.testing.random_seed);
...@@ -4259,6 +4298,8 @@ test "ring mapped buffers recv" {...@@ -4259,6 +4298,8 @@ test "ring mapped buffers recv" {
4259test "ring mapped buffers multishot recv" {4298test "ring mapped buffers multishot recv" {
4260 if (!is_linux) return error.SkipZigTest;4299 if (!is_linux) return error.SkipZigTest;
42614300
4301 const io = testing.io;
4302
4262 var ring = IoUring.init(16, 0) catch |err| switch (err) {4303 var ring = IoUring.init(16, 0) catch |err| switch (err) {
4263 error.SystemOutdated => return error.SkipZigTest,4304 error.SystemOutdated => return error.SkipZigTest,
4264 error.PermissionDenied => return error.SkipZigTest,4305 error.PermissionDenied => return error.SkipZigTest,
...@@ -4285,7 +4326,7 @@ test "ring mapped buffers multishot recv" {...@@ -4285,7 +4326,7 @@ test "ring mapped buffers multishot recv" {
42854326
4286 // create client/server fds4327 // create client/server fds
4287 const fds = try createSocketTestHarness(&ring);4328 const fds = try createSocketTestHarness(&ring);
4288 defer fds.close();4329 defer fds.close(io);
42894330
4290 // for random user_data in sqe/cqe4331 // for random user_data in sqe/cqe
4291 var Rnd = std.Random.DefaultPrng.init(std.testing.random_seed);4332 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;...@@ -12,12 +12,14 @@ const fs = std.fs;
12test "fallocate" {12test "fallocate" {
13 if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/3022013 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
15 var tmp = std.testing.tmpDir(.{});17 var tmp = std.testing.tmpDir(.{});
16 defer tmp.cleanup();18 defer tmp.cleanup();
1719
18 const path = "test_fallocate";20 const path = "test_fallocate";
19 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });21 const file = try tmp.dir.createFile(path, .{ .truncate = true, .mode = 0o666 });
20 defer file.close();22 defer file.close(io);
2123
22 try expect((try file.stat()).size == 0);24 try expect((try file.stat()).size == 0);
2325
...@@ -77,12 +79,14 @@ test "timer" {...@@ -77,12 +79,14 @@ test "timer" {
77}79}
7880
79test "statx" {81test "statx" {
82 const io = std.testing.io;
83
80 var tmp = std.testing.tmpDir(.{});84 var tmp = std.testing.tmpDir(.{});
81 defer tmp.cleanup();85 defer tmp.cleanup();
8286
83 const tmp_file_name = "just_a_temporary_file.txt";87 const tmp_file_name = "just_a_temporary_file.txt";
84 var file = try tmp.dir.createFile(tmp_file_name, .{});88 var file = try tmp.dir.createFile(tmp_file_name, .{});
85 defer file.close();89 defer file.close(io);
8690
87 var buf: linux.Statx = undefined;91 var buf: linux.Statx = undefined;
88 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, .BASIC_STATS, &buf))) {92 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, .BASIC_STATS, &buf))) {
...@@ -111,12 +115,14 @@ test "user and group ids" {...@@ -111,12 +115,14 @@ test "user and group ids" {
111}115}
112116
113test "fadvise" {117test "fadvise" {
118 const io = std.testing.io;
119
114 var tmp = std.testing.tmpDir(.{});120 var tmp = std.testing.tmpDir(.{});
115 defer tmp.cleanup();121 defer tmp.cleanup();
116122
117 const tmp_file_name = "temp_posix_fadvise.txt";123 const tmp_file_name = "temp_posix_fadvise.txt";
118 var file = try tmp.dir.createFile(tmp_file_name, .{});124 var file = try tmp.dir.createFile(tmp_file_name, .{});
119 defer file.close();125 defer file.close(io);
120126
121 var buf: [2048]u8 = undefined;127 var buf: [2048]u8 = undefined;
122 try file.writeAll(&buf);128 try file.writeAll(&buf);
lib/std/posix/test.zig+38-16
...@@ -148,6 +148,8 @@ test "linkat with different directories" {...@@ -148,6 +148,8 @@ test "linkat with different directories" {
148 else => return error.SkipZigTest,148 else => return error.SkipZigTest,
149 }149 }
150150
151 const io = testing.io;
152
151 var tmp = tmpDir(.{});153 var tmp = tmpDir(.{});
152 defer tmp.cleanup();154 defer tmp.cleanup();
153155
...@@ -163,10 +165,10 @@ test "linkat with different directories" {...@@ -163,10 +165,10 @@ test "linkat with different directories" {
163 try posix.linkat(tmp.dir.fd, target_name, subdir.fd, link_name, 0);165 try posix.linkat(tmp.dir.fd, target_name, subdir.fd, link_name, 0);
164166
165 const efd = try tmp.dir.openFile(target_name, .{});167 const efd = try tmp.dir.openFile(target_name, .{});
166 defer efd.close();168 defer efd.close(io);
167169
168 const nfd = try subdir.openFile(link_name, .{});170 const nfd = try subdir.openFile(link_name, .{});
169 defer nfd.close();171 defer nfd.close(io);
170172
171 {173 {
172 const eino, _ = try getLinkInfo(efd.handle);174 const eino, _ = try getLinkInfo(efd.handle);
...@@ -381,6 +383,8 @@ test "mmap" {...@@ -381,6 +383,8 @@ test "mmap" {
381 if (native_os == .windows or native_os == .wasi)383 if (native_os == .windows or native_os == .wasi)
382 return error.SkipZigTest;384 return error.SkipZigTest;
383385
386 const io = testing.io;
387
384 var tmp = tmpDir(.{});388 var tmp = tmpDir(.{});
385 defer tmp.cleanup();389 defer tmp.cleanup();
386390
...@@ -413,7 +417,7 @@ test "mmap" {...@@ -413,7 +417,7 @@ test "mmap" {
413 // Create a file used for testing mmap() calls with a file descriptor417 // Create a file used for testing mmap() calls with a file descriptor
414 {418 {
415 const file = try tmp.dir.createFile(test_out_file, .{});419 const file = try tmp.dir.createFile(test_out_file, .{});
416 defer file.close();420 defer file.close(io);
417421
418 var stream = file.writer(&.{});422 var stream = file.writer(&.{});
419423
...@@ -426,7 +430,7 @@ test "mmap" {...@@ -426,7 +430,7 @@ test "mmap" {
426 // Map the whole file430 // Map the whole file
427 {431 {
428 const file = try tmp.dir.openFile(test_out_file, .{});432 const file = try tmp.dir.openFile(test_out_file, .{});
429 defer file.close();433 defer file.close(io);
430434
431 const data = try posix.mmap(435 const data = try posix.mmap(
432 null,436 null,
...@@ -451,7 +455,7 @@ test "mmap" {...@@ -451,7 +455,7 @@ test "mmap" {
451 // Map the upper half of the file455 // Map the upper half of the file
452 {456 {
453 const file = try tmp.dir.openFile(test_out_file, .{});457 const file = try tmp.dir.openFile(test_out_file, .{});
454 defer file.close();458 defer file.close(io);
455459
456 const data = try posix.mmap(460 const data = try posix.mmap(
457 null,461 null,
...@@ -476,13 +480,15 @@ test "fcntl" {...@@ -476,13 +480,15 @@ test "fcntl" {
476 if (native_os == .windows or native_os == .wasi)480 if (native_os == .windows or native_os == .wasi)
477 return error.SkipZigTest;481 return error.SkipZigTest;
478482
483 const io = testing.io;
484
479 var tmp = tmpDir(.{});485 var tmp = tmpDir(.{});
480 defer tmp.cleanup();486 defer tmp.cleanup();
481487
482 const test_out_file = "os_tmp_test";488 const test_out_file = "os_tmp_test";
483489
484 const file = try tmp.dir.createFile(test_out_file, .{});490 const file = try tmp.dir.createFile(test_out_file, .{});
485 defer file.close();491 defer file.close(io);
486492
487 // Note: The test assumes createFile opens the file with CLOEXEC493 // Note: The test assumes createFile opens the file with CLOEXEC
488 {494 {
...@@ -526,12 +532,14 @@ test "fsync" {...@@ -526,12 +532,14 @@ test "fsync" {
526 else => return error.SkipZigTest,532 else => return error.SkipZigTest,
527 }533 }
528534
535 const io = testing.io;
536
529 var tmp = tmpDir(.{});537 var tmp = tmpDir(.{});
530 defer tmp.cleanup();538 defer tmp.cleanup();
531539
532 const test_out_file = "os_tmp_test";540 const test_out_file = "os_tmp_test";
533 const file = try tmp.dir.createFile(test_out_file, .{});541 const file = try tmp.dir.createFile(test_out_file, .{});
534 defer file.close();542 defer file.close(io);
535543
536 try posix.fsync(file.handle);544 try posix.fsync(file.handle);
537 try posix.fdatasync(file.handle);545 try posix.fdatasync(file.handle);
...@@ -646,22 +654,24 @@ test "dup & dup2" {...@@ -646,22 +654,24 @@ test "dup & dup2" {
646 else => return error.SkipZigTest,654 else => return error.SkipZigTest,
647 }655 }
648656
657 const io = testing.io;
658
649 var tmp = tmpDir(.{});659 var tmp = tmpDir(.{});
650 defer tmp.cleanup();660 defer tmp.cleanup();
651661
652 {662 {
653 var file = try tmp.dir.createFile("os_dup_test", .{});663 var file = try tmp.dir.createFile("os_dup_test", .{});
654 defer file.close();664 defer file.close(io);
655665
656 var duped = std.fs.File{ .handle = try posix.dup(file.handle) };666 var duped = std.fs.File{ .handle = try posix.dup(file.handle) };
657 defer duped.close();667 defer duped.close(io);
658 try duped.writeAll("dup");668 try duped.writeAll("dup");
659669
660 // Tests aren't run in parallel so using the next fd shouldn't be an issue.670 // Tests aren't run in parallel so using the next fd shouldn't be an issue.
661 const new_fd = duped.handle + 1;671 const new_fd = duped.handle + 1;
662 try posix.dup2(file.handle, new_fd);672 try posix.dup2(file.handle, new_fd);
663 var dup2ed = std.fs.File{ .handle = new_fd };673 var dup2ed = std.fs.File{ .handle = new_fd };
664 defer dup2ed.close();674 defer dup2ed.close(io);
665 try dup2ed.writeAll("dup2");675 try dup2ed.writeAll("dup2");
666 }676 }
667677
...@@ -687,11 +697,13 @@ test "getppid" {...@@ -687,11 +697,13 @@ test "getppid" {
687test "writev longer than IOV_MAX" {697test "writev longer than IOV_MAX" {
688 if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;698 if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
689699
700 const io = testing.io;
701
690 var tmp = tmpDir(.{});702 var tmp = tmpDir(.{});
691 defer tmp.cleanup();703 defer tmp.cleanup();
692704
693 var file = try tmp.dir.createFile("pwritev", .{});705 var file = try tmp.dir.createFile("pwritev", .{});
694 defer file.close();706 defer file.close(io);
695707
696 const iovecs = [_]posix.iovec_const{.{ .base = "a", .len = 1 }} ** (posix.IOV_MAX + 1);708 const iovecs = [_]posix.iovec_const{.{ .base = "a", .len = 1 }} ** (posix.IOV_MAX + 1);
697 const amt = try file.writev(&iovecs);709 const amt = try file.writev(&iovecs);
...@@ -709,12 +721,14 @@ test "POSIX file locking with fcntl" {...@@ -709,12 +721,14 @@ test "POSIX file locking with fcntl" {
709 return error.SkipZigTest;721 return error.SkipZigTest;
710 }722 }
711723
724 const io = testing.io;
725
712 var tmp = tmpDir(.{});726 var tmp = tmpDir(.{});
713 defer tmp.cleanup();727 defer tmp.cleanup();
714728
715 // Create a temporary lock file729 // Create a temporary lock file
716 var file = try tmp.dir.createFile("lock", .{ .read = true });730 var file = try tmp.dir.createFile("lock", .{ .read = true });
717 defer file.close();731 defer file.close(io);
718 try file.setEndPos(2);732 try file.setEndPos(2);
719 const fd = file.handle;733 const fd = file.handle;
720734
...@@ -905,21 +919,25 @@ test "timerfd" {...@@ -905,21 +919,25 @@ test "timerfd" {
905}919}
906920
907test "isatty" {921test "isatty" {
922 const io = testing.io;
923
908 var tmp = tmpDir(.{});924 var tmp = tmpDir(.{});
909 defer tmp.cleanup();925 defer tmp.cleanup();
910926
911 var file = try tmp.dir.createFile("foo", .{});927 var file = try tmp.dir.createFile("foo", .{});
912 defer file.close();928 defer file.close(io);
913929
914 try expectEqual(posix.isatty(file.handle), false);930 try expectEqual(posix.isatty(file.handle), false);
915}931}
916932
917test "pread with empty buffer" {933test "pread with empty buffer" {
934 const io = testing.io;
935
918 var tmp = tmpDir(.{});936 var tmp = tmpDir(.{});
919 defer tmp.cleanup();937 defer tmp.cleanup();
920938
921 var file = try tmp.dir.createFile("pread_empty", .{ .read = true });939 var file = try tmp.dir.createFile("pread_empty", .{ .read = true });
922 defer file.close();940 defer file.close(io);
923941
924 const bytes = try a.alloc(u8, 0);942 const bytes = try a.alloc(u8, 0);
925 defer a.free(bytes);943 defer a.free(bytes);
...@@ -929,11 +947,13 @@ test "pread with empty buffer" {...@@ -929,11 +947,13 @@ test "pread with empty buffer" {
929}947}
930948
931test "write with empty buffer" {949test "write with empty buffer" {
950 const io = testing.io;
951
932 var tmp = tmpDir(.{});952 var tmp = tmpDir(.{});
933 defer tmp.cleanup();953 defer tmp.cleanup();
934954
935 var file = try tmp.dir.createFile("write_empty", .{});955 var file = try tmp.dir.createFile("write_empty", .{});
936 defer file.close();956 defer file.close(io);
937957
938 const bytes = try a.alloc(u8, 0);958 const bytes = try a.alloc(u8, 0);
939 defer a.free(bytes);959 defer a.free(bytes);
...@@ -943,11 +963,13 @@ test "write with empty buffer" {...@@ -943,11 +963,13 @@ test "write with empty buffer" {
943}963}
944964
945test "pwrite with empty buffer" {965test "pwrite with empty buffer" {
966 const io = testing.io;
967
946 var tmp = tmpDir(.{});968 var tmp = tmpDir(.{});
947 defer tmp.cleanup();969 defer tmp.cleanup();
948970
949 var file = try tmp.dir.createFile("pwrite_empty", .{});971 var file = try tmp.dir.createFile("pwrite_empty", .{});
950 defer file.close();972 defer file.close(io);
951973
952 const bytes = try a.alloc(u8, 0);974 const bytes = try a.alloc(u8, 0);
953 defer a.free(bytes);975 defer a.free(bytes);
lib/std/process.zig+7-5
...@@ -1,12 +1,14 @@...@@ -1,12 +1,14 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");1const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("std.zig");
5const Io = std.Io;
3const fs = std.fs;6const fs = std.fs;
4const mem = std.mem;7const mem = std.mem;
5const math = std.math;8const math = std.math;
6const Allocator = mem.Allocator;9const Allocator = std.mem.Allocator;
7const assert = std.debug.assert;10const assert = std.debug.assert;
8const testing = std.testing;11const testing = std.testing;
9const native_os = builtin.os.tag;
10const posix = std.posix;12const posix = std.posix;
11const windows = std.os.windows;13const windows = std.os.windows;
12const unicode = std.unicode;14const unicode = std.unicode;
...@@ -1571,9 +1573,9 @@ pub fn getUserInfo(name: []const u8) !UserInfo {...@@ -1571,9 +1573,9 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
15711573
1572/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else1574/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
1573/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.1575/// 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 {
1575 const file = try std.fs.openFileAbsolute("/etc/passwd", .{});1577 const file = try std.fs.openFileAbsolute("/etc/passwd", .{});
1576 defer file.close();1578 defer file.close(io);
1577 var buffer: [4096]u8 = undefined;1579 var buffer: [4096]u8 = undefined;
1578 var file_reader = file.reader(&buffer);1580 var file_reader = file.reader(&buffer);
1579 return posixGetUserInfoPasswdStream(name, &file_reader.interface) catch |err| switch (err) {1581 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");...@@ -4,6 +4,7 @@ const builtin = @import("builtin");
4const native_os = builtin.os.tag;4const native_os = builtin.os.tag;
55
6const std = @import("../std.zig");6const std = @import("../std.zig");
7const Io = std.Io;
7const unicode = std.unicode;8const unicode = std.unicode;
8const fs = std.fs;9const fs = std.fs;
9const process = std.process;10const process = std.process;
...@@ -277,17 +278,17 @@ pub fn spawnAndWait(self: *ChildProcess) SpawnError!Term {...@@ -277,17 +278,17 @@ pub fn spawnAndWait(self: *ChildProcess) SpawnError!Term {
277}278}
278279
279/// Forcibly terminates child process and then cleans up all resources.280/// Forcibly terminates child process and then cleans up all resources.
280pub fn kill(self: *ChildProcess) !Term {281pub fn kill(self: *ChildProcess, io: Io) !Term {
281 if (native_os == .windows) {282 if (native_os == .windows) {
282 return self.killWindows(1);283 return self.killWindows(io, 1);
283 } else {284 } else {
284 return self.killPosix();285 return self.killPosix(io);
285 }286 }
286}287}
287288
288pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {289pub fn killWindows(self: *ChildProcess, io: Io, exit_code: windows.UINT) !Term {
289 if (self.term) |term| {290 if (self.term) |term| {
290 self.cleanupStreams();291 self.cleanupStreams(io);
291 return term;292 return term;
292 }293 }
293294
...@@ -303,20 +304,20 @@ pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {...@@ -303,20 +304,20 @@ pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
303 },304 },
304 else => return err,305 else => return err,
305 };306 };
306 try self.waitUnwrappedWindows();307 try self.waitUnwrappedWindows(io);
307 return self.term.?;308 return self.term.?;
308}309}
309310
310pub fn killPosix(self: *ChildProcess) !Term {311pub fn killPosix(self: *ChildProcess, io: Io) !Term {
311 if (self.term) |term| {312 if (self.term) |term| {
312 self.cleanupStreams();313 self.cleanupStreams(io);
313 return term;314 return term;
314 }315 }
315 posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {316 posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {
316 error.ProcessNotFound => return error.AlreadyTerminated,317 error.ProcessNotFound => return error.AlreadyTerminated,
317 else => return err,318 else => return err,
318 };319 };
319 self.waitUnwrappedPosix();320 self.waitUnwrappedPosix(io);
320 return self.term.?;321 return self.term.?;
321}322}
322323
...@@ -354,15 +355,15 @@ pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {...@@ -354,15 +355,15 @@ pub fn waitForSpawn(self: *ChildProcess) SpawnError!void {
354}355}
355356
356/// Blocks until child process terminates and then cleans up all resources.357/// 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 {
358 try self.waitForSpawn(); // report spawn errors359 try self.waitForSpawn(); // report spawn errors
359 if (self.term) |term| {360 if (self.term) |term| {
360 self.cleanupStreams();361 self.cleanupStreams(io);
361 return term;362 return term;
362 }363 }
363 switch (native_os) {364 switch (native_os) {
364 .windows => try self.waitUnwrappedWindows(),365 .windows => try self.waitUnwrappedWindows(io),
365 else => self.waitUnwrappedPosix(),366 else => self.waitUnwrappedPosix(io),
366 }367 }
367 self.id = undefined;368 self.id = undefined;
368 return self.term.?;369 return self.term.?;
...@@ -474,7 +475,7 @@ pub fn run(args: struct {...@@ -474,7 +475,7 @@ pub fn run(args: struct {
474 };475 };
475}476}
476477
477fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {478fn waitUnwrappedWindows(self: *ChildProcess, io: Io) WaitError!void {
478 const result = windows.WaitForSingleObjectEx(self.id, windows.INFINITE, false);479 const result = windows.WaitForSingleObjectEx(self.id, windows.INFINITE, false);
479480
480 self.term = @as(SpawnError!Term, x: {481 self.term = @as(SpawnError!Term, x: {
...@@ -492,11 +493,11 @@ fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {...@@ -492,11 +493,11 @@ fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {
492493
493 posix.close(self.id);494 posix.close(self.id);
494 posix.close(self.thread_handle);495 posix.close(self.thread_handle);
495 self.cleanupStreams();496 self.cleanupStreams(io);
496 return result;497 return result;
497}498}
498499
499fn waitUnwrappedPosix(self: *ChildProcess) void {500fn waitUnwrappedPosix(self: *ChildProcess, io: Io) void {
500 const res: posix.WaitPidResult = res: {501 const res: posix.WaitPidResult = res: {
501 if (self.request_resource_usage_statistics) {502 if (self.request_resource_usage_statistics) {
502 switch (native_os) {503 switch (native_os) {
...@@ -527,7 +528,7 @@ fn waitUnwrappedPosix(self: *ChildProcess) void {...@@ -527,7 +528,7 @@ fn waitUnwrappedPosix(self: *ChildProcess) void {
527 break :res posix.waitpid(self.id, 0);528 break :res posix.waitpid(self.id, 0);
528 };529 };
529 const status = res.status;530 const status = res.status;
530 self.cleanupStreams();531 self.cleanupStreams(io);
531 self.handleWaitResult(status);532 self.handleWaitResult(status);
532}533}
533534
...@@ -535,17 +536,17 @@ fn handleWaitResult(self: *ChildProcess, status: u32) void {...@@ -535,17 +536,17 @@ fn handleWaitResult(self: *ChildProcess, status: u32) void {
535 self.term = statusToTerm(status);536 self.term = statusToTerm(status);
536}537}
537538
538fn cleanupStreams(self: *ChildProcess) void {539fn cleanupStreams(self: *ChildProcess, io: Io) void {
539 if (self.stdin) |*stdin| {540 if (self.stdin) |*stdin| {
540 stdin.close();541 stdin.close(io);
541 self.stdin = null;542 self.stdin = null;
542 }543 }
543 if (self.stdout) |*stdout| {544 if (self.stdout) |*stdout| {
544 stdout.close();545 stdout.close(io);
545 self.stdout = null;546 self.stdout = null;
546 }547 }
547 if (self.stderr) |*stderr| {548 if (self.stderr) |*stderr| {
548 stderr.close();549 stderr.close(io);
549 self.stderr = null;550 self.stderr = null;
550 }551 }
551}552}
lib/std/tar.zig+40-31
...@@ -16,6 +16,7 @@...@@ -16,6 +16,7 @@
16//! pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_1316//! pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
1717
18const std = @import("std");18const std = @import("std");
19const Io = std.Io;
19const assert = std.debug.assert;20const assert = std.debug.assert;
20const testing = std.testing;21const testing = std.testing;
2122
...@@ -302,7 +303,7 @@ pub const FileKind = enum {...@@ -302,7 +303,7 @@ pub const FileKind = enum {
302303
303/// Iterator over entries in the tar file represented by reader.304/// Iterator over entries in the tar file represented by reader.
304pub const Iterator = struct {305pub const Iterator = struct {
305 reader: *std.Io.Reader,306 reader: *Io.Reader,
306 diagnostics: ?*Diagnostics = null,307 diagnostics: ?*Diagnostics = null,
307308
308 // buffers for heeader and file attributes309 // buffers for heeader and file attributes
...@@ -328,7 +329,7 @@ pub const Iterator = struct {...@@ -328,7 +329,7 @@ pub const Iterator = struct {
328329
329 /// Iterates over files in tar archive.330 /// Iterates over files in tar archive.
330 /// `next` returns each file in tar archive.331 /// `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 {
332 return .{333 return .{
333 .reader = reader,334 .reader = reader,
334 .diagnostics = options.diagnostics,335 .diagnostics = options.diagnostics,
...@@ -473,7 +474,7 @@ pub const Iterator = struct {...@@ -473,7 +474,7 @@ pub const Iterator = struct {
473 return null;474 return null;
474 }475 }
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 {
477 try it.reader.streamExact64(w, file.size);478 try it.reader.streamExact64(w, file.size);
478 it.unread_file_bytes = 0;479 it.unread_file_bytes = 0;
479 }480 }
...@@ -499,14 +500,14 @@ const pax_max_size_attr_len = 64;...@@ -499,14 +500,14 @@ const pax_max_size_attr_len = 64;
499500
500pub const PaxIterator = struct {501pub const PaxIterator = struct {
501 size: usize, // cumulative size of all pax attributes502 size: usize, // cumulative size of all pax attributes
502 reader: *std.Io.Reader,503 reader: *Io.Reader,
503504
504 const Self = @This();505 const Self = @This();
505506
506 const Attribute = struct {507 const Attribute = struct {
507 kind: PaxAttributeKind,508 kind: PaxAttributeKind,
508 len: usize, // length of the attribute value509 len: usize, // length of the attribute value
509 reader: *std.Io.Reader, // reader positioned at value start510 reader: *Io.Reader, // reader positioned at value start
510511
511 // Copies pax attribute value into destination buffer.512 // Copies pax attribute value into destination buffer.
512 // Must be called with destination buffer of size at least Attribute.len.513 // Must be called with destination buffer of size at least Attribute.len.
...@@ -573,13 +574,13 @@ pub const PaxIterator = struct {...@@ -573,13 +574,13 @@ pub const PaxIterator = struct {
573 }574 }
574575
575 // Checks that each record ends with new line.576 // Checks that each record ends with new line.
576 fn validateAttributeEnding(reader: *std.Io.Reader) !void {577 fn validateAttributeEnding(reader: *Io.Reader) !void {
577 if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd;578 if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd;
578 }579 }
579};580};
580581
581/// Saves tar file content to the file systems.582/// 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 {
583 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;584 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
584 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;585 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
585 var file_contents_buffer: [1024]u8 = undefined;586 var file_contents_buffer: [1024]u8 = undefined;
...@@ -610,7 +611,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp...@@ -610,7 +611,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp
610 },611 },
611 .file => {612 .file => {
612 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {613 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
613 defer fs_file.close();614 defer fs_file.close(io);
614 var file_writer = fs_file.writer(&file_contents_buffer);615 var file_writer = fs_file.writer(&file_contents_buffer);
615 try it.streamRemaining(file, &file_writer.interface);616 try it.streamRemaining(file, &file_writer.interface);
616 try file_writer.interface.flush();617 try file_writer.interface.flush();
...@@ -637,7 +638,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp...@@ -637,7 +638,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOp
637 }638 }
638}639}
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 {
641 const fs_file = dir.createFile(file_name, .{ .exclusive = true, .mode = mode }) catch |err| {642 const fs_file = dir.createFile(file_name, .{ .exclusive = true, .mode = mode }) catch |err| {
642 if (err == error.FileNotFound) {643 if (err == error.FileNotFound) {
643 if (std.fs.path.dirname(file_name)) |dir_name| {644 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...@@ -651,7 +652,7 @@ fn createDirAndFile(dir: std.fs.Dir, file_name: []const u8, mode: std.fs.File.Mo
651}652}
652653
653// Creates a symbolic link at path `file_name` which points to `link_name`.654// Creates a symbolic link at path `file_name` which points to `link_name`.
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 {
655 dir.symLink(link_name, file_name, .{}) catch |err| {656 dir.symLink(link_name, file_name, .{}) catch |err| {
656 if (err == error.FileNotFound) {657 if (err == error.FileNotFound) {
657 if (std.fs.path.dirname(file_name)) |dir_name| {658 if (std.fs.path.dirname(file_name)) |dir_name| {
...@@ -783,7 +784,7 @@ test PaxIterator {...@@ -783,7 +784,7 @@ test PaxIterator {
783 var buffer: [1024]u8 = undefined;784 var buffer: [1024]u8 = undefined;
784785
785 outer: for (cases) |case| {786 outer: for (cases) |case| {
786 var reader: std.Io.Reader = .fixed(case.data);787 var reader: Io.Reader = .fixed(case.data);
787 var it: PaxIterator = .{788 var it: PaxIterator = .{
788 .size = case.data.len,789 .size = case.data.len,
789 .reader = &reader,790 .reader = &reader,
...@@ -874,13 +875,15 @@ test "header parse mode" {...@@ -874,13 +875,15 @@ test "header parse mode" {
874}875}
875876
876test "create file and symlink" {877test "create file and symlink" {
878 const io = testing.io;
879
877 var root = testing.tmpDir(.{});880 var root = testing.tmpDir(.{});
878 defer root.cleanup();881 defer root.cleanup();
879882
880 var file = try createDirAndFile(root.dir, "file1", default_mode);883 var file = try createDirAndFile(root.dir, "file1", default_mode);
881 file.close();884 file.close(io);
882 file = try createDirAndFile(root.dir, "a/b/c/file2", default_mode);885 file = try createDirAndFile(root.dir, "a/b/c/file2", default_mode);
883 file.close();886 file.close(io);
884887
885 createDirAndSymlink(root.dir, "a/b/c/file2", "symlink1") catch |err| {888 createDirAndSymlink(root.dir, "a/b/c/file2", "symlink1") catch |err| {
886 // On Windows when developer mode is not enabled889 // On Windows when developer mode is not enabled
...@@ -892,7 +895,7 @@ test "create file and symlink" {...@@ -892,7 +895,7 @@ test "create file and symlink" {
892 // Danglink symlnik, file created later895 // Danglink symlnik, file created later
893 try createDirAndSymlink(root.dir, "../../../g/h/i/file4", "j/k/l/symlink3");896 try createDirAndSymlink(root.dir, "../../../g/h/i/file4", "j/k/l/symlink3");
894 file = try createDirAndFile(root.dir, "g/h/i/file4", default_mode);897 file = try createDirAndFile(root.dir, "g/h/i/file4", default_mode);
895 file.close();898 file.close(io);
896}899}
897900
898test Iterator {901test Iterator {
...@@ -916,7 +919,7 @@ test Iterator {...@@ -916,7 +919,7 @@ test Iterator {
916 // example/empty/919 // example/empty/
917920
918 const data = @embedFile("tar/testdata/example.tar");921 const data = @embedFile("tar/testdata/example.tar");
919 var reader: std.Io.Reader = .fixed(data);922 var reader: Io.Reader = .fixed(data);
920923
921 // User provided buffers to the iterator924 // User provided buffers to the iterator
922 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;925 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
...@@ -942,7 +945,7 @@ test Iterator {...@@ -942,7 +945,7 @@ test Iterator {
942 .file => {945 .file => {
943 try testing.expectEqualStrings("example/a/file", file.name);946 try testing.expectEqualStrings("example/a/file", file.name);
944 var buf: [16]u8 = undefined;947 var buf: [16]u8 = undefined;
945 var w: std.Io.Writer = .fixed(&buf);948 var w: Io.Writer = .fixed(&buf);
946 try it.streamRemaining(file, &w);949 try it.streamRemaining(file, &w);
947 try testing.expectEqualStrings("content\n", w.buffered());950 try testing.expectEqualStrings("content\n", w.buffered());
948 },951 },
...@@ -955,6 +958,7 @@ test Iterator {...@@ -955,6 +958,7 @@ test Iterator {
955}958}
956959
957test pipeToFileSystem {960test pipeToFileSystem {
961 const io = testing.io;
958 // Example tar file is created from this tree structure:962 // Example tar file is created from this tree structure:
959 // $ tree example963 // $ tree example
960 // example964 // example
...@@ -975,14 +979,14 @@ test pipeToFileSystem {...@@ -975,14 +979,14 @@ test pipeToFileSystem {
975 // example/empty/979 // example/empty/
976980
977 const data = @embedFile("tar/testdata/example.tar");981 const data = @embedFile("tar/testdata/example.tar");
978 var reader: std.Io.Reader = .fixed(data);982 var reader: Io.Reader = .fixed(data);
979983
980 var tmp = testing.tmpDir(.{ .follow_symlinks = false });984 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
981 defer tmp.cleanup();985 defer tmp.cleanup();
982 const dir = tmp.dir;986 const dir = tmp.dir;
983987
984 // Save tar from reader to the file system `dir`988 // Save tar from reader to the file system `dir`
985 pipeToFileSystem(dir, &reader, .{989 pipeToFileSystem(io, dir, &reader, .{
986 .mode_mode = .ignore,990 .mode_mode = .ignore,
987 .strip_components = 1,991 .strip_components = 1,
988 .exclude_empty_directories = true,992 .exclude_empty_directories = true,
...@@ -1005,8 +1009,9 @@ test pipeToFileSystem {...@@ -1005,8 +1009,9 @@ test pipeToFileSystem {
1005}1009}
10061010
1007test "pipeToFileSystem root_dir" {1011test "pipeToFileSystem root_dir" {
1012 const io = testing.io;
1008 const data = @embedFile("tar/testdata/example.tar");1013 const data = @embedFile("tar/testdata/example.tar");
1009 var reader: std.Io.Reader = .fixed(data);1014 var reader: Io.Reader = .fixed(data);
10101015
1011 // with strip_components = 11016 // with strip_components = 1
1012 {1017 {
...@@ -1015,7 +1020,7 @@ test "pipeToFileSystem root_dir" {...@@ -1015,7 +1020,7 @@ test "pipeToFileSystem root_dir" {
1015 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1020 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1016 defer diagnostics.deinit();1021 defer diagnostics.deinit();
10171022
1018 pipeToFileSystem(tmp.dir, &reader, .{1023 pipeToFileSystem(io, tmp.dir, &reader, .{
1019 .strip_components = 1,1024 .strip_components = 1,
1020 .diagnostics = &diagnostics,1025 .diagnostics = &diagnostics,
1021 }) catch |err| {1026 }) catch |err| {
...@@ -1037,7 +1042,7 @@ test "pipeToFileSystem root_dir" {...@@ -1037,7 +1042,7 @@ test "pipeToFileSystem root_dir" {
1037 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1042 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1038 defer diagnostics.deinit();1043 defer diagnostics.deinit();
10391044
1040 pipeToFileSystem(tmp.dir, &reader, .{1045 pipeToFileSystem(io, tmp.dir, &reader, .{
1041 .strip_components = 0,1046 .strip_components = 0,
1042 .diagnostics = &diagnostics,1047 .diagnostics = &diagnostics,
1043 }) catch |err| {1048 }) catch |err| {
...@@ -1053,43 +1058,46 @@ test "pipeToFileSystem root_dir" {...@@ -1053,43 +1058,46 @@ test "pipeToFileSystem root_dir" {
1053}1058}
10541059
1055test "findRoot with single file archive" {1060test "findRoot with single file archive" {
1061 const io = testing.io;
1056 const data = @embedFile("tar/testdata/22752.tar");1062 const data = @embedFile("tar/testdata/22752.tar");
1057 var reader: std.Io.Reader = .fixed(data);1063 var reader: Io.Reader = .fixed(data);
10581064
1059 var tmp = testing.tmpDir(.{});1065 var tmp = testing.tmpDir(.{});
1060 defer tmp.cleanup();1066 defer tmp.cleanup();
10611067
1062 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1068 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1063 defer diagnostics.deinit();1069 defer diagnostics.deinit();
1064 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });1070 try pipeToFileSystem(io, tmp.dir, &reader, .{ .diagnostics = &diagnostics });
10651071
1066 try testing.expectEqualStrings("", diagnostics.root_dir);1072 try testing.expectEqualStrings("", diagnostics.root_dir);
1067}1073}
10681074
1069test "findRoot without explicit root dir" {1075test "findRoot without explicit root dir" {
1076 const io = testing.io;
1070 const data = @embedFile("tar/testdata/19820.tar");1077 const data = @embedFile("tar/testdata/19820.tar");
1071 var reader: std.Io.Reader = .fixed(data);1078 var reader: Io.Reader = .fixed(data);
10721079
1073 var tmp = testing.tmpDir(.{});1080 var tmp = testing.tmpDir(.{});
1074 defer tmp.cleanup();1081 defer tmp.cleanup();
10751082
1076 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1083 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1077 defer diagnostics.deinit();1084 defer diagnostics.deinit();
1078 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });1085 try pipeToFileSystem(io, tmp.dir, &reader, .{ .diagnostics = &diagnostics });
10791086
1080 try testing.expectEqualStrings("root", diagnostics.root_dir);1087 try testing.expectEqualStrings("root", diagnostics.root_dir);
1081}1088}
10821089
1083test "pipeToFileSystem strip_components" {1090test "pipeToFileSystem strip_components" {
1091 const io = testing.io;
1084 const data = @embedFile("tar/testdata/example.tar");1092 const data = @embedFile("tar/testdata/example.tar");
1085 var reader: std.Io.Reader = .fixed(data);1093 var reader: Io.Reader = .fixed(data);
10861094
1087 var tmp = testing.tmpDir(.{ .follow_symlinks = false });1095 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
1088 defer tmp.cleanup();1096 defer tmp.cleanup();
1089 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1097 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1090 defer diagnostics.deinit();1098 defer diagnostics.deinit();
10911099
1092 pipeToFileSystem(tmp.dir, &reader, .{1100 pipeToFileSystem(io, tmp.dir, &reader, .{
1093 .strip_components = 3,1101 .strip_components = 3,
1094 .diagnostics = &diagnostics,1102 .diagnostics = &diagnostics,
1095 }) catch |err| {1103 }) catch |err| {
...@@ -1110,10 +1118,10 @@ fn normalizePath(bytes: []u8) []u8 {...@@ -1110,10 +1118,10 @@ fn normalizePath(bytes: []u8) []u8 {
1110 return bytes;1118 return bytes;
1111}1119}
11121120
1113const default_mode = std.fs.File.default_mode;1121const default_mode = Io.File.default_mode;
11141122
1115// File system mode based on tar header mode and mode_mode options.1123// 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 {
1117 if (!std.fs.has_executable_bit or options.mode_mode == .ignore)1125 if (!std.fs.has_executable_bit or options.mode_mode == .ignore)
1118 return default_mode;1126 return default_mode;
11191127
...@@ -1139,16 +1147,17 @@ test fileMode {...@@ -1139,16 +1147,17 @@ test fileMode {
1139test "executable bit" {1147test "executable bit" {
1140 if (!std.fs.has_executable_bit) return error.SkipZigTest;1148 if (!std.fs.has_executable_bit) return error.SkipZigTest;
11411149
1150 const io = testing.io;
1142 const S = std.posix.S;1151 const S = std.posix.S;
1143 const data = @embedFile("tar/testdata/example.tar");1152 const data = @embedFile("tar/testdata/example.tar");
11441153
1145 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {1154 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {
1146 var reader: std.Io.Reader = .fixed(data);1155 var reader: Io.Reader = .fixed(data);
11471156
1148 var tmp = testing.tmpDir(.{ .follow_symlinks = false });1157 var tmp = testing.tmpDir(.{ .follow_symlinks = false });
1149 //defer tmp.cleanup();1158 //defer tmp.cleanup();
11501159
1151 pipeToFileSystem(tmp.dir, &reader, .{1160 pipeToFileSystem(io, tmp.dir, &reader, .{
1152 .strip_components = 1,1161 .strip_components = 1,
1153 .exclude_empty_directories = true,1162 .exclude_empty_directories = true,
1154 .mode_mode = opt,1163 .mode_mode = opt,
lib/std/tar/test.zig+5-3
...@@ -424,6 +424,7 @@ test "insufficient buffer in Header name filed" {...@@ -424,6 +424,7 @@ test "insufficient buffer in Header name filed" {
424}424}
425425
426test "should not overwrite existing file" {426test "should not overwrite existing file" {
427 const io = testing.io;
427 // Starting from this folder structure:428 // Starting from this folder structure:
428 // $ tree root429 // $ tree root
429 // root430 // root
...@@ -469,17 +470,18 @@ test "should not overwrite existing file" {...@@ -469,17 +470,18 @@ test "should not overwrite existing file" {
469 defer root.cleanup();470 defer root.cleanup();
470 try testing.expectError(471 try testing.expectError(
471 error.PathAlreadyExists,472 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 }),
473 );474 );
474475
475 // Unpack with strip_components = 0 should pass476 // Unpack with strip_components = 0 should pass
476 r = .fixed(data);477 r = .fixed(data);
477 var root2 = std.testing.tmpDir(.{});478 var root2 = std.testing.tmpDir(.{});
478 defer root2.cleanup();479 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 });
480}481}
481482
482test "case sensitivity" {483test "case sensitivity" {
484 const io = testing.io;
483 // Mimicking issue #18089, this tar contains, same file name in two case485 // Mimicking issue #18089, this tar contains, same file name in two case
484 // sensitive name version. Should fail on case insensitive file systems.486 // sensitive name version. Should fail on case insensitive file systems.
485 //487 //
...@@ -495,7 +497,7 @@ test "case sensitivity" {...@@ -495,7 +497,7 @@ test "case sensitivity" {
495 var root = std.testing.tmpDir(.{});497 var root = std.testing.tmpDir(.{});
496 defer root.cleanup();498 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| {
499 // on case insensitive fs we fail on overwrite existing file501 // on case insensitive fs we fail on overwrite existing file
500 try testing.expectEqual(error.PathAlreadyExists, err);502 try testing.expectEqual(error.PathAlreadyExists, err);
501 return;503 return;
lib/std/testing.zig+3-3
...@@ -613,9 +613,9 @@ pub const TmpDir = struct {...@@ -613,9 +613,9 @@ pub const TmpDir = struct {
613 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);613 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
614614
615 pub fn cleanup(self: *TmpDir) void {615 pub fn cleanup(self: *TmpDir) void {
616 self.dir.close();616 self.dir.close(io);
617 self.parent_dir.deleteTree(&self.sub_path) catch {};617 self.parent_dir.deleteTree(&self.sub_path) catch {};
618 self.parent_dir.close();618 self.parent_dir.close(io);
619 self.* = undefined;619 self.* = undefined;
620 }620 }
621};621};
...@@ -629,7 +629,7 @@ pub fn tmpDir(opts: std.fs.Dir.OpenOptions) TmpDir {...@@ -629,7 +629,7 @@ pub fn tmpDir(opts: std.fs.Dir.OpenOptions) TmpDir {
629 const cwd = std.fs.cwd();629 const cwd = std.fs.cwd();
630 var cache_dir = cwd.makeOpenPath(".zig-cache", .{}) catch630 var cache_dir = cwd.makeOpenPath(".zig-cache", .{}) catch
631 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");631 @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);
633 const parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch633 const parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch
634 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");634 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
635 const dir = parent_dir.makeOpenPath(&sub_path, opts) catch635 const dir = parent_dir.makeOpenPath(&sub_path, opts) catch
lib/std/zig/LibCInstallation.zig+40-31
...@@ -1,4 +1,18 @@...@@ -1,4 +1,18 @@
1//! See the render function implementation for documentation of the fields.1//! 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
3include_dir: ?[]const u8 = null,17include_dir: ?[]const u8 = null,
4sys_include_dir: ?[]const u8 = null,18sys_include_dir: ?[]const u8 = null,
...@@ -157,6 +171,7 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {...@@ -157,6 +171,7 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {
157171
158pub const FindNativeOptions = struct {172pub const FindNativeOptions = struct {
159 allocator: Allocator,173 allocator: Allocator,
174 io: Io,
160 target: *const std.Target,175 target: *const std.Target,
161176
162 /// If enabled, will print human-friendly errors to stderr.177 /// If enabled, will print human-friendly errors to stderr.
...@@ -165,29 +180,32 @@ pub const FindNativeOptions = struct {...@@ -165,29 +180,32 @@ pub const FindNativeOptions = struct {
165180
166/// Finds the default, native libc.181/// Finds the default, native libc.
167pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {182pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
183 const gpa = args.allocator;
184 const io = args.io;
185
168 var self: LibCInstallation = .{};186 var self: LibCInstallation = .{};
169187
170 if (is_darwin and args.target.os.tag.isDarwin()) {188 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))
172 return error.DarwinSdkNotFound;190 return error.DarwinSdkNotFound;
173 const sdk = std.zig.system.darwin.getSdk(args.allocator, args.target) orelse191 const sdk = std.zig.system.darwin.getSdk(gpa, args.target) orelse
174 return error.DarwinSdkNotFound;192 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, &.{
178 sdk, "usr/include",196 sdk, "usr/include",
179 });197 });
180 self.sys_include_dir = try fs.path.join(args.allocator, &.{198 self.sys_include_dir = try fs.path.join(gpa, &.{
181 sdk, "usr/include",199 sdk, "usr/include",
182 });200 });
183 return self;201 return self;
184 } else if (is_windows) {202 } 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) {
186 error.NotFound => return error.WindowsSdkNotFound,204 error.NotFound => return error.WindowsSdkNotFound,
187 error.PathTooLong => return error.WindowsSdkNotFound,205 error.PathTooLong => return error.WindowsSdkNotFound,
188 error.OutOfMemory => return error.OutOfMemory,206 error.OutOfMemory => return error.OutOfMemory,
189 };207 };
190 defer sdk.free(args.allocator);208 defer sdk.free(gpa);
191209
192 try self.findNativeMsvcIncludeDir(args, sdk);210 try self.findNativeMsvcIncludeDir(args, sdk);
193 try self.findNativeMsvcLibDir(args, sdk);211 try self.findNativeMsvcLibDir(args, sdk);
...@@ -197,16 +215,16 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {...@@ -197,16 +215,16 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
197 } else if (is_haiku) {215 } else if (is_haiku) {
198 try self.findNativeIncludeDirPosix(args);216 try self.findNativeIncludeDirPosix(args);
199 try self.findNativeGccDirHaiku(args);217 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");
201 } else if (builtin.target.os.tag == .illumos) {219 } else if (builtin.target.os.tag == .illumos) {
202 // There is only one libc, and its headers/libraries are always in the same spot.220 // 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");221 self.include_dir = try gpa.dupeZ(u8, "/usr/include");
204 self.sys_include_dir = try args.allocator.dupeZ(u8, "/usr/include");222 self.sys_include_dir = try gpa.dupeZ(u8, "/usr/include");
205 self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib/64");223 self.crt_dir = try gpa.dupeZ(u8, "/usr/lib/64");
206 } else if (std.process.can_spawn) {224 } else if (std.process.can_spawn) {
207 try self.findNativeIncludeDirPosix(args);225 try self.findNativeIncludeDirPosix(args);
208 switch (builtin.target.os.tag) {226 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"),
210 .linux => try self.findNativeCrtDirPosix(args),228 .linux => try self.findNativeCrtDirPosix(args),
211 else => {},229 else => {},
212 }230 }
...@@ -229,6 +247,7 @@ pub fn deinit(self: *LibCInstallation, allocator: Allocator) void {...@@ -229,6 +247,7 @@ pub fn deinit(self: *LibCInstallation, allocator: Allocator) void {
229247
230fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {248fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
231 const allocator = args.allocator;249 const allocator = args.allocator;
250 const io = args.io;
232251
233 // Detect infinite loops.252 // Detect infinite loops.
234 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {253 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
...@@ -326,7 +345,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F...@@ -326,7 +345,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
326345
327 else => return error.FileSystem,346 else => return error.FileSystem,
328 };347 };
329 defer search_dir.close();348 defer search_dir.close(io);
330349
331 if (self.include_dir == null) {350 if (self.include_dir == null) {
332 if (search_dir.access(include_dir_example_file, .{})) |_| {351 if (search_dir.access(include_dir_example_file, .{})) |_| {
...@@ -361,6 +380,7 @@ fn findNativeIncludeDirWindows(...@@ -361,6 +380,7 @@ fn findNativeIncludeDirWindows(
361 sdk: std.zig.WindowsSdk,380 sdk: std.zig.WindowsSdk,
362) FindError!void {381) FindError!void {
363 const allocator = args.allocator;382 const allocator = args.allocator;
383 const io = args.io;
364384
365 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;385 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
366 const installs = fillInstallations(&install_buf, sdk);386 const installs = fillInstallations(&install_buf, sdk);
...@@ -380,7 +400,7 @@ fn findNativeIncludeDirWindows(...@@ -380,7 +400,7 @@ fn findNativeIncludeDirWindows(
380400
381 else => return error.FileSystem,401 else => return error.FileSystem,
382 };402 };
383 defer dir.close();403 defer dir.close(io);
384404
385 dir.access("stdlib.h", .{}) catch |err| switch (err) {405 dir.access("stdlib.h", .{}) catch |err| switch (err) {
386 error.FileNotFound => continue,406 error.FileNotFound => continue,
...@@ -400,6 +420,7 @@ fn findNativeCrtDirWindows(...@@ -400,6 +420,7 @@ fn findNativeCrtDirWindows(
400 sdk: std.zig.WindowsSdk,420 sdk: std.zig.WindowsSdk,
401) FindError!void {421) FindError!void {
402 const allocator = args.allocator;422 const allocator = args.allocator;
423 const io = args.io;
403424
404 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;425 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
405 const installs = fillInstallations(&install_buf, sdk);426 const installs = fillInstallations(&install_buf, sdk);
...@@ -427,7 +448,7 @@ fn findNativeCrtDirWindows(...@@ -427,7 +448,7 @@ fn findNativeCrtDirWindows(
427448
428 else => return error.FileSystem,449 else => return error.FileSystem,
429 };450 };
430 defer dir.close();451 defer dir.close(io);
431452
432 dir.access("ucrt.lib", .{}) catch |err| switch (err) {453 dir.access("ucrt.lib", .{}) catch |err| switch (err) {
433 error.FileNotFound => continue,454 error.FileNotFound => continue,
...@@ -467,6 +488,7 @@ fn findNativeKernel32LibDir(...@@ -467,6 +488,7 @@ fn findNativeKernel32LibDir(
467 sdk: std.zig.WindowsSdk,488 sdk: std.zig.WindowsSdk,
468) FindError!void {489) FindError!void {
469 const allocator = args.allocator;490 const allocator = args.allocator;
491 const io = args.io;
470492
471 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;493 var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
472 const installs = fillInstallations(&install_buf, sdk);494 const installs = fillInstallations(&install_buf, sdk);
...@@ -494,7 +516,7 @@ fn findNativeKernel32LibDir(...@@ -494,7 +516,7 @@ fn findNativeKernel32LibDir(
494516
495 else => return error.FileSystem,517 else => return error.FileSystem,
496 };518 };
497 defer dir.close();519 defer dir.close(io);
498520
499 dir.access("kernel32.lib", .{}) catch |err| switch (err) {521 dir.access("kernel32.lib", .{}) catch |err| switch (err) {
500 error.FileNotFound => continue,522 error.FileNotFound => continue,
...@@ -513,6 +535,7 @@ fn findNativeMsvcIncludeDir(...@@ -513,6 +535,7 @@ fn findNativeMsvcIncludeDir(
513 sdk: std.zig.WindowsSdk,535 sdk: std.zig.WindowsSdk,
514) FindError!void {536) FindError!void {
515 const allocator = args.allocator;537 const allocator = args.allocator;
538 const io = args.io;
516539
517 const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCStdLibHeaderNotFound;540 const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCStdLibHeaderNotFound;
518 const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound;541 const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound;
...@@ -529,7 +552,7 @@ fn findNativeMsvcIncludeDir(...@@ -529,7 +552,7 @@ fn findNativeMsvcIncludeDir(
529552
530 else => return error.FileSystem,553 else => return error.FileSystem,
531 };554 };
532 defer dir.close();555 defer dir.close(io);
533556
534 dir.access("vcruntime.h", .{}) catch |err| switch (err) {557 dir.access("vcruntime.h", .{}) catch |err| switch (err) {
535 error.FileNotFound => return error.LibCStdLibHeaderNotFound,558 error.FileNotFound => return error.LibCStdLibHeaderNotFound,
...@@ -1015,17 +1038,3 @@ pub fn resolveCrtPaths(...@@ -1015,17 +1038,3 @@ pub fn resolveCrtPaths(
1015 },1038 },
1016 }1039 }
1017}1040}
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 @@...@@ -1,7 +1,10 @@
1const WindowsSdk = @This();1const WindowsSdk = @This();
2const builtin = @import("builtin");2const builtin = @import("builtin");
3
3const std = @import("std");4const std = @import("std");
5const Io = std.Io;
4const Writer = std.Io.Writer;6const Writer = std.Io.Writer;
7const Allocator = std.mem.Allocator;
58
6windows10sdk: ?Installation,9windows10sdk: ?Installation,
7windows81sdk: ?Installation,10windows81sdk: ?Installation,
...@@ -20,7 +23,7 @@ const product_version_max_length = version_major_minor_max_length + ".65535".len...@@ -20,7 +23,7 @@ const product_version_max_length = version_major_minor_max_length + ".65535".len
20/// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory.23/// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory.
21/// Caller owns the result's fields.24/// Caller owns the result's fields.
22/// After finishing work, call `free(allocator)`.25/// 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 {
24 if (builtin.os.tag != .windows) return error.NotFound;27 if (builtin.os.tag != .windows) return error.NotFound;
2528
26 //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed29 //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...@@ -58,7 +61,7 @@ pub fn find(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutO
58 };61 };
59}62}
6063
61pub fn free(sdk: WindowsSdk, allocator: std.mem.Allocator) void {64pub fn free(sdk: WindowsSdk, allocator: Allocator) void {
62 if (sdk.windows10sdk) |*w10sdk| {65 if (sdk.windows10sdk) |*w10sdk| {
63 w10sdk.free(allocator);66 w10sdk.free(allocator);
64 }67 }
...@@ -75,7 +78,7 @@ pub fn free(sdk: WindowsSdk, allocator: std.mem.Allocator) void {...@@ -75,7 +78,7 @@ pub fn free(sdk: WindowsSdk, allocator: std.mem.Allocator) void {
75/// Caller owns result.78/// Caller owns result.
76fn iterateAndFilterByVersion(79fn iterateAndFilterByVersion(
77 iterator: *std.fs.Dir.Iterator,80 iterator: *std.fs.Dir.Iterator,
78 allocator: std.mem.Allocator,81 allocator: Allocator,
79 prefix: []const u8,82 prefix: []const u8,
80) error{OutOfMemory}![][]const u8 {83) error{OutOfMemory}![][]const u8 {
81 const Version = struct {84 const Version = struct {
...@@ -174,7 +177,7 @@ const RegistryWtf8 = struct {...@@ -174,7 +177,7 @@ const RegistryWtf8 = struct {
174177
175 /// Get string from registry.178 /// Get string from registry.
176 /// Caller owns result.179 /// 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 {
178 const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: {181 const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: {
179 var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined;182 var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined;
180 const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable;183 const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable;
...@@ -282,7 +285,7 @@ const RegistryWtf16Le = struct {...@@ -282,7 +285,7 @@ const RegistryWtf16Le = struct {
282 }285 }
283286
284 /// Get string ([:0]const u16) from registry.287 /// 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 {
286 var actual_type: windows.ULONG = undefined;289 var actual_type: windows.ULONG = undefined;
287290
288 // Calculating length to allocate291 // Calculating length to allocate
...@@ -416,7 +419,7 @@ pub const Installation = struct {...@@ -416,7 +419,7 @@ pub const Installation = struct {
416 /// Caller owns the result's fields.419 /// Caller owns the result's fields.
417 /// After finishing work, call `free(allocator)`.420 /// After finishing work, call `free(allocator)`.
418 fn find(421 fn find(
419 allocator: std.mem.Allocator,422 allocator: Allocator,
420 roots_key: RegistryWtf8,423 roots_key: RegistryWtf8,
421 roots_subkey: []const u8,424 roots_subkey: []const u8,
422 prefix: []const u8,425 prefix: []const u8,
...@@ -437,7 +440,8 @@ pub const Installation = struct {...@@ -437,7 +440,8 @@ pub const Installation = struct {
437 }440 }
438441
439 fn findFromRoot(442 fn findFromRoot(
440 allocator: std.mem.Allocator,443 allocator: Allocator,
444 io: Io,
441 roots_key: RegistryWtf8,445 roots_key: RegistryWtf8,
442 roots_subkey: []const u8,446 roots_subkey: []const u8,
443 prefix: []const u8,447 prefix: []const u8,
...@@ -478,7 +482,7 @@ pub const Installation = struct {...@@ -478,7 +482,7 @@ pub const Installation = struct {
478 error.NameTooLong => return error.PathTooLong,482 error.NameTooLong => return error.PathTooLong,
479 else => return error.InstallationNotFound,483 else => return error.InstallationNotFound,
480 };484 };
481 defer sdk_lib_dir.close();485 defer sdk_lib_dir.close(io);
482486
483 var iterator = sdk_lib_dir.iterate();487 var iterator = sdk_lib_dir.iterate();
484 const versions = try iterateAndFilterByVersion(&iterator, allocator, prefix);488 const versions = try iterateAndFilterByVersion(&iterator, allocator, prefix);
...@@ -495,7 +499,7 @@ pub const Installation = struct {...@@ -495,7 +499,7 @@ pub const Installation = struct {
495 }499 }
496500
497 fn findFromInstallationFolder(501 fn findFromInstallationFolder(
498 allocator: std.mem.Allocator,502 allocator: Allocator,
499 version_key_name: []const u8,503 version_key_name: []const u8,
500 ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation {504 ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation {
501 var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined;505 var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined;
...@@ -597,14 +601,14 @@ pub const Installation = struct {...@@ -597,14 +601,14 @@ pub const Installation = struct {
597 return (reg_value == 1);601 return (reg_value == 1);
598 }602 }
599603
600 fn free(install: Installation, allocator: std.mem.Allocator) void {604 fn free(install: Installation, allocator: Allocator) void {
601 allocator.free(install.path);605 allocator.free(install.path);
602 allocator.free(install.version);606 allocator.free(install.version);
603 }607 }
604};608};
605609
606const MsvcLibDir = struct {610const 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 {
608 const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup";612 const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup";
609 const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) {613 const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) {
610 error.KeyNotFound => return error.PathNotFound,614 error.KeyNotFound => return error.PathNotFound,
...@@ -629,7 +633,7 @@ const MsvcLibDir = struct {...@@ -629,7 +633,7 @@ const MsvcLibDir = struct {
629 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;633 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
630 }634 }
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 {
633 const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";637 const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";
634 const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) {638 const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) {
635 error.KeyNotFound => return error.PathNotFound,639 error.KeyNotFound => return error.PathNotFound,
...@@ -665,7 +669,7 @@ const MsvcLibDir = struct {...@@ -665,7 +669,7 @@ const MsvcLibDir = struct {
665 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;669 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
666 }670 }
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 {
669 // First, try getting the packages cache path from the registry.673 // First, try getting the packages cache path from the registry.
670 // This only seems to exist when the path is different from the default.674 // This only seems to exist when the path is different from the default.
671 method1: {675 method1: {
...@@ -748,13 +752,13 @@ const MsvcLibDir = struct {...@@ -748,13 +752,13 @@ const MsvcLibDir = struct {
748 ///752 ///
749 /// The logic in this function is intended to match what ISetupConfiguration does753 /// The logic in this function is intended to match what ISetupConfiguration does
750 /// under-the-hood, as verified using Procmon.754 /// 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 {
752 // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances`756 // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances`
753 // This will contain directories with names of instance IDs like 80a758ca,757 // This will contain directories with names of instance IDs like 80a758ca,
754 // which will contain `state.json` files that have the version and758 // which will contain `state.json` files that have the version and
755 // installation directory.759 // installation directory.
756 var instances_dir = try findInstancesDir(allocator);760 var instances_dir = try findInstancesDir(allocator);
757 defer instances_dir.close();761 defer instances_dir.close(io);
758762
759 var state_subpath_buf: [std.fs.max_name_bytes + 32]u8 = undefined;763 var state_subpath_buf: [std.fs.max_name_bytes + 32]u8 = undefined;
760 var latest_version_lib_dir: std.ArrayList(u8) = .empty;764 var latest_version_lib_dir: std.ArrayList(u8) = .empty;
...@@ -791,7 +795,7 @@ const MsvcLibDir = struct {...@@ -791,7 +795,7 @@ const MsvcLibDir = struct {
791 const installation_path = parsed.value.object.get("installationPath") orelse continue;795 const installation_path = parsed.value.object.get("installationPath") orelse continue;
792 if (installation_path != .string) continue;796 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) {
795 error.OutOfMemory => |e| return e,799 error.OutOfMemory => |e| return e,
796 error.PathNotFound => continue,800 error.PathNotFound => continue,
797 };801 };
...@@ -806,7 +810,12 @@ const MsvcLibDir = struct {...@@ -806,7 +810,12 @@ const MsvcLibDir = struct {
806 return latest_version_lib_dir.toOwnedSlice(allocator);810 return latest_version_lib_dir.toOwnedSlice(allocator);
807 }811 }
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 {
810 var lib_dir_buf = try std.array_list.Managed(u8).initCapacity(allocator, installation_path.len + 64);819 var lib_dir_buf = try std.array_list.Managed(u8).initCapacity(allocator, installation_path.len + 64);
811 errdefer lib_dir_buf.deinit();820 errdefer lib_dir_buf.deinit();
812821
...@@ -837,7 +846,7 @@ const MsvcLibDir = struct {...@@ -837,7 +846,7 @@ const MsvcLibDir = struct {
837 else => unreachable,846 else => unreachable,
838 });847 });
839848
840 if (!verifyLibDir(lib_dir_buf.items)) {849 if (!verifyLibDir(io, lib_dir_buf.items)) {
841 return error.PathNotFound;850 return error.PathNotFound;
842 }851 }
843852
...@@ -845,7 +854,7 @@ const MsvcLibDir = struct {...@@ -845,7 +854,7 @@ const MsvcLibDir = struct {
845 }854 }
846855
847 // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#editing-the-registry-for-a-visual-studio-instance856 // 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
850 // %localappdata%\Microsoft\VisualStudio\859 // %localappdata%\Microsoft\VisualStudio\
851 // %appdata%\Local\Microsoft\VisualStudio\860 // %appdata%\Local\Microsoft\VisualStudio\
...@@ -859,7 +868,7 @@ const MsvcLibDir = struct {...@@ -859,7 +868,7 @@ const MsvcLibDir = struct {
859 var visualstudio_folder = std.fs.openDirAbsolute(visualstudio_folder_path, .{868 var visualstudio_folder = std.fs.openDirAbsolute(visualstudio_folder_path, .{
860 .iterate = true,869 .iterate = true,
861 }) catch return error.PathNotFound;870 }) catch return error.PathNotFound;
862 defer visualstudio_folder.close();871 defer visualstudio_folder.close(io);
863872
864 var iterator = visualstudio_folder.iterate();873 var iterator = visualstudio_folder.iterate();
865 break :vs_versions try iterateAndFilterByVersion(&iterator, allocator, "");874 break :vs_versions try iterateAndFilterByVersion(&iterator, allocator, "");
...@@ -926,14 +935,14 @@ const MsvcLibDir = struct {...@@ -926,14 +935,14 @@ const MsvcLibDir = struct {
926 };935 };
927 errdefer allocator.free(msvc_dir);936 errdefer allocator.free(msvc_dir);
928937
929 if (!verifyLibDir(msvc_dir)) {938 if (!verifyLibDir(io, msvc_dir)) {
930 return error.PathNotFound;939 return error.PathNotFound;
931 }940 }
932941
933 return msvc_dir;942 return msvc_dir;
934 }943 }
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 {
937 var base_path: std.array_list.Managed(u8) = base_path: {946 var base_path: std.array_list.Managed(u8) = base_path: {
938 try_env: {947 try_env: {
939 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {948 var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
...@@ -989,7 +998,7 @@ const MsvcLibDir = struct {...@@ -989,7 +998,7 @@ const MsvcLibDir = struct {
989 else => unreachable,998 else => unreachable,
990 });999 });
9911000
992 if (!verifyLibDir(base_path.items)) {1001 if (!verifyLibDir(io, base_path.items)) {
993 return error.PathNotFound;1002 return error.PathNotFound;
994 }1003 }
9951004
...@@ -997,11 +1006,11 @@ const MsvcLibDir = struct {...@@ -997,11 +1006,11 @@ const MsvcLibDir = struct {
997 return full_path;1006 return full_path;
998 }1007 }
9991008
1000 fn verifyLibDir(lib_dir_path: []const u8) bool {1009 fn verifyLibDir(io: Io, lib_dir_path: []const u8) bool {
1001 std.debug.assert(std.fs.path.isAbsolute(lib_dir_path)); // should be already handled in `findVia*`1010 std.debug.assert(std.fs.path.isAbsolute(lib_dir_path)); // should be already handled in `findVia*`
10021011
1003 var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false;1012 var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false;
1004 defer dir.close();1013 defer dir.close(io);
10051014
1006 const stat = dir.statFile("vcruntime.lib") catch return false;1015 const stat = dir.statFile("vcruntime.lib") catch return false;
1007 if (stat.kind != .file)1016 if (stat.kind != .file)
...@@ -1012,12 +1021,12 @@ const MsvcLibDir = struct {...@@ -1012,12 +1021,12 @@ const MsvcLibDir = struct {
10121021
1013 /// Find path to MSVC's `lib/` directory.1022 /// Find path to MSVC's `lib/` directory.
1014 /// Caller owns the result.1023 /// Caller owns the result.
1015 pub fn find(allocator: std.mem.Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 {1024 pub fn find(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 {
1016 const full_path = MsvcLibDir.findViaCOM(allocator, arch) catch |err1| switch (err1) {1025 const full_path = MsvcLibDir.findViaCOM(allocator, io, arch) catch |err1| switch (err1) {
1017 error.OutOfMemory => return error.OutOfMemory,1026 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) {
1019 error.OutOfMemory => return error.OutOfMemory,1028 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) {
1021 error.OutOfMemory => return error.OutOfMemory,1030 error.OutOfMemory => return error.OutOfMemory,
1022 error.PathNotFound => return error.MsvcLibDirNotFound,1031 error.PathNotFound => return error.MsvcLibDirNotFound,
1023 },1032 },
lib/std/zig/llvm/Builder.zig+11-8
...@@ -1,14 +1,17 @@...@@ -1,14 +1,17 @@
1const builtin = @import("builtin");
2const Builder = @This();
3
1const std = @import("../../std.zig");4const std = @import("../../std.zig");
5const Io = std.Io;
2const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;7const assert = std.debug.assert;
4const bitcode_writer = @import("bitcode_writer.zig");
5const Builder = @This();
6const builtin = @import("builtin");
7const DW = std.dwarf;8const DW = std.dwarf;
8const ir = @import("ir.zig");
9const log = std.log.scoped(.llvm);9const log = std.log.scoped(.llvm);
10const Writer = std.Io.Writer;10const Writer = std.Io.Writer;
1111
12const bitcode_writer = @import("bitcode_writer.zig");
13const ir = @import("ir.zig");
14
12gpa: Allocator,15gpa: Allocator,
13strip: bool,16strip: bool,
1417
...@@ -9579,11 +9582,11 @@ pub fn dump(b: *Builder) void {...@@ -9579,11 +9582,11 @@ pub fn dump(b: *Builder) void {
9579 b.printToFile(stderr, &buffer) catch {};9582 b.printToFile(stderr, &buffer) catch {};
9580}9583}
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 {
9583 var buffer: [4000]u8 = undefined;9586 var buffer: [4000]u8 = undefined;
9584 const file = try dir.createFile(path, .{});9587 const file = try dir.createFile(io, path, .{});
9585 defer file.close();9588 defer file.close(io);
9586 try b.printToFile(file, &buffer);9589 try b.printToFile(io, file, &buffer);
9587}9590}
95889591
9589pub fn printToFile(b: *Builder, file: std.fs.File, buffer: []u8) !void {9592pub 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 {...@@ -847,7 +847,7 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {
847 error.Unexpected => |e| return e,847 error.Unexpected => |e| return e,
848 error.Canceled => |e| return e,848 error.Canceled => |e| return e,
849 };849 };
850 defer file.close();850 defer file.close(io);
851851
852 // Empirically, glibc 2.34 libc.so .dynstr section is 32441 bytes on my system.852 // Empirically, glibc 2.34 libc.so .dynstr section is 32441 bytes on my system.
853 var buffer: [8000]u8 = undefined;853 var buffer: [8000]u8 = undefined;
...@@ -1051,7 +1051,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ...@@ -1051,7 +1051,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
1051 else => |e| return e,1051 else => |e| return e,
1052 };1052 };
1053 var is_elf_file = false;1053 var is_elf_file = false;
1054 defer if (!is_elf_file) file.close();1054 defer if (!is_elf_file) file.close(io);
10551055
1056 file_reader = .initAdapted(file, io, &file_reader_buffer);1056 file_reader = .initAdapted(file, io, &file_reader_buffer);
1057 file_name = undefined; // it aliases file_reader_buffer1057 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 {...@@ -447,7 +447,7 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
447 var file = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) {447 var file = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) {
448 else => return null,448 else => return null,
449 };449 };
450 defer file.close();450 defer file.close(io);
451451
452 var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long.452 var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long.
453 var file_reader = file.reader(io, &buffer);453 var file_reader = file.reader(io, &buffer);
lib/std/zip.zig+4-2
...@@ -554,17 +554,19 @@ pub const Iterator = struct {...@@ -554,17 +554,19 @@ pub const Iterator = struct {
554 return;554 return;
555 }555 }
556556
557 const io = stream.io;
558
557 const out_file = blk: {559 const out_file = blk: {
558 if (std.fs.path.dirname(filename)) |dirname| {560 if (std.fs.path.dirname(filename)) |dirname| {
559 var parent_dir = try dest.makeOpenPath(dirname, .{});561 var parent_dir = try dest.makeOpenPath(dirname, .{});
560 defer parent_dir.close();562 defer parent_dir.close(io);
561563
562 const basename = std.fs.path.basename(filename);564 const basename = std.fs.path.basename(filename);
563 break :blk try parent_dir.createFile(basename, .{ .exclusive = true });565 break :blk try parent_dir.createFile(basename, .{ .exclusive = true });
564 }566 }
565 break :blk try dest.createFile(filename, .{ .exclusive = true });567 break :blk try dest.createFile(filename, .{ .exclusive = true });
566 };568 };
567 defer out_file.close();569 defer out_file.close(io);
568 var out_file_buffer: [1024]u8 = undefined;570 var out_file_buffer: [1024]u8 = undefined;
569 var file_writer = out_file.writer(&out_file_buffer);571 var file_writer = out_file.writer(&out_file_buffer);
570 const local_data_file_offset: u64 =572 const local_data_file_offset: u64 =
src/Compilation.zig+34-30
...@@ -721,13 +721,13 @@ pub const Directories = struct {...@@ -721,13 +721,13 @@ pub const Directories = struct {
721 /// This may be the same as `global_cache`.721 /// This may be the same as `global_cache`.
722 local_cache: Cache.Directory,722 local_cache: Cache.Directory,
723723
724 pub fn deinit(dirs: *Directories) void {724 pub fn deinit(dirs: *Directories, io: Io) void {
725 // The local and global caches could be the same.725 // The local and global caches could be the same.
726 const close_local = dirs.local_cache.handle.fd != dirs.global_cache.handle.fd;726 const close_local = dirs.local_cache.handle.fd != dirs.global_cache.handle.fd;
727727
728 dirs.global_cache.handle.close();728 dirs.global_cache.handle.close(io);
729 if (close_local) dirs.local_cache.handle.close();729 if (close_local) dirs.local_cache.handle.close(io);
730 dirs.zig_lib.handle.close();730 dirs.zig_lib.handle.close(io);
731 }731 }
732732
733 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for733 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for
...@@ -1105,7 +1105,7 @@ pub const CObject = struct {...@@ -1105,7 +1105,7 @@ pub const CObject = struct {
1105 if (diag.src_loc.offset == 0 or diag.src_loc.column == 0) break :source_line 0;1105 if (diag.src_loc.offset == 0 or diag.src_loc.column == 0) break :source_line 0;
11061106
1107 const file = fs.cwd().openFile(file_name, .{}) catch break :source_line 0;1107 const file = fs.cwd().openFile(file_name, .{}) catch break :source_line 0;
1108 defer file.close();1108 defer file.close(io);
1109 var buffer: [1024]u8 = undefined;1109 var buffer: [1024]u8 = undefined;
1110 var file_reader = file.reader(io, &buffer);1110 var file_reader = file.reader(io, &buffer);
1111 file_reader.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0;1111 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 {...@@ -1180,7 +1180,7 @@ pub const CObject = struct {
11801180
1181 var buffer: [1024]u8 = undefined;1181 var buffer: [1024]u8 = undefined;
1182 const file = try fs.cwd().openFile(path, .{});1182 const file = try fs.cwd().openFile(path, .{});
1183 defer file.close();1183 defer file.close(io);
1184 var file_reader = file.reader(io, &buffer);1184 var file_reader = file.reader(io, &buffer);
1185 var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = &file_reader.interface });1185 var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = &file_reader.interface });
1186 defer bc.deinit();1186 defer bc.deinit();
...@@ -1617,13 +1617,13 @@ const CacheUse = union(CacheMode) {...@@ -1617,13 +1617,13 @@ const CacheUse = union(CacheMode) {
1617 }1617 }
1618 };1618 };
16191619
1620 fn deinit(cu: CacheUse) void {1620 fn deinit(cu: CacheUse, io: Io) void {
1621 switch (cu) {1621 switch (cu) {
1622 .none => |none| {1622 .none => |none| {
1623 assert(none.tmp_artifact_directory == null);1623 assert(none.tmp_artifact_directory == null);
1624 },1624 },
1625 .incremental => |incremental| {1625 .incremental => |incremental| {
1626 incremental.artifact_directory.handle.close();1626 incremental.artifact_directory.handle.close(io);
1627 },1627 },
1628 .whole => |whole| {1628 .whole => |whole| {
1629 assert(whole.tmp_artifact_directory == null);1629 assert(whole.tmp_artifact_directory == null);
...@@ -2113,7 +2113,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2113,7 +2113,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2113 cache.addPrefix(options.dirs.zig_lib);2113 cache.addPrefix(options.dirs.zig_lib);
2114 cache.addPrefix(options.dirs.local_cache);2114 cache.addPrefix(options.dirs.local_cache);
2115 cache.addPrefix(options.dirs.global_cache);2115 cache.addPrefix(options.dirs.global_cache);
2116 errdefer cache.manifest_dir.close();2116 errdefer cache.manifest_dir.close(io);
21172117
2118 // This is shared hasher state common to zig source and all C source files.2118 // This is shared hasher state common to zig source and all C source files.
2119 cache.hash.addBytes(build_options.version);2119 cache.hash.addBytes(build_options.version);
...@@ -2157,7 +2157,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2157,7 +2157,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2157 var local_zir_dir = options.dirs.local_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {2157 var local_zir_dir = options.dirs.local_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {
2158 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = zir_sub_dir, .err = err } });2158 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = zir_sub_dir, .err = err } });
2159 };2159 };
2160 errdefer local_zir_dir.close();2160 errdefer local_zir_dir.close(io);
2161 const local_zir_cache: Cache.Directory = .{2161 const local_zir_cache: Cache.Directory = .{
2162 .handle = local_zir_dir,2162 .handle = local_zir_dir,
2163 .path = try options.dirs.local_cache.join(arena, &.{zir_sub_dir}),2163 .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,...@@ -2165,7 +2165,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2165 var global_zir_dir = options.dirs.global_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {2165 var global_zir_dir = options.dirs.global_cache.handle.makeOpenPath(zir_sub_dir, .{}) catch |err| {
2166 return diag.fail(.{ .create_cache_path = .{ .which = .global, .sub = zir_sub_dir, .err = err } });2166 return diag.fail(.{ .create_cache_path = .{ .which = .global, .sub = zir_sub_dir, .err = err } });
2167 };2167 };
2168 errdefer global_zir_dir.close();2168 errdefer global_zir_dir.close(io);
2169 const global_zir_cache: Cache.Directory = .{2169 const global_zir_cache: Cache.Directory = .{
2170 .handle = global_zir_dir,2170 .handle = global_zir_dir,
2171 .path = try options.dirs.global_cache.join(arena, &.{zir_sub_dir}),2171 .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,...@@ -2436,7 +2436,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2436 var artifact_dir = options.dirs.local_cache.handle.makeOpenPath(artifact_sub_dir, .{}) catch |err| {2436 var artifact_dir = options.dirs.local_cache.handle.makeOpenPath(artifact_sub_dir, .{}) catch |err| {
2437 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = artifact_sub_dir, .err = err } });2437 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = artifact_sub_dir, .err = err } });
2438 };2438 };
2439 errdefer artifact_dir.close();2439 errdefer artifact_dir.close(io);
2440 const artifact_directory: Cache.Directory = .{2440 const artifact_directory: Cache.Directory = .{
2441 .handle = artifact_dir,2441 .handle = artifact_dir,
2442 .path = try options.dirs.local_cache.join(arena, &.{artifact_sub_dir}),2442 .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,...@@ -2689,6 +2689,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
26892689
2690pub fn destroy(comp: *Compilation) void {2690pub fn destroy(comp: *Compilation) void {
2691 const gpa = comp.gpa;2691 const gpa = comp.gpa;
2692 const io = comp.io;
26922693
2693 if (comp.bin_file) |lf| lf.destroy();2694 if (comp.bin_file) |lf| lf.destroy();
2694 if (comp.zcu) |zcu| zcu.deinit();2695 if (comp.zcu) |zcu| zcu.deinit();
...@@ -2760,7 +2761,7 @@ pub fn destroy(comp: *Compilation) void {...@@ -2760,7 +2761,7 @@ pub fn destroy(comp: *Compilation) void {
27602761
2761 comp.clearMiscFailures();2762 comp.clearMiscFailures();
27622763
2763 comp.cache_parent.manifest_dir.close();2764 comp.cache_parent.manifest_dir.close(io);
2764}2765}
27652766
2766pub fn clearMiscFailures(comp: *Compilation) void {2767pub fn clearMiscFailures(comp: *Compilation) void {
...@@ -2791,10 +2792,12 @@ pub fn hotCodeSwap(...@@ -2791,10 +2792,12 @@ pub fn hotCodeSwap(
2791}2792}
27922793
2793fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {2794fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2795 const io = comp.io;
2796
2794 switch (comp.cache_use) {2797 switch (comp.cache_use) {
2795 .none => |none| {2798 .none => |none| {
2796 if (none.tmp_artifact_directory) |*tmp_dir| {2799 if (none.tmp_artifact_directory) |*tmp_dir| {
2797 tmp_dir.handle.close();2800 tmp_dir.handle.close(io);
2798 none.tmp_artifact_directory = null;2801 none.tmp_artifact_directory = null;
2799 if (dev.env == .bootstrap) {2802 if (dev.env == .bootstrap) {
2800 // zig1 uses `CacheMode.none`, but it doesn't need to know how to delete2803 // 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 {...@@ -2834,7 +2837,7 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2834 comp.bin_file = null;2837 comp.bin_file = null;
2835 }2838 }
2836 if (whole.tmp_artifact_directory) |*tmp_dir| {2839 if (whole.tmp_artifact_directory) |*tmp_dir| {
2837 tmp_dir.handle.close();2840 tmp_dir.handle.close(io);
2838 whole.tmp_artifact_directory = null;2841 whole.tmp_artifact_directory = null;
2839 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);2842 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
2840 comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| {2843 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...@@ -3152,7 +3155,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3152 // the file handle and re-open it in the follow up call to3155 // the file handle and re-open it in the follow up call to
3153 // `makeWritable`.3156 // `makeWritable`.
3154 if (lf.file) |f| {3157 if (lf.file) |f| {
3155 f.close();3158 f.close(io);
3156 lf.file = null;3159 lf.file = null;
31573160
3158 if (lf.closeDebugInfo()) break :w .lf_and_debug;3161 if (lf.closeDebugInfo()) break :w .lf_and_debug;
...@@ -3165,7 +3168,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3165,7 +3168,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
31653168
3166 // Rename the temporary directory into place.3169 // Rename the temporary directory into place.
3167 // Close tmp dir and link.File to avoid open handle during rename.3170 // 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);
3169 whole.tmp_artifact_directory = null;3172 whole.tmp_artifact_directory = null;
3170 const s = fs.path.sep_str;3173 const s = fs.path.sep_str;
3171 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);3174 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
...@@ -5258,6 +5261,7 @@ fn workerDocsCopy(comp: *Compilation) void {...@@ -5258,6 +5261,7 @@ fn workerDocsCopy(comp: *Compilation) void {
52585261
5259fn docsCopyFallible(comp: *Compilation) anyerror!void {5262fn docsCopyFallible(comp: *Compilation) anyerror!void {
5260 const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});5263 const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});
5264 const io = comp.io;
52615265
5262 const docs_path = comp.resolveEmitPath(comp.emit_docs.?);5266 const docs_path = comp.resolveEmitPath(comp.emit_docs.?);
5263 var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| {5267 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 {...@@ -5267,7 +5271,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
5267 .{ docs_path, @errorName(err) },5271 .{ docs_path, @errorName(err) },
5268 );5272 );
5269 };5273 };
5270 defer out_dir.close();5274 defer out_dir.close(io);
52715275
5272 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {5276 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
5273 const basename = fs.path.basename(sub_path);5277 const basename = fs.path.basename(sub_path);
...@@ -5287,7 +5291,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -5287,7 +5291,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
5287 .{ docs_path, @errorName(err) },5291 .{ docs_path, @errorName(err) },
5288 );5292 );
5289 };5293 };
5290 defer tar_file.close();5294 defer tar_file.close(io);
52915295
5292 var buffer: [1024]u8 = undefined;5296 var buffer: [1024]u8 = undefined;
5293 var tar_file_writer = tar_file.writer(&buffer);5297 var tar_file_writer = tar_file.writer(&buffer);
...@@ -5331,7 +5335,7 @@ fn docsCopyModule(...@@ -5331,7 +5335,7 @@ fn docsCopyModule(
5331 } catch |err| {5335 } catch |err| {
5332 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err });5336 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err });
5333 };5337 };
5334 defer mod_dir.close();5338 defer mod_dir.close(io);
53355339
5336 var walker = try mod_dir.walk(comp.gpa);5340 var walker = try mod_dir.walk(comp.gpa);
5337 defer walker.deinit();5341 defer walker.deinit();
...@@ -5355,7 +5359,7 @@ fn docsCopyModule(...@@ -5355,7 +5359,7 @@ fn docsCopyModule(
5355 root.fmt(comp), entry.path, err,5359 root.fmt(comp), entry.path, err,
5356 });5360 });
5357 };5361 };
5358 defer file.close();5362 defer file.close(io);
5359 const stat = try file.stat();5363 const stat = try file.stat();
5360 var file_reader: fs.File.Reader = .initSize(file.adaptToNewApi(), io, &buffer, stat.size);5364 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...@@ -5510,7 +5514,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
5510 );5514 );
5511 return error.AlreadyReported;5515 return error.AlreadyReported;
5512 };5516 };
5513 defer out_dir.close();5517 defer out_dir.close(io);
55145518
5515 crt_file.full_object_path.root_dir.handle.copyFile(5519 crt_file.full_object_path.root_dir.handle.copyFile(
5516 crt_file.full_object_path.sub_path,5520 crt_file.full_object_path.sub_path,
...@@ -5693,7 +5697,7 @@ pub fn translateC(...@@ -5693,7 +5697,7 @@ pub fn translateC(
5693 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename;5697 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename;
5694 const cache_dir = comp.dirs.local_cache.handle;5698 const cache_dir = comp.dirs.local_cache.handle;
5695 var cache_tmp_dir = try cache_dir.makeOpenPath(tmp_sub_path, .{});5699 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
5698 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename });5702 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename });
5699 const source_path = switch (source) {5703 const source_path = switch (source) {
...@@ -6268,7 +6272,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -6268,7 +6272,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
6268 // so we need a temporary filename.6272 // so we need a temporary filename.
6269 const out_obj_path = try comp.tmpFilePath(arena, o_basename);6273 const out_obj_path = try comp.tmpFilePath(arena, o_basename);
6270 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});6274 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
6273 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics())6277 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics())
6274 null6278 null
...@@ -6433,7 +6437,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -6433,7 +6437,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
6433 const digest = man.final();6437 const digest = man.final();
6434 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });6438 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
6435 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});6439 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
6436 defer o_dir.close();6440 defer o_dir.close(io);
6437 const tmp_basename = fs.path.basename(out_obj_path);6441 const tmp_basename = fs.path.basename(out_obj_path);
6438 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);6442 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
6439 break :blk digest;6443 break :blk digest;
...@@ -6477,8 +6481,6 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6477,8 +6481,6 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
6477 const tracy_trace = trace(@src());6481 const tracy_trace = trace(@src());
6478 defer tracy_trace.end();6482 defer tracy_trace.end();
64796483
6480 const io = comp.io;
6481
6482 const src_path = switch (win32_resource.src) {6484 const src_path = switch (win32_resource.src) {
6483 .rc => |rc_src| rc_src.src_path,6485 .rc => |rc_src| rc_src.src_path,
6484 .manifest => |src_path| src_path,6486 .manifest => |src_path| src_path,
...@@ -6487,6 +6489,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6487,6 +6489,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
64876489
6488 log.debug("updating win32 resource: {s}", .{src_path});6490 log.debug("updating win32 resource: {s}", .{src_path});
64896491
6492 const io = comp.io;
6493
6490 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);6494 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
6491 defer arena_allocator.deinit();6495 defer arena_allocator.deinit();
6492 const arena = arena_allocator.allocator();6496 const arena = arena_allocator.allocator();
...@@ -6522,7 +6526,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6522,7 +6526,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
65226526
6523 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });6527 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });
6524 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});6528 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
6527 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{6531 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{
6528 o_sub_path, rc_basename,6532 o_sub_path, rc_basename,
...@@ -6610,7 +6614,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6610,7 +6614,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
66106614
6611 const digest = if (try man.hit()) man.final() else blk: {6615 const digest = if (try man.hit()) man.final() else blk: {
6612 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});6616 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
6615 const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext});6619 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...@@ -6681,7 +6685,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
6681 const digest = man.final();6685 const digest = man.final();
6682 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });6686 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
6683 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});6687 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
6684 defer o_dir.close();6688 defer o_dir.close(io);
6685 const tmp_basename = fs.path.basename(out_res_path);6689 const tmp_basename = fs.path.basename(out_res_path);
6686 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);6690 try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
6687 break :blk digest;6691 break :blk digest;
src/Package/Fetch.zig+38-34
...@@ -513,7 +513,7 @@ fn runResource(...@@ -513,7 +513,7 @@ fn runResource(
513 break :handle dir;513 break :handle dir;
514 },514 },
515 };515 };
516 defer tmp_directory.handle.close();516 defer tmp_directory.handle.close(io);
517517
518 // Fetch and unpack a resource into a temporary directory.518 // Fetch and unpack a resource into a temporary directory.
519 var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);519 var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);
...@@ -523,7 +523,7 @@ fn runResource(...@@ -523,7 +523,7 @@ fn runResource(
523 // Apply btrfs workaround if needed. Reopen tmp_directory.523 // Apply btrfs workaround if needed. Reopen tmp_directory.
524 if (native_os == .linux and f.job_queue.work_around_btrfs_bug) {524 if (native_os == .linux and f.job_queue.work_around_btrfs_bug) {
525 // https://github.com/ziglang/zig/issues/17095525 // https://github.com/ziglang/zig/issues/17095
526 pkg_path.root_dir.handle.close();526 pkg_path.root_dir.handle.close(io);
527 pkg_path.root_dir.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{527 pkg_path.root_dir.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{
528 .iterate = true,528 .iterate = true,
529 }) catch @panic("btrfs workaround failed");529 }) catch @panic("btrfs workaround failed");
...@@ -885,7 +885,7 @@ const Resource = union(enum) {...@@ -885,7 +885,7 @@ const Resource = union(enum) {
885 file: fs.File.Reader,885 file: fs.File.Reader,
886 http_request: HttpRequest,886 http_request: HttpRequest,
887 git: Git,887 git: Git,
888 dir: fs.Dir,888 dir: Io.Dir,
889889
890 const Git = struct {890 const Git = struct {
891 session: git.Session,891 session: git.Session,
...@@ -908,7 +908,7 @@ const Resource = union(enum) {...@@ -908,7 +908,7 @@ const Resource = union(enum) {
908 .git => |*git_resource| {908 .git => |*git_resource| {
909 git_resource.fetch_stream.deinit();909 git_resource.fetch_stream.deinit();
910 },910 },
911 .dir => |*dir| dir.close(),911 .dir => |*dir| dir.close(io),
912 }912 }
913 resource.* = undefined;913 resource.* = undefined;
914 }914 }
...@@ -1247,13 +1247,14 @@ fn unpackResource(...@@ -1247,13 +1247,14 @@ fn unpackResource(
1247 }1247 }
1248}1248}
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 {
1251 const eb = &f.error_bundle;1251 const eb = &f.error_bundle;
1252 const arena = f.arena.allocator();1252 const arena = f.arena.allocator();
1253 const io = f.job_queue.io;
12531254
1254 var diagnostics: std.tar.Diagnostics = .{ .allocator = arena };1255 var diagnostics: std.tar.Diagnostics = .{ .allocator = arena };
12551256
1256 std.tar.pipeToFileSystem(out_dir, reader, .{1257 std.tar.pipeToFileSystem(io, out_dir, reader, .{
1257 .diagnostics = &diagnostics,1258 .diagnostics = &diagnostics,
1258 .strip_components = 0,1259 .strip_components = 0,
1259 .mode_mode = .ignore,1260 .mode_mode = .ignore,
...@@ -1280,7 +1281,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *Io.Reader) RunError!Unpack...@@ -1280,7 +1281,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *Io.Reader) RunError!Unpack
12801281
1281fn unzip(1282fn unzip(
1282 f: *Fetch,1283 f: *Fetch,
1283 out_dir: fs.Dir,1284 out_dir: Io.Dir,
1284 reader: *Io.Reader,1285 reader: *Io.Reader,
1285) error{ ReadFailed, OutOfMemory, Canceled, FetchFailed }!UnpackResult {1286) error{ ReadFailed, OutOfMemory, Canceled, FetchFailed }!UnpackResult {
1286 // We write the entire contents to a file first because zip files1287 // We write the entire contents to a file first because zip files
...@@ -1314,7 +1315,7 @@ fn unzip(...@@ -1314,7 +1315,7 @@ fn unzip(
1314 ),1315 ),
1315 };1316 };
1316 };1317 };
1317 defer zip_file.close();1318 defer zip_file.close(io);
1318 var zip_file_buffer: [4096]u8 = undefined;1319 var zip_file_buffer: [4096]u8 = undefined;
1319 var zip_file_reader = b: {1320 var zip_file_reader = b: {
1320 var zip_file_writer = zip_file.writer(&zip_file_buffer);1321 var zip_file_writer = zip_file.writer(&zip_file_buffer);
...@@ -1349,7 +1350,7 @@ fn unzip(...@@ -1349,7 +1350,7 @@ fn unzip(
1349 return .{ .root_dir = diagnostics.root_dir };1350 return .{ .root_dir = diagnostics.root_dir };
1350}1351}
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 {
1353 const io = f.job_queue.io;1354 const io = f.job_queue.io;
1354 const arena = f.arena.allocator();1355 const arena = f.arena.allocator();
1355 // TODO don't try to get a gpa from an arena. expose this dependency higher up1356 // 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...@@ -1363,9 +1364,9 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
1363 // directory, since that isn't relevant for fetching a package.1364 // directory, since that isn't relevant for fetching a package.
1364 {1365 {
1365 var pack_dir = try out_dir.makeOpenPath(".git", .{});1366 var pack_dir = try out_dir.makeOpenPath(".git", .{});
1366 defer pack_dir.close();1367 defer pack_dir.close(io);
1367 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });1368 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
1368 defer pack_file.close();1369 defer pack_file.close(io);
1369 var pack_file_buffer: [4096]u8 = undefined;1370 var pack_file_buffer: [4096]u8 = undefined;
1370 var pack_file_reader = b: {1371 var pack_file_reader = b: {
1371 var pack_file_writer = pack_file.writer(&pack_file_buffer);1372 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...@@ -1376,7 +1377,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
1376 };1377 };
13771378
1378 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });1379 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
1379 defer index_file.close();1380 defer index_file.close(io);
1380 var index_file_buffer: [2000]u8 = undefined;1381 var index_file_buffer: [2000]u8 = undefined;
1381 var index_file_writer = index_file.writer(&index_file_buffer);1382 var index_file_writer = index_file.writer(&index_file_buffer);
1382 {1383 {
...@@ -1393,7 +1394,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U...@@ -1393,7 +1394,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
1393 try repository.init(gpa, object_format, &pack_file_reader, &index_file_reader);1394 try repository.init(gpa, object_format, &pack_file_reader, &index_file_reader);
1394 defer repository.deinit();1395 defer repository.deinit();
1395 var diagnostics: git.Diagnostics = .{ .allocator = arena };1396 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
1398 if (diagnostics.errors.items.len > 0) {1399 if (diagnostics.errors.items.len > 0) {
1399 try res.allocErrors(arena, diagnostics.errors.items.len, "unable to unpack packfile");1400 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...@@ -1411,7 +1412,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
1411 return res;1412 return res;
1412}1413}
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 {
1415 const gpa = f.arena.child_allocator;1416 const gpa = f.arena.child_allocator;
1416 // Recursive directory copy.1417 // Recursive directory copy.
1417 var it = try dir.walk(gpa);1418 var it = try dir.walk(gpa);
...@@ -1451,7 +1452,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void...@@ -1451,7 +1452,7 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void
1451 }1452 }
1452}1453}
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 {
1455 assert(dest_dir_sub_path[1] == fs.path.sep);1456 assert(dest_dir_sub_path[1] == fs.path.sep);
1456 var handled_missing_dir = false;1457 var handled_missing_dir = false;
1457 while (true) {1458 while (true) {
...@@ -1660,15 +1661,15 @@ fn dumpHashInfo(all_files: []const *const HashedFile) !void {...@@ -1660,15 +1661,15 @@ fn dumpHashInfo(all_files: []const *const HashedFile) !void {
1660 try w.flush();1661 try w.flush();
1661}1662}
16621663
1663fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile) void {1664fn workerHashFile(dir: Io.Dir, hashed_file: *HashedFile) void {
1664 hashed_file.failure = hashFileFallible(dir, hashed_file);1665 hashed_file.failure = hashFileFallible(dir, hashed_file);
1665}1666}
16661667
1667fn workerDeleteFile(dir: fs.Dir, deleted_file: *DeletedFile) void {1668fn workerDeleteFile(dir: Io.Dir, deleted_file: *DeletedFile) void {
1668 deleted_file.failure = deleteFileFallible(dir, deleted_file);1669 deleted_file.failure = deleteFileFallible(dir, deleted_file);
1669}1670}
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 {
1672 var buf: [8000]u8 = undefined;1673 var buf: [8000]u8 = undefined;
1673 var hasher = Package.Hash.Algo.init(.{});1674 var hasher = Package.Hash.Algo.init(.{});
1674 hasher.update(hashed_file.normalized_path);1675 hasher.update(hashed_file.normalized_path);
...@@ -1677,7 +1678,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void...@@ -1677,7 +1678,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
1677 switch (hashed_file.kind) {1678 switch (hashed_file.kind) {
1678 .file => {1679 .file => {
1679 var file = try dir.openFile(hashed_file.fs_path, .{});1680 var file = try dir.openFile(hashed_file.fs_path, .{});
1680 defer file.close();1681 defer file.close(io);
1681 // Hard-coded false executable bit: https://github.com/ziglang/zig/issues/174631682 // Hard-coded false executable bit: https://github.com/ziglang/zig/issues/17463
1682 hasher.update(&.{ 0, 0 });1683 hasher.update(&.{ 0, 0 });
1683 var file_header: FileHeader = .{};1684 var file_header: FileHeader = .{};
...@@ -1707,7 +1708,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void...@@ -1707,7 +1708,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
1707 hashed_file.size = file_size;1708 hashed_file.size = file_size;
1708}1709}
17091710
1710fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {1711fn deleteFileFallible(dir: Io.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {
1711 try dir.deleteFile(deleted_file.fs_path);1712 try dir.deleteFile(deleted_file.fs_path);
1712}1713}
17131714
...@@ -1724,8 +1725,8 @@ const DeletedFile = struct {...@@ -1724,8 +1725,8 @@ const DeletedFile = struct {
1724 failure: Error!void,1725 failure: Error!void,
17251726
1726 const Error =1727 const Error =
1727 fs.Dir.DeleteFileError ||1728 Io.Dir.DeleteFileError ||
1728 fs.Dir.DeleteDirError;1729 Io.Dir.DeleteDirError;
1729};1730};
17301731
1731const HashedFile = struct {1732const HashedFile = struct {
...@@ -1741,7 +1742,7 @@ const HashedFile = struct {...@@ -1741,7 +1742,7 @@ const HashedFile = struct {
1741 fs.File.ReadError ||1742 fs.File.ReadError ||
1742 fs.File.StatError ||1743 fs.File.StatError ||
1743 fs.File.ChmodError ||1744 fs.File.ChmodError ||
1744 fs.Dir.ReadLinkError;1745 Io.Dir.ReadLinkError;
17451746
1746 const Kind = enum { file, link };1747 const Kind = enum { file, link };
17471748
...@@ -2074,7 +2075,7 @@ test "tarball with duplicate paths" {...@@ -2074,7 +2075,7 @@ test "tarball with duplicate paths" {
2074 defer tmp.cleanup();2075 defer tmp.cleanup();
20752076
2076 const tarball_name = "duplicate_paths.tar.gz";2077 const tarball_name = "duplicate_paths.tar.gz";
2077 try saveEmbedFile(tarball_name, tmp.dir);2078 try saveEmbedFile(io, tarball_name, tmp.dir);
2078 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });2079 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2079 defer gpa.free(tarball_path);2080 defer gpa.free(tarball_path);
20802081
...@@ -2107,7 +2108,7 @@ test "tarball with excluded duplicate paths" {...@@ -2107,7 +2108,7 @@ test "tarball with excluded duplicate paths" {
2107 defer tmp.cleanup();2108 defer tmp.cleanup();
21082109
2109 const tarball_name = "duplicate_paths_excluded.tar.gz";2110 const tarball_name = "duplicate_paths_excluded.tar.gz";
2110 try saveEmbedFile(tarball_name, tmp.dir);2111 try saveEmbedFile(io, tarball_name, tmp.dir);
2111 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });2112 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2112 defer gpa.free(tarball_path);2113 defer gpa.free(tarball_path);
21132114
...@@ -2153,7 +2154,7 @@ test "tarball without root folder" {...@@ -2153,7 +2154,7 @@ test "tarball without root folder" {
2153 defer tmp.cleanup();2154 defer tmp.cleanup();
21542155
2155 const tarball_name = "no_root.tar.gz";2156 const tarball_name = "no_root.tar.gz";
2156 try saveEmbedFile(tarball_name, tmp.dir);2157 try saveEmbedFile(io, tarball_name, tmp.dir);
2157 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });2158 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2158 defer gpa.free(tarball_path);2159 defer gpa.free(tarball_path);
21592160
...@@ -2186,7 +2187,7 @@ test "set executable bit based on file content" {...@@ -2186,7 +2187,7 @@ test "set executable bit based on file content" {
2186 defer tmp.cleanup();2187 defer tmp.cleanup();
21872188
2188 const tarball_name = "executables.tar.gz";2189 const tarball_name = "executables.tar.gz";
2189 try saveEmbedFile(tarball_name, tmp.dir);2190 try saveEmbedFile(io, tarball_name, tmp.dir);
2190 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });2191 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2191 defer gpa.free(tarball_path);2192 defer gpa.free(tarball_path);
21922193
...@@ -2210,7 +2211,7 @@ test "set executable bit based on file content" {...@@ -2210,7 +2211,7 @@ test "set executable bit based on file content" {
2210 );2211 );
22112212
2212 var out = try fb.packageDir();2213 var out = try fb.packageDir();
2213 defer out.close();2214 defer out.close(io);
2214 const S = std.posix.S;2215 const S = std.posix.S;
2215 // expect executable bit not set2216 // expect executable bit not set
2216 try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0);2217 try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0);
...@@ -2231,11 +2232,11 @@ test "set executable bit based on file content" {...@@ -2231,11 +2232,11 @@ test "set executable bit based on file content" {
2231 // -rwxrwxr-x 1 17 Apr script_with_shebang_without_exec_bit2232 // -rwxrwxr-x 1 17 Apr script_with_shebang_without_exec_bit
2232}2233}
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 {
2235 //const tarball_name = "duplicate_paths_excluded.tar.gz";2236 //const tarball_name = "duplicate_paths_excluded.tar.gz";
2236 const tarball_content = @embedFile("Fetch/testdata/" ++ tarball_name);2237 const tarball_content = @embedFile("Fetch/testdata/" ++ tarball_name);
2237 var tmp_file = try dir.createFile(tarball_name, .{});2238 var tmp_file = try dir.createFile(tarball_name, .{});
2238 defer tmp_file.close();2239 defer tmp_file.close(io);
2239 try tmp_file.writeAll(tarball_content);2240 try tmp_file.writeAll(tarball_content);
2240}2241}
22412242
...@@ -2250,7 +2251,7 @@ const TestFetchBuilder = struct {...@@ -2250,7 +2251,7 @@ const TestFetchBuilder = struct {
2250 self: *TestFetchBuilder,2251 self: *TestFetchBuilder,
2251 allocator: std.mem.Allocator,2252 allocator: std.mem.Allocator,
2252 io: Io,2253 io: Io,
2253 cache_parent_dir: std.fs.Dir,2254 cache_parent_dir: std.Io.Dir,
2254 path_or_url: []const u8,2255 path_or_url: []const u8,
2255 ) !*Fetch {2256 ) !*Fetch {
2256 const cache_dir = try cache_parent_dir.makeOpenPath("zig-global-cache", .{});2257 const cache_dir = try cache_parent_dir.makeOpenPath("zig-global-cache", .{});
...@@ -2301,14 +2302,15 @@ const TestFetchBuilder = struct {...@@ -2301,14 +2302,15 @@ const TestFetchBuilder = struct {
2301 }2302 }
23022303
2303 fn deinit(self: *TestFetchBuilder) void {2304 fn deinit(self: *TestFetchBuilder) void {
2305 const io = self.job_queue.io;
2304 self.fetch.deinit();2306 self.fetch.deinit();
2305 self.job_queue.deinit();2307 self.job_queue.deinit();
2306 self.fetch.prog_node.end();2308 self.fetch.prog_node.end();
2307 self.global_cache_directory.handle.close();2309 self.global_cache_directory.handle.close(io);
2308 self.http_client.deinit();2310 self.http_client.deinit();
2309 }2311 }
23102312
2311 fn packageDir(self: *TestFetchBuilder) !fs.Dir {2313 fn packageDir(self: *TestFetchBuilder) !Io.Dir {
2312 const root = self.fetch.package_root;2314 const root = self.fetch.package_root;
2313 return try root.root_dir.handle.openDir(root.sub_path, .{ .iterate = true });2315 return try root.root_dir.handle.openDir(root.sub_path, .{ .iterate = true });
2314 }2316 }
...@@ -2316,8 +2318,10 @@ const TestFetchBuilder = struct {...@@ -2316,8 +2318,10 @@ const TestFetchBuilder = struct {
2316 // Test helper, asserts thet package dir constains expected_files.2318 // Test helper, asserts thet package dir constains expected_files.
2317 // expected_files must be sorted.2319 // expected_files must be sorted.
2318 fn expectPackageFiles(self: *TestFetchBuilder, expected_files: []const []const u8) !void {2320 fn expectPackageFiles(self: *TestFetchBuilder, expected_files: []const []const u8) !void {
2321 const io = self.job_queue.io;
2322
2319 var package_dir = try self.packageDir();2323 var package_dir = try self.packageDir();
2320 defer package_dir.close();2324 defer package_dir.close(io);
23212325
2322 var actual_files: std.ArrayList([]u8) = .empty;2326 var actual_files: std.ArrayList([]u8) = .empty;
2323 defer actual_files.deinit(std.testing.allocator);2327 defer actual_files.deinit(std.testing.allocator);
src/Package/Fetch/git.zig+14-12
...@@ -213,6 +213,7 @@ pub const Repository = struct {...@@ -213,6 +213,7 @@ pub const Repository = struct {
213 /// Checks out the repository at `commit_oid` to `worktree`.213 /// Checks out the repository at `commit_oid` to `worktree`.
214 pub fn checkout(214 pub fn checkout(
215 repository: *Repository,215 repository: *Repository,
216 io: Io,
216 worktree: std.fs.Dir,217 worktree: std.fs.Dir,
217 commit_oid: Oid,218 commit_oid: Oid,
218 diagnostics: *Diagnostics,219 diagnostics: *Diagnostics,
...@@ -223,12 +224,13 @@ pub const Repository = struct {...@@ -223,12 +224,13 @@ pub const Repository = struct {
223 if (commit_object.type != .commit) return error.NotACommit;224 if (commit_object.type != .commit) return error.NotACommit;
224 break :tree_oid try getCommitTree(repository.odb.format, commit_object.data);225 break :tree_oid try getCommitTree(repository.odb.format, commit_object.data);
225 };226 };
226 try repository.checkoutTree(worktree, tree_oid, "", diagnostics);227 try repository.checkoutTree(io, worktree, tree_oid, "", diagnostics);
227 }228 }
228229
229 /// Checks out the tree at `tree_oid` to `worktree`.230 /// Checks out the tree at `tree_oid` to `worktree`.
230 fn checkoutTree(231 fn checkoutTree(
231 repository: *Repository,232 repository: *Repository,
233 io: Io,
232 dir: std.fs.Dir,234 dir: std.fs.Dir,
233 tree_oid: Oid,235 tree_oid: Oid,
234 current_path: []const u8,236 current_path: []const u8,
...@@ -253,10 +255,10 @@ pub const Repository = struct {...@@ -253,10 +255,10 @@ pub const Repository = struct {
253 .directory => {255 .directory => {
254 try dir.makeDir(entry.name);256 try dir.makeDir(entry.name);
255 var subdir = try dir.openDir(entry.name, .{});257 var subdir = try dir.openDir(entry.name, .{});
256 defer subdir.close();258 defer subdir.close(io);
257 const sub_path = try std.fs.path.join(repository.odb.allocator, &.{ current_path, entry.name });259 const sub_path = try std.fs.path.join(repository.odb.allocator, &.{ current_path, entry.name });
258 defer repository.odb.allocator.free(sub_path);260 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);
260 },262 },
261 .file => {263 .file => {
262 try repository.odb.seekOid(entry.oid);264 try repository.odb.seekOid(entry.oid);
...@@ -271,7 +273,7 @@ pub const Repository = struct {...@@ -271,7 +273,7 @@ pub const Repository = struct {
271 } });273 } });
272 continue;274 continue;
273 };275 };
274 defer file.close();276 defer file.close(io);
275 try file.writeAll(file_object.data);277 try file.writeAll(file_object.data);
276 },278 },
277 .symlink => {279 .symlink => {
...@@ -1583,14 +1585,14 @@ fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u...@@ -1583,14 +1585,14 @@ fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u
1583 var git_dir = testing.tmpDir(.{});1585 var git_dir = testing.tmpDir(.{});
1584 defer git_dir.cleanup();1586 defer git_dir.cleanup();
1585 var pack_file = try git_dir.dir.createFile("testrepo.pack", .{ .read = true });1587 var pack_file = try git_dir.dir.createFile("testrepo.pack", .{ .read = true });
1586 defer pack_file.close();1588 defer pack_file.close(io);
1587 try pack_file.writeAll(testrepo_pack);1589 try pack_file.writeAll(testrepo_pack);
15881590
1589 var pack_file_buffer: [2000]u8 = undefined;1591 var pack_file_buffer: [2000]u8 = undefined;
1590 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);1592 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);
15911593
1592 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });1594 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
1593 defer index_file.close();1595 defer index_file.close(io);
1594 var index_file_buffer: [2000]u8 = undefined;1596 var index_file_buffer: [2000]u8 = undefined;
1595 var index_file_writer = index_file.writer(&index_file_buffer);1597 var index_file_writer = index_file.writer(&index_file_buffer);
1596 try indexPack(testing.allocator, format, &pack_file_reader, &index_file_writer);1598 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...@@ -1621,7 +1623,7 @@ fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u
16211623
1622 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1624 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1623 defer diagnostics.deinit();1625 defer diagnostics.deinit();
1624 try repository.checkout(worktree.dir, commit_id, &diagnostics);1626 try repository.checkout(io, worktree.dir, commit_id, &diagnostics);
1625 try testing.expect(diagnostics.errors.items.len == 0);1627 try testing.expect(diagnostics.errors.items.len == 0);
16261628
1627 const expected_files: []const []const u8 = &.{1629 const expected_files: []const []const u8 = &.{
...@@ -1713,20 +1715,20 @@ pub fn main() !void {...@@ -1713,20 +1715,20 @@ pub fn main() !void {
1713 const format = std.meta.stringToEnum(Oid.Format, args[1]) orelse return error.InvalidFormat;1715 const format = std.meta.stringToEnum(Oid.Format, args[1]) orelse return error.InvalidFormat;
17141716
1715 var pack_file = try std.fs.cwd().openFile(args[2], .{});1717 var pack_file = try std.fs.cwd().openFile(args[2], .{});
1716 defer pack_file.close();1718 defer pack_file.close(io);
1717 var pack_file_buffer: [4096]u8 = undefined;1719 var pack_file_buffer: [4096]u8 = undefined;
1718 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);1720 var pack_file_reader = pack_file.reader(io, &pack_file_buffer);
17191721
1720 const commit = try Oid.parse(format, args[3]);1722 const commit = try Oid.parse(format, args[3]);
1721 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});1723 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});
1722 defer worktree.close();1724 defer worktree.close(io);
17231725
1724 var git_dir = try worktree.makeOpenPath(".git", .{});1726 var git_dir = try worktree.makeOpenPath(".git", .{});
1725 defer git_dir.close();1727 defer git_dir.close(io);
17261728
1727 std.debug.print("Starting index...\n", .{});1729 std.debug.print("Starting index...\n", .{});
1728 var index_file = try git_dir.createFile("idx", .{ .read = true });1730 var index_file = try git_dir.createFile("idx", .{ .read = true });
1729 defer index_file.close();1731 defer index_file.close(io);
1730 var index_file_buffer: [4096]u8 = undefined;1732 var index_file_buffer: [4096]u8 = undefined;
1731 var index_file_writer = index_file.writer(&index_file_buffer);1733 var index_file_writer = index_file.writer(&index_file_buffer);
1732 try indexPack(allocator, format, &pack_file_reader, &index_file_writer);1734 try indexPack(allocator, format, &pack_file_reader, &index_file_writer);
...@@ -1738,7 +1740,7 @@ pub fn main() !void {...@@ -1738,7 +1740,7 @@ pub fn main() !void {
1738 defer repository.deinit();1740 defer repository.deinit();
1739 var diagnostics: Diagnostics = .{ .allocator = allocator };1741 var diagnostics: Diagnostics = .{ .allocator = allocator };
1740 defer diagnostics.deinit();1742 defer diagnostics.deinit();
1741 try repository.checkout(worktree, commit, &diagnostics);1743 try repository.checkout(io, worktree, commit, &diagnostics);
17421744
1743 for (diagnostics.errors.items) |err| {1745 for (diagnostics.errors.items) |err| {
1744 std.debug.print("Diagnostic: {}\n", .{err});1746 std.debug.print("Diagnostic: {}\n", .{err});
src/Zcu.zig+5-5
...@@ -1078,7 +1078,7 @@ pub const File = struct {...@@ -1078,7 +1078,7 @@ pub const File = struct {
1078 const dir, const sub_path = file.path.openInfo(zcu.comp.dirs);1078 const dir, const sub_path = file.path.openInfo(zcu.comp.dirs);
1079 break :f try dir.openFile(sub_path, .{});1079 break :f try dir.openFile(sub_path, .{});
1080 };1080 };
1081 defer f.close();1081 defer f.close(io);
10821082
1083 const stat = f.stat() catch |err| switch (err) {1083 const stat = f.stat() catch |err| switch (err) {
1084 error.Streaming => {1084 error.Streaming => {
...@@ -2813,8 +2813,8 @@ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {...@@ -2813,8 +2813,8 @@ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {
28132813
2814pub fn deinit(zcu: *Zcu) void {2814pub fn deinit(zcu: *Zcu) void {
2815 const comp = zcu.comp;2815 const comp = zcu.comp;
2816 const gpa = comp.gpa;
2817 const io = comp.io;2816 const io = comp.io;
2817 const gpa = zcu.gpa;
2818 {2818 {
2819 const pt: Zcu.PerThread = .activate(zcu, .main);2819 const pt: Zcu.PerThread = .activate(zcu, .main);
2820 defer pt.deactivate();2820 defer pt.deactivate();
...@@ -2835,8 +2835,8 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2835,8 +2835,8 @@ pub fn deinit(zcu: *Zcu) void {
2835 }2835 }
2836 zcu.embed_table.deinit(gpa);2836 zcu.embed_table.deinit(gpa);
28372837
2838 zcu.local_zir_cache.handle.close();2838 zcu.local_zir_cache.handle.close(io);
2839 zcu.global_zir_cache.handle.close();2839 zcu.global_zir_cache.handle.close(io);
28402840
2841 for (zcu.failed_analysis.values()) |value| value.destroy(gpa);2841 for (zcu.failed_analysis.values()) |value| value.destroy(gpa);
2842 for (zcu.failed_codegen.values()) |value| value.destroy(gpa);2842 for (zcu.failed_codegen.values()) |value| value.destroy(gpa);
...@@ -2900,7 +2900,7 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2900,7 +2900,7 @@ pub fn deinit(zcu: *Zcu) void {
29002900
2901 if (zcu.resolved_references) |*r| r.deinit(gpa);2901 if (zcu.resolved_references) |*r| r.deinit(gpa);
29022902
2903 if (zcu.comp.debugIncremental()) {2903 if (comp.debugIncremental()) {
2904 zcu.incremental_debug_state.deinit(gpa);2904 zcu.incremental_debug_state.deinit(gpa);
2905 }2905 }
2906 }2906 }
src/Zcu/PerThread.zig+3-3
...@@ -96,7 +96,7 @@ pub fn updateFile(...@@ -96,7 +96,7 @@ pub fn updateFile(
96 const dir, const sub_path = file.path.openInfo(comp.dirs);96 const dir, const sub_path = file.path.openInfo(comp.dirs);
97 break :f try dir.openFile(sub_path, .{});97 break :f try dir.openFile(sub_path, .{});
98 };98 };
99 defer source_file.close();99 defer source_file.close(io);
100100
101 const stat = try source_file.stat();101 const stat = try source_file.stat();
102102
...@@ -215,7 +215,7 @@ pub fn updateFile(...@@ -215,7 +215,7 @@ pub fn updateFile(
215 else => |e| return e, // Retryable errors are handled at callsite.215 else => |e| return e, // Retryable errors are handled at callsite.
216 };216 };
217 };217 };
218 defer cache_file.close();218 defer cache_file.close(io);
219219
220 // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers.220 // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers.
221 const ignore_hit = comp.time_report != null;221 const ignore_hit = comp.time_report != null;
...@@ -2468,7 +2468,7 @@ fn updateEmbedFileInner(...@@ -2468,7 +2468,7 @@ fn updateEmbedFileInner(
2468 const dir, const sub_path = ef.path.openInfo(zcu.comp.dirs);2468 const dir, const sub_path = ef.path.openInfo(zcu.comp.dirs);
2469 break :f try dir.openFile(sub_path, .{});2469 break :f try dir.openFile(sub_path, .{});
2470 };2470 };
2471 defer file.close();2471 defer file.close(io);
24722472
2473 const stat: Cache.File.Stat = .fromFs(try file.stat());2473 const stat: Cache.File.Stat = .fromFs(try file.stat());
24742474
src/codegen/llvm.zig+3-2
...@@ -799,6 +799,7 @@ pub const Object = struct {...@@ -799,6 +799,7 @@ pub const Object = struct {
799 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) error{ LinkFailure, OutOfMemory }!void {799 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) error{ LinkFailure, OutOfMemory }!void {
800 const zcu = pt.zcu;800 const zcu = pt.zcu;
801 const comp = zcu.comp;801 const comp = zcu.comp;
802 const io = comp.io;
802 const diags = &comp.link_diags;803 const diags = &comp.link_diags;
803804
804 {805 {
...@@ -979,7 +980,7 @@ pub const Object = struct {...@@ -979,7 +980,7 @@ pub const Object = struct {
979 if (options.pre_bc_path) |path| {980 if (options.pre_bc_path) |path| {
980 var file = std.fs.cwd().createFile(path, .{}) catch |err|981 var file = std.fs.cwd().createFile(path, .{}) catch |err|
981 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });982 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });
982 defer file.close();983 defer file.close(io);
983984
984 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);985 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
985 file.writeAll(ptr[0..(bitcode.len * 4)]) catch |err|986 file.writeAll(ptr[0..(bitcode.len * 4)]) catch |err|
...@@ -992,7 +993,7 @@ pub const Object = struct {...@@ -992,7 +993,7 @@ pub const Object = struct {
992 if (options.post_bc_path) |path| {993 if (options.post_bc_path) |path| {
993 var file = std.fs.cwd().createFile(path, .{}) catch |err|994 var file = std.fs.cwd().createFile(path, .{}) catch |err|
994 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });995 return diags.fail("failed to create '{s}': {s}", .{ path, @errorName(err) });
995 defer file.close();996 defer file.close(io);
996997
997 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);998 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
998 file.writeAll(ptr[0..(bitcode.len * 4)]) catch |err|999 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) !...@@ -187,7 +187,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
187 // On Windows, statFile does not work for directories187 // On Windows, statFile does not work for directories
188 error.IsDir => dir: {188 error.IsDir => dir: {
189 var dir = try fs.cwd().openDir(file_path, .{});189 var dir = try fs.cwd().openDir(file_path, .{});
190 defer dir.close();190 defer dir.close(io);
191 break :dir try dir.stat();191 break :dir try dir.stat();
192 },192 },
193 else => |e| return e,193 else => |e| return e,
...@@ -222,8 +222,10 @@ fn fmtPathDir(...@@ -222,8 +222,10 @@ fn fmtPathDir(
222 parent_dir: fs.Dir,222 parent_dir: fs.Dir,
223 parent_sub_path: []const u8,223 parent_sub_path: []const u8,
224) !void {224) !void {
225 const io = fmt.io;
226
225 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });227 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
226 defer dir.close();228 defer dir.close(io);
227229
228 const stat = try dir.stat();230 const stat = try dir.stat();
229 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;231 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
...@@ -262,7 +264,7 @@ fn fmtPathFile(...@@ -262,7 +264,7 @@ fn fmtPathFile(
262264
263 const source_file = try dir.openFile(sub_path, .{});265 const source_file = try dir.openFile(sub_path, .{});
264 var file_closed = false;266 var file_closed = false;
265 errdefer if (!file_closed) source_file.close();267 errdefer if (!file_closed) source_file.close(io);
266268
267 const stat = try source_file.stat();269 const stat = try source_file.stat();
268270
...@@ -280,7 +282,7 @@ fn fmtPathFile(...@@ -280,7 +282,7 @@ fn fmtPathFile(
280 };282 };
281 defer gpa.free(source_code);283 defer gpa.free(source_code);
282284
283 source_file.close();285 source_file.close(io);
284 file_closed = true;286 file_closed = true;
285287
286 // Add to set after no longer possible to get error.IsDir.288 // Add to set after no longer possible to get error.IsDir.
src/introspect.zig+16-12
...@@ -1,18 +1,21 @@...@@ -1,18 +1,21 @@
1const std = @import("std");
2const builtin = @import("builtin");1const builtin = @import("builtin");
2const build_options = @import("build_options");
3
4const std = @import("std");
5const Io = std.Io;
3const mem = std.mem;6const mem = std.mem;
4const Allocator = mem.Allocator;7const Allocator = std.mem.Allocator;
5const os = std.os;8const os = std.os;
6const fs = std.fs;9const fs = std.fs;
7const Cache = std.Build.Cache;10const Cache = std.Build.Cache;
11
8const Compilation = @import("Compilation.zig");12const Compilation = @import("Compilation.zig");
9const Package = @import("Package.zig");13const Package = @import("Package.zig");
10const build_options = @import("build_options");
1114
12/// Returns the sub_path that worked, or `null` if none did.15/// Returns the sub_path that worked, or `null` if none did.
13/// The path of the returned Directory is relative to `base`.16/// The path of the returned Directory is relative to `base`.
14/// The handle of the returned Directory is open.17/// 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 {
16 const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";19 const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";
1720
18 zig_dir: {21 zig_dir: {
...@@ -20,31 +23,31 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Cache.Directory {...@@ -20,31 +23,31 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Cache.Directory {
20 const lib_zig = "lib" ++ fs.path.sep_str ++ "zig";23 const lib_zig = "lib" ++ fs.path.sep_str ++ "zig";
21 var test_zig_dir = base_dir.openDir(lib_zig, .{}) catch break :zig_dir;24 var test_zig_dir = base_dir.openDir(lib_zig, .{}) catch break :zig_dir;
22 const file = test_zig_dir.openFile(test_index_file, .{}) catch {25 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
23 test_zig_dir.close();26 test_zig_dir.close(io);
24 break :zig_dir;27 break :zig_dir;
25 };28 };
26 file.close();29 file.close(io);
27 return .{ .handle = test_zig_dir, .path = lib_zig };30 return .{ .handle = test_zig_dir, .path = lib_zig };
28 }31 }
2932
30 // Try lib/std/std.zig33 // Try lib/std/std.zig
31 var test_zig_dir = base_dir.openDir("lib", .{}) catch return null;34 var test_zig_dir = base_dir.openDir("lib", .{}) catch return null;
32 const file = test_zig_dir.openFile(test_index_file, .{}) catch {35 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
33 test_zig_dir.close();36 test_zig_dir.close(io);
34 return null;37 return null;
35 };38 };
36 file.close();39 file.close(io);
37 return .{ .handle = test_zig_dir, .path = "lib" };40 return .{ .handle = test_zig_dir, .path = "lib" };
38}41}
3942
40/// Both the directory handle and the path are newly allocated resources which the caller now owns.43/// 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 {
42 const cwd_path = try getResolvedCwd(gpa);45 const cwd_path = try getResolvedCwd(gpa);
43 defer gpa.free(cwd_path);46 defer gpa.free(cwd_path);
44 const self_exe_path = try fs.selfExePathAlloc(gpa);47 const self_exe_path = try fs.selfExePathAlloc(gpa);
45 defer gpa.free(self_exe_path);48 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);
48}51}
4952
50/// Like `std.process.getCwdAlloc`, but also resolves the path with `std.fs.path.resolve`. This53/// 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{...@@ -73,6 +76,7 @@ pub fn getResolvedCwd(gpa: Allocator) error{
73/// Both the directory handle and the path are newly allocated resources which the caller now owns.76/// Both the directory handle and the path are newly allocated resources which the caller now owns.
74pub fn findZigLibDirFromSelfExe(77pub fn findZigLibDirFromSelfExe(
75 allocator: Allocator,78 allocator: Allocator,
79 io: Io,
76 /// The return value of `getResolvedCwd`.80 /// The return value of `getResolvedCwd`.
77 /// Passed as an argument to avoid pointlessly repeating the call.81 /// Passed as an argument to avoid pointlessly repeating the call.
78 cwd_path: []const u8,82 cwd_path: []const u8,
...@@ -82,9 +86,9 @@ pub fn findZigLibDirFromSelfExe(...@@ -82,9 +86,9 @@ pub fn findZigLibDirFromSelfExe(
82 var cur_path: []const u8 = self_exe_path;86 var cur_path: []const u8 = self_exe_path;
83 while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {87 while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {
84 var base_dir = cwd.openDir(dirname, .{}) catch continue;88 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;
88 const p = try fs.path.join(allocator, &.{ dirname, sub_directory.path.? });92 const p = try fs.path.join(allocator, &.{ dirname, sub_directory.path.? });
89 defer allocator.free(p);93 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...@@ -449,7 +449,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
449 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });449 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
450 cache.addPrefix(comp.dirs.zig_lib);450 cache.addPrefix(comp.dirs.zig_lib);
451 cache.addPrefix(comp.dirs.global_cache);451 cache.addPrefix(comp.dirs.global_cache);
452 defer cache.manifest_dir.close();452 defer cache.manifest_dir.close(io);
453453
454 var man = cache.obtain();454 var man = cache.obtain();
455 defer man.deinit();455 defer man.deinit();
...@@ -480,7 +480,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -480,7 +480,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
480 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),480 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
481 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),481 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
482 };482 };
483 defer o_directory.handle.close();483 defer o_directory.handle.close(io);
484484
485 const abilists_contents = man.files.keys()[abilists_index].contents.?;485 const abilists_contents = man.files.keys()[abilists_index].contents.?;
486 const metadata = try loadMetaData(gpa, abilists_contents);486 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...@@ -684,7 +684,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
684 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });684 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
685 cache.addPrefix(comp.dirs.zig_lib);685 cache.addPrefix(comp.dirs.zig_lib);
686 cache.addPrefix(comp.dirs.global_cache);686 cache.addPrefix(comp.dirs.global_cache);
687 defer cache.manifest_dir.close();687 defer cache.manifest_dir.close(io);
688688
689 var man = cache.obtain();689 var man = cache.obtain();
690 defer man.deinit();690 defer man.deinit();
...@@ -715,7 +715,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -715,7 +715,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
715 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),715 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
716 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),716 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
717 };717 };
718 defer o_directory.handle.close();718 defer o_directory.handle.close(io);
719719
720 const abilists_contents = man.files.keys()[abilists_index].contents.?;720 const abilists_contents = man.files.keys()[abilists_index].contents.?;
721 const metadata = try loadMetaData(gpa, abilists_contents);721 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 {...@@ -262,7 +262,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
262 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });262 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
263 cache.addPrefix(comp.dirs.zig_lib);263 cache.addPrefix(comp.dirs.zig_lib);
264 cache.addPrefix(comp.dirs.global_cache);264 cache.addPrefix(comp.dirs.global_cache);
265 defer cache.manifest_dir.close();265 defer cache.manifest_dir.close(io);
266266
267 cache.hash.addBytes(build_options.version);267 cache.hash.addBytes(build_options.version);
268 cache.hash.addOptionalBytes(comp.dirs.zig_lib.path);268 cache.hash.addOptionalBytes(comp.dirs.zig_lib.path);
...@@ -297,7 +297,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -297,7 +297,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
297 const digest = man.final();297 const digest = man.final();
298 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });298 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
299 var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});299 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
302 const aro = @import("aro");302 const aro = @import("aro");
303 var diagnostics: aro.Diagnostics = .{303 var diagnostics: aro.Diagnostics = .{
...@@ -377,7 +377,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -377,7 +377,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
377377
378 {378 {
379 const lib_final_file = try o_dir.createFile(final_lib_basename, .{ .truncate = true });379 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);
381 var buffer: [1024]u8 = undefined;381 var buffer: [1024]u8 = undefined;
382 var file_writer = lib_final_file.writer(&buffer);382 var file_writer = lib_final_file.writer(&buffer);
383 try implib.writeCoffArchive(gpa, &file_writer.interface, members);383 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...@@ -390,7 +390,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
390 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });390 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
391 cache.addPrefix(comp.dirs.zig_lib);391 cache.addPrefix(comp.dirs.zig_lib);
392 cache.addPrefix(comp.dirs.global_cache);392 cache.addPrefix(comp.dirs.global_cache);
393 defer cache.manifest_dir.close();393 defer cache.manifest_dir.close(io);
394394
395 var man = cache.obtain();395 var man = cache.obtain();
396 defer man.deinit();396 defer man.deinit();
...@@ -421,7 +421,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -421,7 +421,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
421 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),421 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
422 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),422 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
423 };423 };
424 defer o_directory.handle.close();424 defer o_directory.handle.close(io);
425425
426 const abilists_contents = man.files.keys()[abilists_index].contents.?;426 const abilists_contents = man.files.keys()[abilists_index].contents.?;
427 const metadata = try loadMetaData(gpa, abilists_contents);427 const metadata = try loadMetaData(gpa, abilists_contents);
src/link.zig+49-34
...@@ -687,7 +687,7 @@ pub const File = struct {...@@ -687,7 +687,7 @@ pub const File = struct {
687 .lld => assert(base.file == null),687 .lld => assert(base.file == null),
688 .elf => if (base.file) |f| {688 .elf => if (base.file) |f| {
689 dev.check(.elf_linker);689 dev.check(.elf_linker);
690 f.close();690 f.close(io);
691 base.file = null;691 base.file = null;
692692
693 if (base.child_pid) |pid| {693 if (base.child_pid) |pid| {
...@@ -701,7 +701,7 @@ pub const File = struct {...@@ -701,7 +701,7 @@ pub const File = struct {
701 },701 },
702 .macho, .wasm => if (base.file) |f| {702 .macho, .wasm => if (base.file) |f| {
703 dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });703 dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
704 f.close();704 f.close(io);
705 base.file = null;705 base.file = null;
706706
707 if (base.child_pid) |pid| {707 if (base.child_pid) |pid| {
...@@ -866,8 +866,9 @@ pub const File = struct {...@@ -866,8 +866,9 @@ pub const File = struct {
866 }866 }
867867
868 pub fn destroy(base: *File) void {868 pub fn destroy(base: *File) void {
869 const io = base.comp.io;
869 base.releaseLock();870 base.releaseLock();
870 if (base.file) |f| f.close();871 if (base.file) |f| f.close(io);
871 switch (base.tag) {872 switch (base.tag) {
872 .plan9 => unreachable,873 .plan9 => unreachable,
873 inline else => |tag| {874 inline else => |tag| {
...@@ -1060,9 +1061,10 @@ pub const File = struct {...@@ -1060,9 +1061,10 @@ pub const File = struct {
1060 /// Opens a path as an object file and parses it into the linker.1061 /// Opens a path as an object file and parses it into the linker.
1061 fn openLoadObject(base: *File, path: Path) anyerror!void {1062 fn openLoadObject(base: *File, path: Path) anyerror!void {
1062 if (base.tag == .lld) return;1063 if (base.tag == .lld) return;
1064 const io = base.comp.io;
1063 const diags = &base.comp.link_diags;1065 const diags = &base.comp.link_diags;
1064 const input = try openObjectInput(diags, path);1066 const input = try openObjectInput(io, diags, path);
1065 errdefer input.object.file.close();1067 errdefer input.object.file.close(io);
1066 try loadInput(base, input);1068 try loadInput(base, input);
1067 }1069 }
10681070
...@@ -1070,21 +1072,22 @@ pub const File = struct {...@@ -1070,21 +1072,22 @@ pub const File = struct {
1070 /// If `query` is non-null, allows GNU ld scripts.1072 /// If `query` is non-null, allows GNU ld scripts.
1071 fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void {1073 fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void {
1072 if (base.tag == .lld) return;1074 if (base.tag == .lld) return;
1075 const io = base.comp.io;
1073 if (opt_query) |query| {1076 if (opt_query) |query| {
1074 const archive = try openObject(path, query.must_link, query.hidden);1077 const archive = try openObject(io, path, query.must_link, query.hidden);
1075 errdefer archive.file.close();1078 errdefer archive.file.close(io);
1076 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {1079 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
1077 error.BadMagic, error.UnexpectedEndOfFile => {1080 error.BadMagic, error.UnexpectedEndOfFile => {
1078 if (base.tag != .elf and base.tag != .elf2) return err;1081 if (base.tag != .elf and base.tag != .elf2) return err;
1079 try loadGnuLdScript(base, path, query, archive.file);1082 try loadGnuLdScript(base, path, query, archive.file);
1080 archive.file.close();1083 archive.file.close(io);
1081 return;1084 return;
1082 },1085 },
1083 else => return err,1086 else => return err,
1084 };1087 };
1085 } else {1088 } else {
1086 const archive = try openObject(path, false, false);1089 const archive = try openObject(io, path, false, false);
1087 errdefer archive.file.close();1090 errdefer archive.file.close(io);
1088 try loadInput(base, .{ .archive = archive });1091 try loadInput(base, .{ .archive = archive });
1089 }1092 }
1090 }1093 }
...@@ -1093,13 +1096,14 @@ pub const File = struct {...@@ -1093,13 +1096,14 @@ pub const File = struct {
1093 /// Handles GNU ld scripts.1096 /// Handles GNU ld scripts.
1094 fn openLoadDso(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void {1097 fn openLoadDso(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void {
1095 if (base.tag == .lld) return;1098 if (base.tag == .lld) return;
1096 const dso = try openDso(path, query.needed, query.weak, query.reexport);1099 const io = base.comp.io;
1097 errdefer dso.file.close();1100 const dso = try openDso(io, path, query.needed, query.weak, query.reexport);
1101 errdefer dso.file.close(io);
1098 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {1102 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {
1099 error.BadMagic, error.UnexpectedEndOfFile => {1103 error.BadMagic, error.UnexpectedEndOfFile => {
1100 if (base.tag != .elf and base.tag != .elf2) return err;1104 if (base.tag != .elf and base.tag != .elf2) return err;
1101 try loadGnuLdScript(base, path, query, dso.file);1105 try loadGnuLdScript(base, path, query, dso.file);
1102 dso.file.close();1106 dso.file.close(io);
1103 return;1107 return;
1104 },1108 },
1105 else => return err,1109 else => return err,
...@@ -1735,6 +1739,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {...@@ -1735,6 +1739,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
1735pub fn resolveInputs(1739pub fn resolveInputs(
1736 gpa: Allocator,1740 gpa: Allocator,
1737 arena: Allocator,1741 arena: Allocator,
1742 io: Io,
1738 target: *const std.Target,1743 target: *const std.Target,
1739 /// This function mutates this array but does not take ownership.1744 /// This function mutates this array but does not take ownership.
1740 /// Allocated with `gpa`.1745 /// Allocated with `gpa`.
...@@ -1784,6 +1789,7 @@ pub fn resolveInputs(...@@ -1784,6 +1789,7 @@ pub fn resolveInputs(
1784 for (lib_directories) |lib_directory| switch (try resolveLibInput(1789 for (lib_directories) |lib_directory| switch (try resolveLibInput(
1785 gpa,1790 gpa,
1786 arena,1791 arena,
1792 io,
1787 unresolved_inputs,1793 unresolved_inputs,
1788 resolved_inputs,1794 resolved_inputs,
1789 &checked_paths,1795 &checked_paths,
...@@ -1810,6 +1816,7 @@ pub fn resolveInputs(...@@ -1810,6 +1816,7 @@ pub fn resolveInputs(
1810 for (lib_directories) |lib_directory| switch (try resolveLibInput(1816 for (lib_directories) |lib_directory| switch (try resolveLibInput(
1811 gpa,1817 gpa,
1812 arena,1818 arena,
1819 io,
1813 unresolved_inputs,1820 unresolved_inputs,
1814 resolved_inputs,1821 resolved_inputs,
1815 &checked_paths,1822 &checked_paths,
...@@ -1837,6 +1844,7 @@ pub fn resolveInputs(...@@ -1837,6 +1844,7 @@ pub fn resolveInputs(
1837 switch (try resolveLibInput(1844 switch (try resolveLibInput(
1838 gpa,1845 gpa,
1839 arena,1846 arena,
1847 io,
1840 unresolved_inputs,1848 unresolved_inputs,
1841 resolved_inputs,1849 resolved_inputs,
1842 &checked_paths,1850 &checked_paths,
...@@ -1855,6 +1863,7 @@ pub fn resolveInputs(...@@ -1855,6 +1863,7 @@ pub fn resolveInputs(
1855 switch (try resolveLibInput(1863 switch (try resolveLibInput(
1856 gpa,1864 gpa,
1857 arena,1865 arena,
1866 io,
1858 unresolved_inputs,1867 unresolved_inputs,
1859 resolved_inputs,1868 resolved_inputs,
1860 &checked_paths,1869 &checked_paths,
...@@ -1886,6 +1895,7 @@ pub fn resolveInputs(...@@ -1886,6 +1895,7 @@ pub fn resolveInputs(
1886 if (try resolvePathInput(1895 if (try resolvePathInput(
1887 gpa,1896 gpa,
1888 arena,1897 arena,
1898 io,
1889 unresolved_inputs,1899 unresolved_inputs,
1890 resolved_inputs,1900 resolved_inputs,
1891 &ld_script_bytes,1901 &ld_script_bytes,
...@@ -1903,6 +1913,7 @@ pub fn resolveInputs(...@@ -1903,6 +1913,7 @@ pub fn resolveInputs(
1903 switch ((try resolvePathInput(1913 switch ((try resolvePathInput(
1904 gpa,1914 gpa,
1905 arena,1915 arena,
1916 io,
1906 unresolved_inputs,1917 unresolved_inputs,
1907 resolved_inputs,1918 resolved_inputs,
1908 &ld_script_bytes,1919 &ld_script_bytes,
...@@ -1930,6 +1941,7 @@ pub fn resolveInputs(...@@ -1930,6 +1941,7 @@ pub fn resolveInputs(
1930 if (try resolvePathInput(1941 if (try resolvePathInput(
1931 gpa,1942 gpa,
1932 arena,1943 arena,
1944 io,
1933 unresolved_inputs,1945 unresolved_inputs,
1934 resolved_inputs,1946 resolved_inputs,
1935 &ld_script_bytes,1947 &ld_script_bytes,
...@@ -1969,6 +1981,7 @@ const fatal = std.process.fatal;...@@ -1969,6 +1981,7 @@ const fatal = std.process.fatal;
1969fn resolveLibInput(1981fn resolveLibInput(
1970 gpa: Allocator,1982 gpa: Allocator,
1971 arena: Allocator,1983 arena: Allocator,
1984 io: Io,
1972 /// Allocated via `gpa`.1985 /// Allocated via `gpa`.
1973 unresolved_inputs: *std.ArrayList(UnresolvedInput),1986 unresolved_inputs: *std.ArrayList(UnresolvedInput),
1974 /// Allocated via `gpa`.1987 /// Allocated via `gpa`.
...@@ -1998,7 +2011,7 @@ fn resolveLibInput(...@@ -1998,7 +2011,7 @@ fn resolveLibInput(
1998 error.FileNotFound => break :tbd,2011 error.FileNotFound => break :tbd,
1999 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),2012 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),
2000 };2013 };
2001 errdefer file.close();2014 errdefer file.close(io);
2002 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);2015 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2003 }2016 }
20042017
...@@ -2013,7 +2026,7 @@ fn resolveLibInput(...@@ -2013,7 +2026,7 @@ fn resolveLibInput(
2013 }),2026 }),
2014 };2027 };
2015 try checked_paths.print(gpa, "\n {f}", .{test_path});2028 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, .{
2017 .path = test_path,2030 .path = test_path,
2018 .query = name_query.query,2031 .query = name_query.query,
2019 }, link_mode, color)) {2032 }, link_mode, color)) {
...@@ -2036,7 +2049,7 @@ fn resolveLibInput(...@@ -2036,7 +2049,7 @@ fn resolveLibInput(
2036 test_path, @errorName(e),2049 test_path, @errorName(e),
2037 }),2050 }),
2038 };2051 };
2039 errdefer file.close();2052 errdefer file.close(io);
2040 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);2053 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2041 }2054 }
20422055
...@@ -2052,7 +2065,7 @@ fn resolveLibInput(...@@ -2052,7 +2065,7 @@ fn resolveLibInput(
2052 error.FileNotFound => break :mingw,2065 error.FileNotFound => break :mingw,
2053 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),2066 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),
2054 };2067 };
2055 errdefer file.close();2068 errdefer file.close(io);
2056 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);2069 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2057 }2070 }
20582071
...@@ -2087,6 +2100,7 @@ fn finishResolveLibInput(...@@ -2087,6 +2100,7 @@ fn finishResolveLibInput(
2087fn resolvePathInput(2100fn resolvePathInput(
2088 gpa: Allocator,2101 gpa: Allocator,
2089 arena: Allocator,2102 arena: Allocator,
2103 io: Io,
2090 /// Allocated with `gpa`.2104 /// Allocated with `gpa`.
2091 unresolved_inputs: *std.ArrayList(UnresolvedInput),2105 unresolved_inputs: *std.ArrayList(UnresolvedInput),
2092 /// Allocated with `gpa`.2106 /// Allocated with `gpa`.
...@@ -2098,12 +2112,12 @@ fn resolvePathInput(...@@ -2098,12 +2112,12 @@ fn resolvePathInput(
2098 color: std.zig.Color,2112 color: std.zig.Color,
2099) Allocator.Error!?ResolveLibInputResult {2113) Allocator.Error!?ResolveLibInputResult {
2100 switch (Compilation.classifyFileExt(pq.path.sub_path)) {2114 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),2115 .static_library => return try resolvePathInputLib(gpa, arena, io, 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),2116 .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
2103 .object => {2117 .object => {
2104 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|2118 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
2105 fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) });2119 fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) });
2106 errdefer file.close();2120 errdefer file.close(io);
2107 try resolved_inputs.append(gpa, .{ .object = .{2121 try resolved_inputs.append(gpa, .{ .object = .{
2108 .path = pq.path,2122 .path = pq.path,
2109 .file = file,2123 .file = file,
...@@ -2115,7 +2129,7 @@ fn resolvePathInput(...@@ -2115,7 +2129,7 @@ fn resolvePathInput(
2115 .res => {2129 .res => {
2116 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|2130 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
2117 fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) });2131 fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) });
2118 errdefer file.close();2132 errdefer file.close(io);
2119 try resolved_inputs.append(gpa, .{ .res = .{2133 try resolved_inputs.append(gpa, .{ .res = .{
2120 .path = pq.path,2134 .path = pq.path,
2121 .file = file,2135 .file = file,
...@@ -2129,6 +2143,7 @@ fn resolvePathInput(...@@ -2129,6 +2143,7 @@ fn resolvePathInput(
2129fn resolvePathInputLib(2143fn resolvePathInputLib(
2130 gpa: Allocator,2144 gpa: Allocator,
2131 arena: Allocator,2145 arena: Allocator,
2146 io: Io,
2132 /// Allocated with `gpa`.2147 /// Allocated with `gpa`.
2133 unresolved_inputs: *std.ArrayList(UnresolvedInput),2148 unresolved_inputs: *std.ArrayList(UnresolvedInput),
2134 /// Allocated with `gpa`.2149 /// Allocated with `gpa`.
...@@ -2155,7 +2170,7 @@ fn resolvePathInputLib(...@@ -2155,7 +2170,7 @@ fn resolvePathInputLib(
2155 @tagName(link_mode), std.fmt.alt(test_path, .formatEscapeChar), @errorName(e),2170 @tagName(link_mode), std.fmt.alt(test_path, .formatEscapeChar), @errorName(e),
2156 }),2171 }),
2157 };2172 };
2158 errdefer file.close();2173 errdefer file.close(io);
2159 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));2174 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));
2160 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f}': {s}", .{2175 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f}': {s}", .{
2161 std.fmt.alt(test_path, .formatEscapeChar), @errorName(err),2176 std.fmt.alt(test_path, .formatEscapeChar), @errorName(err),
...@@ -2223,7 +2238,7 @@ fn resolvePathInputLib(...@@ -2223,7 +2238,7 @@ fn resolvePathInputLib(
2223 } });2238 } });
2224 }2239 }
2225 }2240 }
2226 file.close();2241 file.close(io);
2227 return .ok;2242 return .ok;
2228 }2243 }
22292244
...@@ -2233,13 +2248,13 @@ fn resolvePathInputLib(...@@ -2233,13 +2248,13 @@ fn resolvePathInputLib(
2233 @tagName(link_mode), test_path, @errorName(e),2248 @tagName(link_mode), test_path, @errorName(e),
2234 }),2249 }),
2235 };2250 };
2236 errdefer file.close();2251 errdefer file.close(io);
2237 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);2252 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2238}2253}
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 {
2241 var file = try path.root_dir.handle.openFile(path.sub_path, .{});2256 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
2242 errdefer file.close();2257 errdefer file.close(io);
2243 return .{2258 return .{
2244 .path = path,2259 .path = path,
2245 .file = file,2260 .file = file,
...@@ -2248,9 +2263,9 @@ pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {...@@ -2248,9 +2263,9 @@ pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
2248 };2263 };
2249}2264}
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 {
2252 var file = try path.root_dir.handle.openFile(path.sub_path, .{});2267 var file = try path.root_dir.handle.openFile(path.sub_path, .{});
2253 errdefer file.close();2268 errdefer file.close(io);
2254 return .{2269 return .{
2255 .path = path,2270 .path = path,
2256 .file = file,2271 .file = file,
...@@ -2260,20 +2275,20 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso...@@ -2260,20 +2275,20 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
2260 };2275 };
2261}2276}
22622277
2263pub fn openObjectInput(diags: *Diags, path: Path) error{LinkFailure}!Input {2278pub fn openObjectInput(io: Io, diags: *Diags, path: Path) error{LinkFailure}!Input {
2264 return .{ .object = openObject(path, false, false) catch |err| {2279 return .{ .object = openObject(io, path, false, false) catch |err| {
2265 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });2280 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
2266 } };2281 } };
2267}2282}
22682283
2269pub fn openArchiveInput(diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input {2284pub fn openArchiveInput(io: Io, diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input {
2270 return .{ .archive = openObject(path, must_link, hidden) catch |err| {2285 return .{ .archive = openObject(io, path, must_link, hidden) catch |err| {
2271 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });2286 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
2272 } };2287 } };
2273}2288}
22742289
2275pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input {2290pub fn openDsoInput(io: Io, diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input {
2276 return .{ .dso = openDso(path, needed, weak, reexport) catch |err| {2291 return .{ .dso = openDso(io, path, needed, weak, reexport) catch |err| {
2277 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });2292 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
2278 } };2293 } };
2279}2294}
src/link/C.zig+4-2
...@@ -124,6 +124,7 @@ pub fn createEmpty(...@@ -124,6 +124,7 @@ pub fn createEmpty(
124 emit: Path,124 emit: Path,
125 options: link.File.OpenOptions,125 options: link.File.OpenOptions,
126) !*C {126) !*C {
127 const io = comp.io;
127 const target = &comp.root_mod.resolved_target.result;128 const target = &comp.root_mod.resolved_target.result;
128 assert(target.ofmt == .c);129 assert(target.ofmt == .c);
129 const optimize_mode = comp.root_mod.optimize_mode;130 const optimize_mode = comp.root_mod.optimize_mode;
...@@ -139,7 +140,7 @@ pub fn createEmpty(...@@ -139,7 +140,7 @@ pub fn createEmpty(
139 // Truncation is done on `flush`.140 // Truncation is done on `flush`.
140 .truncate = false,141 .truncate = false,
141 });142 });
142 errdefer file.close();143 errdefer file.close(io);
143144
144 const c_file = try arena.create(C);145 const c_file = try arena.create(C);
145146
...@@ -763,6 +764,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {...@@ -763,6 +764,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {
763 if (true) return; // emit-h is regressed764 if (true) return; // emit-h is regressed
764765
765 const emit_h = zcu.emit_h orelse return;766 const emit_h = zcu.emit_h orelse return;
767 const io = zcu.comp.io;
766768
767 // We collect a list of buffers to write, and write them all at once with pwritev 😎769 // We collect a list of buffers to write, and write them all at once with pwritev 😎
768 const num_buffers = emit_h.decl_table.count() + 1;770 const num_buffers = emit_h.decl_table.count() + 1;
...@@ -795,7 +797,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {...@@ -795,7 +797,7 @@ pub fn flushEmitH(zcu: *Zcu) !void {
795 // make it easier on the file system by doing 1 reallocation instead of two.797 // make it easier on the file system by doing 1 reallocation instead of two.
796 .truncate = false,798 .truncate = false,
797 });799 });
798 defer file.close();800 defer file.close(io);
799801
800 try file.setEndPos(file_size);802 try file.setEndPos(file_size);
801 try file.pwritevAll(all_buffers.items, 0);803 try file.pwritevAll(all_buffers.items, 0);
src/link/Elf.zig+4-2
...@@ -406,10 +406,12 @@ pub fn open(...@@ -406,10 +406,12 @@ pub fn open(
406}406}
407407
408pub fn deinit(self: *Elf) void {408pub 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
411 for (self.file_handles.items) |fh| {413 for (self.file_handles.items) |fh| {
412 fh.close();414 fh.close(io);
413 }415 }
414 self.file_handles.deinit(gpa);416 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...@@ -1628,7 +1628,7 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
1628 defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err|1628 defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err|
1629 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });1629 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });
1630 {1630 {
1631 defer rsp_file.close();1631 defer rsp_file.close(io);
1632 var rsp_file_buffer: [1024]u8 = undefined;1632 var rsp_file_buffer: [1024]u8 = undefined;
1633 var rsp_file_writer = rsp_file.writer(&rsp_file_buffer);1633 var rsp_file_writer = rsp_file.writer(&rsp_file_buffer);
1634 const rsp_writer = &rsp_file_writer.interface;1634 const rsp_writer = &rsp_file_writer.interface;
src/link/MachO.zig+11-5
...@@ -267,14 +267,16 @@ pub fn open(...@@ -267,14 +267,16 @@ pub fn open(
267}267}
268268
269pub fn deinit(self: *MachO) void {269pub 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
272 if (self.d_sym) |*d_sym| {274 if (self.d_sym) |*d_sym| {
273 d_sym.deinit();275 d_sym.deinit();
274 }276 }
275277
276 for (self.file_handles.items) |handle| {278 for (self.file_handles.items) |handle| {
277 handle.close();279 handle.close(io);
278 }280 }
279 self.file_handles.deinit(gpa);281 self.file_handles.deinit(gpa);
280282
...@@ -3257,8 +3259,10 @@ const InitMetadataOptions = struct {...@@ -3257,8 +3259,10 @@ const InitMetadataOptions = struct {
3257};3259};
32583260
3259pub fn closeDebugInfo(self: *MachO) bool {3261pub fn closeDebugInfo(self: *MachO) bool {
3262 const comp = self.base.comp;
3263 const io = comp.io;
3260 const d_sym = &(self.d_sym orelse return false);3264 const d_sym = &(self.d_sym orelse return false);
3261 d_sym.file.?.close();3265 d_sym.file.?.close(io);
3262 d_sym.file = null;3266 d_sym.file = null;
3263 return true;3267 return true;
3264}3268}
...@@ -3269,7 +3273,9 @@ pub fn reopenDebugInfo(self: *MachO) !void {...@@ -3269,7 +3273,9 @@ pub fn reopenDebugInfo(self: *MachO) !void {
3269 assert(!self.base.comp.config.use_llvm);3273 assert(!self.base.comp.config.use_llvm);
3270 assert(self.base.comp.config.debug_format == .dwarf);3274 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;
3273 const sep = fs.path.sep_str;3279 const sep = fs.path.sep_str;
3274 const d_sym_path = try std.fmt.allocPrint(3280 const d_sym_path = try std.fmt.allocPrint(
3275 gpa,3281 gpa,
...@@ -3279,7 +3285,7 @@ pub fn reopenDebugInfo(self: *MachO) !void {...@@ -3279,7 +3285,7 @@ pub fn reopenDebugInfo(self: *MachO) !void {
3279 defer gpa.free(d_sym_path);3285 defer gpa.free(d_sym_path);
32803286
3281 var d_sym_bundle = try self.base.emit.root_dir.handle.makeOpenPath(d_sym_path, .{});3287 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
3284 self.d_sym.?.file = try d_sym_bundle.createFile(fs.path.basename(self.base.emit.sub_path), .{3290 self.d_sym.?.file = try d_sym_bundle.createFile(fs.path.basename(self.base.emit.sub_path), .{
3285 .truncate = false,3291 .truncate = false,
src/link/MachO/DebugSymbols.zig+26-24
...@@ -1,5 +1,28 @@...@@ -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,
1allocator: Allocator,24allocator: Allocator,
2file: ?fs.File,25file: ?Io.File,
326
4symtab_cmd: macho.symtab_command = .{},27symtab_cmd: macho.symtab_command = .{},
5uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },28uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
...@@ -208,7 +231,8 @@ pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -208,7 +231,8 @@ pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void {
208231
209pub fn deinit(self: *DebugSymbols) void {232pub fn deinit(self: *DebugSymbols) void {
210 const gpa = self.allocator;233 const gpa = self.allocator;
211 if (self.file) |file| file.close();234 const io = self.io;
235 if (self.file) |file| file.close(io);
212 self.segments.deinit(gpa);236 self.segments.deinit(gpa);
213 self.sections.deinit(gpa);237 self.sections.deinit(gpa);
214 self.relocs.deinit(gpa);238 self.relocs.deinit(gpa);
...@@ -443,25 +467,3 @@ pub fn getSection(self: DebugSymbols, sect: u8) macho.section_64 {...@@ -443,25 +467,3 @@ pub fn getSection(self: DebugSymbols, sect: u8) macho.section_64 {
443 assert(sect < self.sections.items.len);467 assert(sect < self.sections.items.len);
444 return self.sections.items[sect];468 return self.sections.items[sect];
445}469}
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 {...@@ -3032,7 +3032,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
3032 const io = wasm.base.comp.io;3032 const io = wasm.base.comp.io;
3033 const gc_sections = wasm.base.gc_sections;3033 const gc_sections = wasm.base.gc_sections;
30343034
3035 defer obj.file.close();3035 defer obj.file.close(io);
30363036
3037 var file_reader = obj.file.reader(io, &.{});3037 var file_reader = obj.file.reader(io, &.{});
30383038
...@@ -3060,7 +3060,7 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {...@@ -3060,7 +3060,7 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {
3060 const io = wasm.base.comp.io;3060 const io = wasm.base.comp.io;
3061 const gc_sections = wasm.base.gc_sections;3061 const gc_sections = wasm.base.gc_sections;
30623062
3063 defer obj.file.close();3063 defer obj.file.close(io);
30643064
3065 var file_reader = obj.file.reader(io, &.{});3065 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 {...@@ -328,21 +328,21 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
328 .prepend_global_cache_path = true,328 .prepend_global_cache_path = true,
329 });329 });
330 } else if (mem.eql(u8, cmd, "init")) {330 } else if (mem.eql(u8, cmd, "init")) {
331 return cmdInit(gpa, arena, cmd_args);331 return cmdInit(gpa, arena, io, cmd_args);
332 } else if (mem.eql(u8, cmd, "targets")) {332 } else if (mem.eql(u8, cmd, "targets")) {
333 dev.check(.targets_command);333 dev.check(.targets_command);
334 const host = std.zig.resolveTargetQueryOrFatal(io, .{});334 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
335 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);335 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
336 try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host);336 try @import("print_targets.zig").cmdTargets(arena, io, cmd_args, &stdout_writer.interface, &host);
337 return stdout_writer.interface.flush();337 return stdout_writer.interface.flush();
338 } else if (mem.eql(u8, cmd, "version")) {338 } else if (mem.eql(u8, cmd, "version")) {
339 dev.check(.version_command);339 dev.check(.version_command);
340 try fs.File.stdout().writeAll(build_options.version ++ "\n");340 try Io.File.stdout().writeAll(build_options.version ++ "\n");
341 return;341 return;
342 } else if (mem.eql(u8, cmd, "env")) {342 } else if (mem.eql(u8, cmd, "env")) {
343 dev.check(.env_command);343 dev.check(.env_command);
344 const host = std.zig.resolveTargetQueryOrFatal(io, .{});344 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);
346 try @import("print_env.zig").cmdEnv(346 try @import("print_env.zig").cmdEnv(
347 arena,347 arena,
348 &stdout_writer.interface,348 &stdout_writer.interface,
...@@ -358,10 +358,10 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -358,10 +358,10 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
358 });358 });
359 } else if (mem.eql(u8, cmd, "zen")) {359 } else if (mem.eql(u8, cmd, "zen")) {
360 dev.check(.zen_command);360 dev.check(.zen_command);
361 return fs.File.stdout().writeAll(info_zen);361 return Io.File.stdout().writeAll(info_zen);
362 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {362 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
363 dev.check(.help_command);363 dev.check(.help_command);
364 return fs.File.stdout().writeAll(usage);364 return Io.File.stdout().writeAll(usage);
365 } else if (mem.eql(u8, cmd, "ast-check")) {365 } else if (mem.eql(u8, cmd, "ast-check")) {
366 return cmdAstCheck(arena, io, cmd_args);366 return cmdAstCheck(arena, io, cmd_args);
367 } else if (mem.eql(u8, cmd, "detect-cpu")) {367 } else if (mem.eql(u8, cmd, "detect-cpu")) {
...@@ -698,7 +698,7 @@ const Emit = union(enum) {...@@ -698,7 +698,7 @@ const Emit = union(enum) {
698 yes: []const u8,698 yes: []const u8,
699699
700 const OutputToCacheReason = enum { listen, @"zig run", @"zig test" };700 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 {
702 return switch (emit) {702 return switch (emit) {
703 .no => .no,703 .no => .no,
704 .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename },704 .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename },
...@@ -716,7 +716,7 @@ const Emit = union(enum) {...@@ -716,7 +716,7 @@ const Emit = union(enum) {
716 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {716 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
717 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });717 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
718 };718 };
719 dir.close();719 dir.close(io);
720 }720 }
721 break :e .{ .yes_path = path };721 break :e .{ .yes_path = path };
722 },722 },
...@@ -1034,7 +1034,7 @@ fn buildOutputType(...@@ -1034,7 +1034,7 @@ fn buildOutputType(
1034 };1034 };
1035 } else if (mem.startsWith(u8, arg, "-")) {1035 } else if (mem.startsWith(u8, arg, "-")) {
1036 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {1036 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);
1038 return cleanExit();1038 return cleanExit();
1039 } else if (mem.eql(u8, arg, "--")) {1039 } else if (mem.eql(u8, arg, "--")) {
1040 if (arg_mode == .run) {1040 if (arg_mode == .run) {
...@@ -2834,9 +2834,9 @@ fn buildOutputType(...@@ -2834,9 +2834,9 @@ fn buildOutputType(
2834 } else if (mem.eql(u8, arg, "-V")) {2834 } else if (mem.eql(u8, arg, "-V")) {
2835 warn("ignoring request for supported emulations: unimplemented", .{});2835 warn("ignoring request for supported emulations: unimplemented", .{});
2836 } else if (mem.eql(u8, arg, "-v")) {2836 } 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");
2838 } else if (mem.eql(u8, arg, "--version")) {2838 } 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");
2840 process.exit(0);2840 process.exit(0);
2841 } else {2841 } else {
2842 fatal("unsupported linker arg: {s}", .{arg});2842 fatal("unsupported linker arg: {s}", .{arg});
...@@ -3251,8 +3251,8 @@ fn buildOutputType(...@@ -3251,8 +3251,8 @@ fn buildOutputType(
3251 }3251 }
3252 }3252 }
32533253
3254 var cleanup_emit_bin_dir: ?fs.Dir = null;3254 var cleanup_emit_bin_dir: ?Io.Dir = null;
3255 defer if (cleanup_emit_bin_dir) |*dir| dir.close();3255 defer if (cleanup_emit_bin_dir) |*dir| dir.close(io);
32563256
3257 // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if3257 // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if
3258 // the binary is requested with no explicit path (as is the default), we emit to the cache.3258 // the binary is requested with no explicit path (as is the default), we emit to the cache.
...@@ -3307,7 +3307,7 @@ fn buildOutputType(...@@ -3307,7 +3307,7 @@ fn buildOutputType(
3307 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {3307 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
3308 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });3308 fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
3309 };3309 };
3310 dir.close();3310 dir.close(io);
3311 }3311 }
3312 break :emit .{ .yes_path = path };3312 break :emit .{ .yes_path = path };
3313 },3313 },
...@@ -3390,7 +3390,7 @@ fn buildOutputType(...@@ -3390,7 +3390,7 @@ fn buildOutputType(
3390 // will be a hash of its contents — so multiple invocations of3390 // will be a hash of its contents — so multiple invocations of
3391 // `zig cc -` will result in the same temp file name.3391 // `zig cc -` will result in the same temp file name.
3392 var f = try dirs.local_cache.handle.createFile(dump_path, .{});3392 var f = try dirs.local_cache.handle.createFile(dump_path, .{});
3393 defer f.close();3393 defer f.close(io);
33943394
3395 // Re-using the hasher from Cache, since the functional requirements3395 // Re-using the hasher from Cache, since the functional requirements
3396 // for the hashing algorithm here and in the cache are the same.3396 // for the hashing algorithm here and in the cache are the same.
...@@ -3399,7 +3399,7 @@ fn buildOutputType(...@@ -3399,7 +3399,7 @@ fn buildOutputType(
3399 var file_writer = f.writer(&.{});3399 var file_writer = f.writer(&.{});
3400 var buffer: [1000]u8 = undefined;3400 var buffer: [1000]u8 = undefined;
3401 var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer);3401 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, &.{});
3403 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {3403 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {
3404 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),3404 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),
3405 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),3405 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),
...@@ -3630,13 +3630,13 @@ fn buildOutputType(...@@ -3630,13 +3630,13 @@ fn buildOutputType(
3630 if (show_builtin) {3630 if (show_builtin) {
3631 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);3631 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
3632 const source = try builtin_opts.generate(arena);3632 const source = try builtin_opts.generate(arena);
3633 return fs.File.stdout().writeAll(source);3633 return Io.File.stdout().writeAll(source);
3634 }3634 }
3635 switch (listen) {3635 switch (listen) {
3636 .none => {},3636 .none => {},
3637 .stdio => {3637 .stdio => {
3638 var stdin_reader = fs.File.stdin().reader(io, &stdin_buffer);3638 var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer);
3639 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);3639 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
3640 try serve(3640 try serve(
3641 comp,3641 comp,
3642 &stdin_reader.interface,3642 &stdin_reader.interface,
...@@ -4034,6 +4034,7 @@ fn createModule(...@@ -4034,6 +4034,7 @@ fn createModule(
4034 link.resolveInputs(4034 link.resolveInputs(
4035 gpa,4035 gpa,
4036 arena,4036 arena,
4037 io,
4037 target,4038 target,
4038 &unresolved_link_inputs,4039 &unresolved_link_inputs,
4039 &create_module.link_inputs,4040 &create_module.link_inputs,
...@@ -4689,8 +4690,8 @@ fn cmdTranslateC(...@@ -4689,8 +4690,8 @@ fn cmdTranslateC(
4689 @errorName(err),4690 @errorName(err),
4690 });4691 });
4691 };4692 };
4692 defer zig_file.close();4693 defer zig_file.close(io);
4693 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);4694 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
4694 var file_reader = zig_file.reader(io, &.{});4695 var file_reader = zig_file.reader(io, &.{});
4695 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);4696 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
4696 try stdout_writer.interface.flush();4697 try stdout_writer.interface.flush();
...@@ -4728,7 +4729,7 @@ const usage_init =...@@ -4728,7 +4729,7 @@ const usage_init =
4728 \\4729 \\
4729;4730;
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 {
4732 dev.check(.init_command);4733 dev.check(.init_command);
47334734
4734 var template: enum { example, minimal } = .example;4735 var template: enum { example, minimal } = .example;
...@@ -4740,7 +4741,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4740,7 +4741,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4740 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {4741 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4741 template = .minimal;4742 template = .minimal;
4742 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {4743 } 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);
4744 return cleanExit();4745 return cleanExit();
4745 } else {4746 } else {
4746 fatal("unrecognized parameter: '{s}'", .{arg});4747 fatal("unrecognized parameter: '{s}'", .{arg});
...@@ -4759,7 +4760,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4759,7 +4760,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
47594760
4760 switch (template) {4761 switch (template) {
4761 .example => {4762 .example => {
4762 var templates = findTemplates(gpa, arena);4763 var templates = findTemplates(gpa, arena, io);
4763 defer templates.deinit();4764 defer templates.deinit();
47644765
4765 const s = fs.path.sep_str;4766 const s = fs.path.sep_str;
...@@ -4789,7 +4790,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4789,7 +4790,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4789 return cleanExit();4790 return cleanExit();
4790 },4791 },
4791 .minimal => {4792 .minimal => {
4792 writeSimpleTemplateFile(Package.Manifest.basename,4793 writeSimpleTemplateFile(io, Package.Manifest.basename,
4793 \\.{{4794 \\.{{
4794 \\ .name = .{s},4795 \\ .name = .{s},
4795 \\ .version = "0.0.1",4796 \\ .version = "0.0.1",
...@@ -4806,7 +4807,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4806,7 +4807,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4806 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),4807 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
4807 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),4808 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
4808 };4809 };
4809 writeSimpleTemplateFile(Package.build_zig_basename,4810 writeSimpleTemplateFile(io, Package.build_zig_basename,
4810 \\const std = @import("std");4811 \\const std = @import("std");
4811 \\4812 \\
4812 \\pub fn build(b: *std.Build) void {{4813 \\pub fn build(b: *std.Build) void {{
...@@ -5203,8 +5204,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)...@@ -5203,8 +5204,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
5203 .parent = root_mod,5204 .parent = root_mod,
5204 });5205 });
52055206
5206 var cleanup_build_dir: ?fs.Dir = null;5207 var cleanup_build_dir: ?Io.Dir = null;
5207 defer if (cleanup_build_dir) |*dir| dir.close();5208 defer if (cleanup_build_dir) |*dir| dir.close(io);
52085209
5209 if (dev.env.supports(.fetch_command)) {5210 if (dev.env.supports(.fetch_command)) {
5210 const fetch_prog_node = root_prog_node.start("Fetch Packages", 0);5211 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)...@@ -5296,6 +5297,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
5296 try job_queue.createDependenciesSource(&source_buf);5297 try job_queue.createDependenciesSource(&source_buf);
5297 const deps_mod = try createDependenciesModule(5298 const deps_mod = try createDependenciesModule(
5298 arena,5299 arena,
5300 io,
5299 source_buf.items,5301 source_buf.items,
5300 root_mod,5302 root_mod,
5301 dirs,5303 dirs,
...@@ -5357,6 +5359,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)...@@ -5357,6 +5359,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
5357 }5359 }
5358 } else try createEmptyDependenciesModule(5360 } else try createEmptyDependenciesModule(
5359 arena,5361 arena,
5362 io,
5360 root_mod,5363 root_mod,
5361 dirs,5364 dirs,
5362 config,5365 config,
...@@ -5623,7 +5626,7 @@ fn jitCmd(...@@ -5623,7 +5626,7 @@ fn jitCmd(
5623 defer comp.destroy();5626 defer comp.destroy();
56245627
5625 if (options.server) {5628 if (options.server) {
5626 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);5629 var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
5627 var server: std.zig.Server = .{5630 var server: std.zig.Server = .{
5628 .out = &stdout_writer.interface,5631 .out = &stdout_writer.interface,
5629 .in = undefined, // won't be receiving messages5632 .in = undefined, // won't be receiving messages
...@@ -6156,7 +6159,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6156,7 +6159,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
6156 const arg = args[i];6159 const arg = args[i];
6157 if (mem.startsWith(u8, arg, "-")) {6160 if (mem.startsWith(u8, arg, "-")) {
6158 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {6161 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);
6160 return cleanExit();6163 return cleanExit();
6161 } else if (mem.eql(u8, arg, "-t")) {6164 } else if (mem.eql(u8, arg, "-t")) {
6162 want_output_text = true;6165 want_output_text = true;
...@@ -6187,9 +6190,9 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6187,9 +6190,9 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
6187 break :file fs.cwd().openFile(p, .{}) catch |err| {6190 break :file fs.cwd().openFile(p, .{}) catch |err| {
6188 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });6191 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
6189 };6192 };
6190 } else fs.File.stdin();6193 } else Io.File.stdin();
6191 defer if (zig_source_path != null) f.close();6194 defer if (zig_source_path != null) f.close(io);
6192 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);6195 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
6193 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {6196 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
6194 fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });6197 fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
6195 };6198 };
...@@ -6207,7 +6210,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6207,7 +6210,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
62076210
6208 const tree = try Ast.parse(arena, source, mode);6211 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);
6211 const stdout_bw = &stdout_writer.interface;6214 const stdout_bw = &stdout_writer.interface;
6212 switch (mode) {6215 switch (mode) {
6213 .zig => {6216 .zig => {
...@@ -6330,7 +6333,7 @@ fn cmdDetectCpu(io: Io, args: []const []const u8) !void {...@@ -6330,7 +6333,7 @@ fn cmdDetectCpu(io: Io, args: []const []const u8) !void {
6330 const arg = args[i];6333 const arg = args[i];
6331 if (mem.startsWith(u8, arg, "-")) {6334 if (mem.startsWith(u8, arg, "-")) {
6332 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {6335 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);
6334 return cleanExit();6337 return cleanExit();
6335 } else if (mem.eql(u8, arg, "--llvm")) {6338 } else if (mem.eql(u8, arg, "--llvm")) {
6336 use_llvm = true;6339 use_llvm = true;
...@@ -6422,7 +6425,7 @@ fn detectNativeCpuWithLLVM(...@@ -6422,7 +6425,7 @@ fn detectNativeCpuWithLLVM(
6422}6425}
64236426
6424fn printCpu(cpu: std.Target.Cpu) !void {6427fn 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);
6426 const stdout_bw = &stdout_writer.interface;6429 const stdout_bw = &stdout_writer.interface;
64276430
6428 if (cpu.model.llvm_name) |llvm_name| {6431 if (cpu.model.llvm_name) |llvm_name| {
...@@ -6471,7 +6474,7 @@ fn cmdDumpLlvmInts(...@@ -6471,7 +6474,7 @@ fn cmdDumpLlvmInts(
6471 const dl = tm.createTargetDataLayout();6474 const dl = tm.createTargetDataLayout();
6472 const context = llvm.Context.create();6475 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);
6475 const stdout_bw = &stdout_writer.interface;6478 const stdout_bw = &stdout_writer.interface;
6476 for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {6479 for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
6477 const int_type = context.intType(bits);6480 const int_type = context.intType(bits);
...@@ -6494,10 +6497,10 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6494,10 +6497,10 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
6494 var f = fs.cwd().openFile(cache_file, .{}) catch |err| {6497 var f = fs.cwd().openFile(cache_file, .{}) catch |err| {
6495 fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) });6498 fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) });
6496 };6499 };
6497 defer f.close();6500 defer f.close(io);
64986501
6499 const zir = try Zcu.loadZirCache(arena, io, f);6502 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);
6501 const stdout_bw = &stdout_writer.interface;6504 const stdout_bw = &stdout_writer.interface;
6502 {6505 {
6503 const instruction_bytes = zir.instructions.len *6506 const instruction_bytes = zir.instructions.len *
...@@ -6540,16 +6543,16 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6540,16 +6543,16 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {
6540 const old_source = source: {6543 const old_source = source: {
6541 var f = fs.cwd().openFile(old_source_path, .{}) catch |err|6544 var f = fs.cwd().openFile(old_source_path, .{}) catch |err|
6542 fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });6545 fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
6543 defer f.close();6546 defer f.close(io);
6544 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);6547 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
6545 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|6548 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
6546 fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });6549 fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
6547 };6550 };
6548 const new_source = source: {6551 const new_source = source: {
6549 var f = fs.cwd().openFile(new_source_path, .{}) catch |err|6552 var f = fs.cwd().openFile(new_source_path, .{}) catch |err|
6550 fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });6553 fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
6551 defer f.close();6554 defer f.close(io);
6552 var file_reader: fs.File.Reader = f.reader(io, &stdin_buffer);6555 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
6553 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|6556 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
6554 fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });6557 fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
6555 };6558 };
...@@ -6581,7 +6584,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6581,7 +6584,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {
6581 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;6584 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
6582 try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);6585 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);
6585 const stdout_bw = &stdout_writer.interface;6588 const stdout_bw = &stdout_writer.interface;
6586 {6589 {
6587 try stdout_bw.print("Instruction mappings:\n", .{});6590 try stdout_bw.print("Instruction mappings:\n", .{});
...@@ -6912,7 +6915,7 @@ fn cmdFetch(...@@ -6912,7 +6915,7 @@ fn cmdFetch(
6912 const arg = args[i];6915 const arg = args[i];
6913 if (mem.startsWith(u8, arg, "-")) {6916 if (mem.startsWith(u8, arg, "-")) {
6914 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {6917 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);
6916 return cleanExit();6919 return cleanExit();
6917 } else if (mem.eql(u8, arg, "--global-cache-dir")) {6920 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
6918 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});6921 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
...@@ -6958,7 +6961,7 @@ fn cmdFetch(...@@ -6958,7 +6961,7 @@ fn cmdFetch(
6958 .path = p,6961 .path = p,
6959 };6962 };
6960 };6963 };
6961 defer global_cache_directory.handle.close();6964 defer global_cache_directory.handle.close(io);
69626965
6963 var job_queue: Package.Fetch.JobQueue = .{6966 var job_queue: Package.Fetch.JobQueue = .{
6964 .io = io,6967 .io = io,
...@@ -7021,7 +7024,7 @@ fn cmdFetch(...@@ -7021,7 +7024,7 @@ fn cmdFetch(
70217024
7022 const name = switch (save) {7025 const name = switch (save) {
7023 .no => {7026 .no => {
7024 var stdout = fs.File.stdout().writerStreaming(&stdout_buffer);7027 var stdout = Io.File.stdout().writerStreaming(&stdout_buffer);
7025 try stdout.interface.print("{s}\n", .{package_hash_slice});7028 try stdout.interface.print("{s}\n", .{package_hash_slice});
7026 try stdout.interface.flush();7029 try stdout.interface.flush();
7027 return cleanExit();7030 return cleanExit();
...@@ -7043,7 +7046,7 @@ fn cmdFetch(...@@ -7043,7 +7046,7 @@ fn cmdFetch(
70437046
7044 // The name to use in case the manifest file needs to be created now.7047 // The name to use in case the manifest file needs to be created now.
7045 const init_root_name = fs.path.basename(build_root.directory.path orelse cwd_path);7048 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, .{
7047 .root_name = try sanitizeExampleName(arena, init_root_name),7050 .root_name = try sanitizeExampleName(arena, init_root_name),
7048 .dir = build_root.directory.handle,7051 .dir = build_root.directory.handle,
7049 .color = color,7052 .color = color,
...@@ -7168,6 +7171,7 @@ fn cmdFetch(...@@ -7168,6 +7171,7 @@ fn cmdFetch(
71687171
7169fn createEmptyDependenciesModule(7172fn createEmptyDependenciesModule(
7170 arena: Allocator,7173 arena: Allocator,
7174 io: Io,
7171 main_mod: *Package.Module,7175 main_mod: *Package.Module,
7172 dirs: Compilation.Directories,7176 dirs: Compilation.Directories,
7173 global_options: Compilation.Config,7177 global_options: Compilation.Config,
...@@ -7176,6 +7180,7 @@ fn createEmptyDependenciesModule(...@@ -7176,6 +7180,7 @@ fn createEmptyDependenciesModule(
7176 try Package.Fetch.JobQueue.createEmptyDependenciesSource(&source);7180 try Package.Fetch.JobQueue.createEmptyDependenciesSource(&source);
7177 _ = try createDependenciesModule(7181 _ = try createDependenciesModule(
7178 arena,7182 arena,
7183 io,
7179 source.items,7184 source.items,
7180 main_mod,7185 main_mod,
7181 dirs,7186 dirs,
...@@ -7187,6 +7192,7 @@ fn createEmptyDependenciesModule(...@@ -7187,6 +7192,7 @@ fn createEmptyDependenciesModule(
7187/// build runner to obtain via `@import("@dependencies")`.7192/// build runner to obtain via `@import("@dependencies")`.
7188fn createDependenciesModule(7193fn createDependenciesModule(
7189 arena: Allocator,7194 arena: Allocator,
7195 io: Io,
7190 source: []const u8,7196 source: []const u8,
7191 main_mod: *Package.Module,7197 main_mod: *Package.Module,
7192 dirs: Compilation.Directories,7198 dirs: Compilation.Directories,
...@@ -7198,7 +7204,7 @@ fn createDependenciesModule(...@@ -7198,7 +7204,7 @@ fn createDependenciesModule(
7198 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);7204 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
7199 {7205 {
7200 var tmp_dir = try dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});7206 var tmp_dir = try dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
7201 defer tmp_dir.close();7207 defer tmp_dir.close(io);
7202 try tmp_dir.writeFile(.{ .sub_path = basename, .data = source });7208 try tmp_dir.writeFile(.{ .sub_path = basename, .data = source });
7203 }7209 }
72047210
...@@ -7232,10 +7238,10 @@ fn createDependenciesModule(...@@ -7232,10 +7238,10 @@ fn createDependenciesModule(
7232const BuildRoot = struct {7238const BuildRoot = struct {
7233 directory: Cache.Directory,7239 directory: Cache.Directory,
7234 build_zig_basename: []const u8,7240 build_zig_basename: []const u8,
7235 cleanup_build_dir: ?fs.Dir,7241 cleanup_build_dir: ?Io.Dir,
72367242
7237 fn deinit(br: *BuildRoot) void {7243 fn deinit(br: *BuildRoot, io: Io) void {
7238 if (br.cleanup_build_dir) |*dir| dir.close();7244 if (br.cleanup_build_dir) |*dir| dir.close(io);
7239 br.* = undefined;7245 br.* = undefined;
7240 }7246 }
7241};7247};
...@@ -7304,13 +7310,14 @@ fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {...@@ -7304,13 +7310,14 @@ fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {
73047310
7305const LoadManifestOptions = struct {7311const LoadManifestOptions = struct {
7306 root_name: []const u8,7312 root_name: []const u8,
7307 dir: fs.Dir,7313 dir: Io.Dir,
7308 color: Color,7314 color: Color,
7309};7315};
73107316
7311fn loadManifest(7317fn loadManifest(
7312 gpa: Allocator,7318 gpa: Allocator,
7313 arena: Allocator,7319 arena: Allocator,
7320 io: Io,
7314 options: LoadManifestOptions,7321 options: LoadManifestOptions,
7315) !struct { Package.Manifest, Ast } {7322) !struct { Package.Manifest, Ast } {
7316 const manifest_bytes = while (true) {7323 const manifest_bytes = while (true) {
...@@ -7322,7 +7329,7 @@ fn loadManifest(...@@ -7322,7 +7329,7 @@ fn loadManifest(
7322 0,7329 0,
7323 ) catch |err| switch (err) {7330 ) catch |err| switch (err) {
7324 error.FileNotFound => {7331 error.FileNotFound => {
7325 writeSimpleTemplateFile(Package.Manifest.basename,7332 writeSimpleTemplateFile(io, Package.Manifest.basename,
7326 \\.{{7333 \\.{{
7327 \\ .name = .{s},7334 \\ .name = .{s},
7328 \\ .version = "{s}",7335 \\ .version = "{s}",
...@@ -7374,12 +7381,12 @@ fn loadManifest(...@@ -7374,12 +7381,12 @@ fn loadManifest(
73747381
7375const Templates = struct {7382const Templates = struct {
7376 zig_lib_directory: Cache.Directory,7383 zig_lib_directory: Cache.Directory,
7377 dir: fs.Dir,7384 dir: Io.Dir,
7378 buffer: std.array_list.Managed(u8),7385 buffer: std.array_list.Managed(u8),
73797386
7380 fn deinit(templates: *Templates) void {7387 fn deinit(templates: *Templates, io: Io) void {
7381 templates.zig_lib_directory.handle.close();7388 templates.zig_lib_directory.handle.close(io);
7382 templates.dir.close();7389 templates.dir.close(io);
7383 templates.buffer.deinit();7390 templates.buffer.deinit();
7384 templates.* = undefined;7391 templates.* = undefined;
7385 }7392 }
...@@ -7387,7 +7394,7 @@ const Templates = struct {...@@ -7387,7 +7394,7 @@ const Templates = struct {
7387 fn write(7394 fn write(
7388 templates: *Templates,7395 templates: *Templates,
7389 arena: Allocator,7396 arena: Allocator,
7390 out_dir: fs.Dir,7397 out_dir: Io.Dir,
7391 root_name: []const u8,7398 root_name: []const u8,
7392 template_path: []const u8,7399 template_path: []const u8,
7393 fingerprint: Package.Fingerprint,7400 fingerprint: Package.Fingerprint,
...@@ -7435,23 +7442,23 @@ const Templates = struct {...@@ -7435,23 +7442,23 @@ const Templates = struct {
7435 });7442 });
7436 }7443 }
7437};7444};
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 {
7439 const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });7446 const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
7440 defer f.close();7447 defer f.close(io);
7441 var buf: [4096]u8 = undefined;7448 var buf: [4096]u8 = undefined;
7442 var fw = f.writer(&buf);7449 var fw = f.writer(&buf);
7443 try fw.interface.print(fmt, args);7450 try fw.interface.print(fmt, args);
7444 try fw.interface.flush();7451 try fw.interface.flush();
7445}7452}
74467453
7447fn findTemplates(gpa: Allocator, arena: Allocator) Templates {7454fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
7448 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {7455 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
7449 fatal("unable to get cwd: {s}", .{@errorName(err)});7456 fatal("unable to get cwd: {s}", .{@errorName(err)});
7450 };7457 };
7451 const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {7458 const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
7452 fatal("unable to find self exe path: {s}", .{@errorName(err)});7459 fatal("unable to find self exe path: {s}", .{@errorName(err)});
7453 };7460 };
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| {
7455 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });7462 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
7456 };7463 };
74577464
src/print_targets.zig+2-1
...@@ -12,6 +12,7 @@ const introspect = @import("introspect.zig");...@@ -12,6 +12,7 @@ const introspect = @import("introspect.zig");
1212
13pub fn cmdTargets(13pub fn cmdTargets(
14 allocator: Allocator,14 allocator: Allocator,
15 io: Io,
15 args: []const []const u8,16 args: []const []const u8,
16 out: *std.Io.Writer,17 out: *std.Io.Writer,
17 native_target: *const Target,18 native_target: *const Target,
...@@ -20,7 +21,7 @@ pub fn cmdTargets(...@@ -20,7 +21,7 @@ pub fn cmdTargets(
20 var zig_lib_directory = introspect.findZigLibDir(allocator) catch |err| {21 var zig_lib_directory = introspect.findZigLibDir(allocator) catch |err| {
21 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});22 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
22 };23 };
23 defer zig_lib_directory.handle.close();24 defer zig_lib_directory.handle.close(io);
24 defer allocator.free(zig_lib_directory.path.?);25 defer allocator.free(zig_lib_directory.path.?);
2526
26 const abilists_contents = zig_lib_directory.handle.readFileAlloc(27 const abilists_contents = zig_lib_directory.handle.readFileAlloc(