Skip to content

Commit d556de2

Browse files
committed
std.fs.File: delete writeFileAll and friends
please use File.Writer for these use cases also breaking API changes to std.fs.AtomicFile
1 parent 620b91c commit d556de2

File tree

10 files changed

+274
-416
lines changed

10 files changed

+274
-416
lines changed

lib/std/Build/Step/Run.zig

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub const Output = struct {
169169
pub fn create(owner: *std.Build, name: []const u8) *Run {
170170
const run = owner.allocator.create(Run) catch @panic("OOM");
171171
run.* = .{
172-
.step = Step.init(.{
172+
.step = .init(.{
173173
.id = base_id,
174174
.name = name,
175175
.owner = owner,
@@ -1769,13 +1769,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
17691769
child.stdin = null;
17701770
},
17711771
.lazy_path => |lazy_path| {
1772-
const path = lazy_path.getPath2(b, &run.step);
1773-
const file = b.build_root.handle.openFile(path, .{}) catch |err| {
1772+
const path = lazy_path.getPath3(b, &run.step);
1773+
const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
17741774
return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
17751775
};
17761776
defer file.close();
1777-
child.stdin.?.writeFileAll(file, .{}) catch |err| {
1778-
return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)});
1777+
// TODO https://github.com/ziglang/zig/issues/23955
1778+
var buffer: [1024]u8 = undefined;
1779+
var file_reader = file.reader(&buffer);
1780+
var stdin_writer = child.stdin.?.writer(&.{});
1781+
_ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
1782+
error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{
1783+
path, file_reader.err.?,
1784+
}),
1785+
error.WriteFailed => return run.step.fail("failed to write to stdin: {t}", .{
1786+
stdin_writer.err.?,
1787+
}),
17791788
};
17801789
child.stdin.?.close();
17811790
child.stdin = null;

lib/std/fs/AtomicFile.zig

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
file: File,
2-
// TODO either replace this with rand_buf or use []u16 on Windows
3-
tmp_path_buf: [tmp_path_len:0]u8,
1+
const AtomicFile = @This();
2+
const std = @import("../std.zig");
3+
const File = std.fs.File;
4+
const Dir = std.fs.Dir;
5+
const fs = std.fs;
6+
const assert = std.debug.assert;
7+
const posix = std.posix;
8+
9+
file_writer: File.Writer,
10+
random_integer: u64,
411
dest_basename: []const u8,
512
file_open: bool,
613
file_exists: bool,
@@ -9,35 +16,24 @@ dir: Dir,
916

1017
pub const InitError = File.OpenError;
1118

12-
pub const random_bytes_len = 12;
13-
const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len);
14-
1519
/// Note that the `Dir.atomicFile` API may be more handy than this lower-level function.
1620
pub fn init(
1721
dest_basename: []const u8,
1822
mode: File.Mode,
1923
dir: Dir,
2024
close_dir_on_deinit: bool,
25+
write_buffer: []u8,
2126
) InitError!AtomicFile {
22-
var rand_buf: [random_bytes_len]u8 = undefined;
23-
var tmp_path_buf: [tmp_path_len:0]u8 = undefined;
24-
2527
while (true) {
26-
std.crypto.random.bytes(rand_buf[0..]);
27-
const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf);
28-
tmp_path_buf[tmp_path.len] = 0;
29-
30-
const file = dir.createFile(
31-
tmp_path,
32-
.{ .mode = mode, .exclusive = true },
33-
) catch |err| switch (err) {
28+
const random_integer = std.crypto.random.int(u64);
29+
const tmp_sub_path = std.fmt.hex(random_integer);
30+
const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) {
3431
error.PathAlreadyExists => continue,
3532
else => |e| return e,
3633
};
37-
38-
return AtomicFile{
39-
.file = file,
40-
.tmp_path_buf = tmp_path_buf,
34+
return .{
35+
.file_writer = file.writer(write_buffer),
36+
.random_integer = random_integer,
4137
.dest_basename = dest_basename,
4238
.file_open = true,
4339
.file_exists = true,
@@ -48,41 +44,51 @@ pub fn init(
4844
}
4945

5046
/// Always call deinit, even after a successful finish().
51-
pub fn deinit(self: *AtomicFile) void {
52-
if (self.file_open) {
53-
self.file.close();
54-
self.file_open = false;
47+
pub fn deinit(af: *AtomicFile) void {
48+
if (af.file_open) {
49+
af.file_writer.file.close();
50+
af.file_open = false;
5551
}
56-
if (self.file_exists) {
57-
self.dir.deleteFile(&self.tmp_path_buf) catch {};
58-
self.file_exists = false;
52+
if (af.file_exists) {
53+
const tmp_sub_path = std.fmt.hex(af.random_integer);
54+
af.dir.deleteFile(&tmp_sub_path) catch {};
55+
af.file_exists = false;
5956
}
60-
if (self.close_dir_on_deinit) {
61-
self.dir.close();
57+
if (af.close_dir_on_deinit) {
58+
af.dir.close();
6259
}
63-
self.* = undefined;
60+
af.* = undefined;
6461
}
6562

66-
pub const FinishError = posix.RenameError;
63+
pub const FlushError = File.WriteError;
64+
65+
pub fn flush(af: *AtomicFile) FlushError!void {
66+
af.file_writer.interface.flush() catch |err| switch (err) {
67+
error.WriteFailed => return af.file_writer.err.?,
68+
};
69+
}
70+
71+
pub const RenameIntoPlaceError = posix.RenameError;
6772

6873
/// On Windows, this function introduces a period of time where some file
6974
/// system operations on the destination file will result in
7075
/// `error.AccessDenied`, including rename operations (such as the one used in
7176
/// this function).
72-
pub fn finish(self: *AtomicFile) FinishError!void {
73-
assert(self.file_exists);
74-
if (self.file_open) {
75-
self.file.close();
76-
self.file_open = false;
77+
pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void {
78+
assert(af.file_exists);
79+
if (af.file_open) {
80+
af.file_writer.file.close();
81+
af.file_open = false;
7782
}
78-
try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename);
79-
self.file_exists = false;
83+
const tmp_sub_path = std.fmt.hex(af.random_integer);
84+
try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename);
85+
af.file_exists = false;
8086
}
8187

82-
const AtomicFile = @This();
83-
const std = @import("../std.zig");
84-
const File = std.fs.File;
85-
const Dir = std.fs.Dir;
86-
const fs = std.fs;
87-
const assert = std.debug.assert;
88-
const posix = std.posix;
88+
pub const FinishError = FlushError || RenameIntoPlaceError;
89+
90+
/// Combination of `flush` followed by `renameIntoPlace`.
91+
pub fn finish(af: *AtomicFile) FinishError!void {
92+
try af.flush();
93+
try af.renameIntoPlace();
94+
}

0 commit comments

Comments
 (0)