aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-03-26 20:32:06 -0400
committerGitHub <noreply@github.com>2020-03-26 20:32:06 -0400
commitaec4967f36d16cfee43529bd341300f5f77af34a (patch)
tree6e4fc6faa7989a494b417b9584d20a97f07e0916 /lib/std
parent463b90b977ba4817f6cf90a85e8609092f53dfd2 (diff)
parentcf4cbea88e2a2e56f71d721e9c686ab68dd19658 (diff)
downloadzig-aec4967f36d16cfee43529bd341300f5f77af34a.tar.gz
zig-aec4967f36d16cfee43529bd341300f5f77af34a.zip
Merge pull request #4814 from gereeter/reduced-path-max
In AtomicFile, work relative to the destination's parent directory
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/fs.zig46
1 files changed, 24 insertions, 22 deletions
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index e705966c97..077e668188 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -63,7 +63,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
const dirname = path.dirname(new_path) orelse ".";
- var rand_buf: [12]u8 = undefined;
+ var rand_buf: [AtomicFile.RANDOM_BYTES]u8 = undefined;
const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
defer allocator.free(tmp_path);
mem.copy(u8, tmp_path[0..], dirname);
@@ -118,38 +118,31 @@ pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: Co
/// TODO update this API to avoid a getrandom syscall for every operation.
pub const AtomicFile = struct {
file: File,
- tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8,
+ // TODO either replace this with rand_buf or use []u16 on Windows
+ tmp_path_buf: [TMP_PATH_LEN:0]u8,
dest_path: []const u8,
file_open: bool,
file_exists: bool,
+ close_dir_on_deinit: bool,
dir: Dir,
const InitError = File.OpenError;
- /// TODO rename this. Callers should go through Dir API
- pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile {
- const dirname = path.dirname(dest_path);
- var rand_buf: [12]u8 = undefined;
- const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
- const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
- const tmp_path_len = dirname_component_len + encoded_rand_len;
- var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined;
- if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong;
-
- if (dirname) |dn| {
- mem.copy(u8, tmp_path_buf[0..], dn);
- tmp_path_buf[dn.len] = path.sep;
- }
+ const RANDOM_BYTES = 12;
+ const TMP_PATH_LEN = base64.Base64Encoder.calcSize(RANDOM_BYTES);
- tmp_path_buf[tmp_path_len] = 0;
- const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0];
+ /// TODO rename this. Callers should go through Dir API
+ pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir, close_dir_on_deinit: bool) InitError!AtomicFile {
+ var rand_buf: [RANDOM_BYTES]u8 = undefined;
+ var tmp_path_buf: [TMP_PATH_LEN:0]u8 = undefined;
+ tmp_path_buf[base64.Base64Encoder.calcSize(RANDOM_BYTES)] = 0;
while (true) {
try crypto.randomBytes(rand_buf[0..]);
- base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf);
+ base64_encoder.encode(&tmp_path_buf, &rand_buf);
const file = dir.createFileC(
- tmp_path_slice,
+ &tmp_path_buf,
.{ .mode = mode, .exclusive = true },
) catch |err| switch (err) {
error.PathAlreadyExists => continue,
@@ -162,6 +155,7 @@ pub const AtomicFile = struct {
.dest_path = dest_path,
.file_open = true,
.file_exists = true,
+ .close_dir_on_deinit = close_dir_on_deinit,
.dir = dir,
};
}
@@ -169,7 +163,7 @@ pub const AtomicFile = struct {
/// Deprecated. Use `Dir.atomicFile`.
pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
- return init2(dest_path, mode, cwd());
+ return cwd().atomicFile(dest_path, .{ .mode = mode });
}
/// always call deinit, even after successful finish()
@@ -182,6 +176,9 @@ pub const AtomicFile = struct {
self.dir.deleteFileC(&self.tmp_path_buf) catch {};
self.file_exists = false;
}
+ if (self.close_dir_on_deinit) {
+ self.dir.close();
+ }
self.* = undefined;
}
@@ -1281,7 +1278,12 @@ pub const Dir = struct {
/// `dest_path` must remain valid for the lifetime of `AtomicFile`.
/// Call `AtomicFile.finish` to atomically replace `dest_path` with contents.
pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) !AtomicFile {
- return AtomicFile.init2(dest_path, options.mode, self);
+ if (path.dirname(dest_path)) |dirname| {
+ const dir = try self.openDir(dirname, .{});
+ return AtomicFile.init2(path.basename(dest_path), options.mode, dir, true);
+ } else {
+ return AtomicFile.init2(dest_path, options.mode, self, false);
+ }
}
};