Skip to content

Commit 555a2c0

Browse files
committed
(breaking) std.fs.copyFile now integrates with Dir
Removed: * `std.fs.updateFile` * `std.fs.updateFileMode` * `std.fs.copyFile` * `std.fs.copyFileMode` Added: * `std.fs.Dir.copyFile` * `std.fs.copyFileAbsolute` * `std.fs.updateFileAbsolute` Moved: * `std.fs.Dir.UpdateFileOptions` => `std.fs.CopyFileOptions` Deprecated: * `std.fs.deleteDir` * `std.fs.deleteDirC` * `std.fs.deleteDirW` * `std.fs.readLink` * `std.fs.readLinkC`
1 parent e3c92d0 commit 555a2c0

File tree

3 files changed

+71
-61
lines changed

3 files changed

+71
-61
lines changed

lib/std/build.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,8 @@ pub const Builder = struct {
847847
if (self.verbose) {
848848
warn("cp {} {} ", .{ source_path, dest_path });
849849
}
850-
const prev_status = try fs.updateFile(source_path, dest_path);
850+
const cwd = fs.cwd();
851+
const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
851852
if (self.verbose) switch (prev_status) {
852853
.stale => warn("# installed\n", .{}),
853854
.fresh => warn("# up-to-date\n", .{}),

lib/std/fs.zig

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -86,51 +86,33 @@ pub const PrevStatus = enum {
8686
fresh,
8787
};
8888

89-
/// Deprecated; use `Dir.updateFile`.
90-
pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
91-
const my_cwd = cwd();
92-
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{});
93-
}
89+
pub const CopyFileOptions = struct {
90+
/// When this is `null` the mode is copied from the source file.
91+
override_mode: ?File.Mode = null,
92+
};
9493

