std.fs.updateFile: make path if necessary

This commit is contained in:
Andrew Kelley 2019-07-14 22:29:39 -04:00
parent 40a562f26d
commit 95fdff3feb
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9

View File

@ -80,11 +80,12 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
return updateFileMode(source_path, dest_path, null);
}
/// Check the file size and mtime of `source_path` and `dest_path`. If they are equal, does nothing.
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime
/// and atime of the source file so that the next call to `updateFile` will not need a copy.
/// TODO https://github.com/ziglang/zig/issues/2885
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
/// Returns the previous status of the file before updating.
/// If any of the directories do not exist for dest_path, they are created.
/// TODO https://github.com/ziglang/zig/issues/2885
pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {
var src_file = try File.openRead(source_path);
defer src_file.close();
@ -108,9 +109,32 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil
return PrevStatus.fresh;
}
}
const actual_mode = mode orelse src_stat.mode;
const in_stream = &src_file.inStream().stream;
var atomic_file = try AtomicFile.init(dest_path, mode orelse src_stat.mode);
// TODO this logic could be made more efficient by calling makePath, once
// that API does not require an allocator
var atomic_file = make_atomic_file: while (true) {
const af = AtomicFile.init(dest_path, actual_mode) catch |err| switch (err) {
error.FileNotFound => {
var p = dest_path;
while (path.dirname(p)) |dirname| {
makeDir(dirname) catch |e| switch (e) {
error.FileNotFound => {
p = dirname;
continue;
},
else => return e,
};
continue :make_atomic_file;
} else {
return err;
}
},
else => |e| return e,
};
break af;
} else unreachable;
defer atomic_file.deinit();
var buf: [mem.page_size * 6]u8 = undefined;