95-
/// Deprecated; use `Dir.updateFile`.
96-
pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !Dir.PrevStatus {
94+
/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path`
95+
/// are absolute. See `Dir.updateFile` for a function that operates on both
96+
/// absolute and relative paths.
97+
pub fn updateFileAbsolute(
98+
source_path: []const u8,
99+
dest_path: []const u8,
100+
args: CopyFileOptions,
101+
) !PrevStatus {
102+
assert(path.isAbsolute(source_path));
103+
assert(path.isAbsolute(dest_path));
97104
const my_cwd = cwd();
98-
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{ .override_mode = mode });
99-
}
100-
101-
/// Guaranteed to be atomic.
102-
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
103-
/// there is a possibility of power loss or application termination leaving temporary files present
104-
/// in the same directory as dest_path.
105-
/// Destination file will have the same mode as the source file.
106-
/// TODO rework this to integrate with Dir
107-
pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
108-
var in_file = try cwd().openFile(source_path, .{});
109-
defer in_file.close();
110-
111-
const stat = try in_file.stat();
112-
113-
var atomic_file = try AtomicFile.init(dest_path, stat.mode);
114-
defer atomic_file.deinit();
115-
116-
try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size });
117-
return atomic_file.finish();
105+
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
118106
}
119107

120-
/// Guaranteed to be atomic.
121-
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
122-
/// there is a possibility of power loss or application termination leaving temporary files present
123-
/// in the same directory as dest_path.
124-
/// TODO rework this to integrate with Dir
125-
pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
126-
var in_file = try cwd().openFile(source_path, .{});
127-
defer in_file.close();
128-
129-
var atomic_file = try AtomicFile.init(dest_path, mode);
130-
defer atomic_file.deinit();
131-
132-
try atomic_file.file.writeFileAll(in_file, .{});
133-
return atomic_file.finish();
108+
/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
109+
/// are absolute. See `Dir.copyFile` for a function that operates on both
110+
/// absolute and relative paths.
111+
pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void {
112+
assert(path.isAbsolute(source_path));
113+
assert(path.isAbsolute(dest_path));
114+
const my_cwd = cwd();
115+
return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
134116
}
135117

136118
/// TODO update this API to avoid a getrandom syscall for every operation.
@@ -245,18 +227,17 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
245227
os.windows.CloseHandle(handle);
246228
}
247229

248-
/// Returns `error.DirNotEmpty` if the directory is not empty.
249-
/// To delete a directory recursively, see `deleteTree`.
230+
/// Deprecated; use `Dir.deleteDir`.
250231
pub fn deleteDir(dir_path: []const u8) !void {
251232
return os.rmdir(dir_path);
252233
}
253234

254-
/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
235+
/// Deprecated; use `Dir.deleteDirC`.
255236
pub fn deleteDirC(dir_path: [*:0]const u8) !void {
256237
return os.rmdirC(dir_path);
257238
}
258239

259-
/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
240+
/// Deprecated; use `Dir.deleteDirW`.
260241
pub fn deleteDirW(dir_path: [*:0]const u16) !void {
261242
return os.rmdirW(dir_path);
262243
}
@@ -1218,22 +1199,17 @@ pub const Dir = struct {
12181199
return os.faccessatW(self.fd, sub_path_w, 0, 0);
12191200
}
12201201

1221-
pub const UpdateFileOptions = struct {
1222-
override_mode: ?File.Mode = null,
1223-
};
1224-
12251202
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
12261203
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
12271204
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
12281205
/// Returns the previous status of the file before updating.
12291206
/// If any of the directories do not exist for dest_path, they are created.
1230-
/// If `override_mode` is provided, then that value is used rather than the source path's mode.
12311207
pub fn updateFile(
12321208
source_dir: Dir,
12331209
source_path: []const u8,
12341210
dest_dir: Dir,
12351211
dest_path: []const u8,
1236-
options: UpdateFileOptions,
1212+
options: CopyFileOptions,
12371213
) !PrevStatus {
12381214
var src_file = try source_dir.openFile(source_path, .{});
12391215
defer src_file.close();
@@ -1272,6 +1248,34 @@ pub const Dir = struct {
12721248
return PrevStatus.stale;
12731249
}
12741250

1251+
/// Guaranteed to be atomic.
1252+
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
1253+
/// there is a possibility of power loss or application termination leaving temporary files present
1254+
/// in the same directory as dest_path.
1255+
pub fn copyFile(
1256+
source_dir: Dir,
1257+
source_path: []const u8,
1258+
dest_dir: Dir,
1259+
dest_path: []const u8,
1260+
options: CopyFileOptions,
1261+
) !void {
1262+
var in_file = try source_dir.openFile(source_path, .{});
1263+
defer in_file.close();
1264+
1265+
var size: ?u64 = null;
1266+
const mode = options.override_mode orelse blk: {
1267+
const stat = try in_file.stat();
1268+
size = stat.size;
1269+
break :blk stat.mode;
1270+
};
1271+
1272+
var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
1273+
defer atomic_file.deinit();
1274+
1275+
try atomic_file.file.writeFileAll(in_file, .{ .in_len = size });
1276+
return atomic_file.finish();
1277+
}
1278+
12751279
pub const AtomicFileOptions = struct {
12761280
mode: File.Mode = File.default_mode,
12771281
};
@@ -1471,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
14711475
return walker;
14721476
}
14731477

1474-
/// Read value of a symbolic link.
1475-
/// The return value is a slice of buffer, from index `0`.
1478+
/// Deprecated; use `Dir.readLink`.
14761479
pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
14771480
return os.readlink(pathname, buffer);
14781481
}
14791482

1480-
/// Same as `readLink`, except the parameter is null-terminated.
1483+
/// Deprecated; use `Dir.readLinkC`.
14811484
pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
14821485
return os.readlinkC(pathname_c, buffer);
14831486
}
@@ -1584,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const
15841587
}
15851588

15861589
/// `realpath`, except caller must free the returned memory.
1590+
/// TODO integrate with `Dir`
15871591
pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
15881592
var buf: [MAX_PATH_BYTES]u8 = undefined;
15891593
return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
@@ -1592,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
15921596
test "" {
15931597
_ = makeDirAbsolute;
15941598
_ = makeDirAbsoluteZ;
1599+
_ = copyFileAbsolute;
1600+
_ = updateFileAbsolute;
1601+
_ = Dir.copyFile;
15951602
_ = @import("fs/path.zig");
15961603
_ = @import("fs/file.zig");
15971604
_ = @import("fs/get_app_data_dir.zig");

lib/std/os/test.zig

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,16 @@ test "fs.copyFile" {
113113
const dest_file = "tmp_test_copy_file2.txt";
114114
const dest_file2 = "tmp_test_copy_file3.txt";
115115

116-
try fs.cwd().writeFile(src_file, data);
117-
defer fs.cwd().deleteFile(src_file) catch {};
116+
const cwd = fs.cwd();
118117

119-
try fs.copyFile(src_file, dest_file);
120-
defer fs.cwd().deleteFile(dest_file) catch {};
118+
try cwd.writeFile(src_file, data);
119+
defer cwd.deleteFile(src_file) catch {};
121120

122-
try fs.copyFileMode(src_file, dest_file2, File.default_mode);
123-
defer fs.cwd().deleteFile(dest_file2) catch {};
121+
try cwd.copyFile(src_file, cwd, dest_file, .{});
122+
defer cwd.deleteFile(dest_file) catch {};
123+
124+
try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode });
125+
defer cwd.deleteFile(dest_file2) catch {};
124126

125127
try expectFileContents(dest_file, data);
126128
try expectFileContents(dest_file2, data);

0 commit comments

Comments
 (0)