Skip to content

Commit

Permalink
std.tar don't overwrite existing file
Browse files Browse the repository at this point in the history
Fail with error if file already exists. File is not silently overwritten
but an error is raised.

Fixes: ziglang#18089
  • Loading branch information
ianic committed Feb 24, 2024
1 parent 6fddc9c commit b84301c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
4 changes: 2 additions & 2 deletions lib/std/tar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -544,12 +544,12 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
const file_name = stripComponents(file.name, options.strip_components);
if (file_name.len == 0) return error.BadFileName;

const fs_file = dir.createFile(file_name, .{}) catch |err| switch (err) {
const fs_file = dir.createFile(file_name, .{ .exclusive = true }) catch |err| switch (err) {
error.FileNotFound => again: {
const code = code: {
if (std.fs.path.dirname(file_name)) |dir_name| {
dir.makePath(dir_name) catch |code| break :code code;
break :again dir.createFile(file_name, .{}) catch |code| {
break :again dir.createFile(file_name, .{ .exclusive = true }) catch |code| {
break :code code;
};
}
Expand Down
57 changes: 57 additions & 0 deletions lib/std/tar/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,60 @@ const Md5Writer = struct {
return std.fmt.bytesToHex(s, .lower);
}
};

test "tar should not overwrite existing file" {
// Starting from this folder structure:
// $ tree root
// root
// ├── a
// │   └── b
// │   └── c
// │   └── file.txt
// └── d
// └── b
// └── c
// └── file.txt
//
// Packed with command:
// $ cd root; tar cf overwrite_file.tar *
// Resulting tar has following structure:
// $ tar tvf overwrite_file.tar
// size path
// 0 a/
// 0 a/b/
// 0 a/b/c/
// 2 a/b/c/file.txt
// 0 d/
// 0 d/b/
// 0 d/b/c/
// 2 d/b/c/file.txt
//
// Note that there is no root folder in archive.
//
// With strip_components = 1 resulting unpacked folder was:
// root
// └── b
// └── c
// └── file.txt
//
// a/b/c/file.txt is overwritten with d/b/c/file.txt !!!
// This ensures that file is not overwritten.
//
const data = @embedFile("testdata/overwrite_file.tar");
var fsb = std.io.fixedBufferStream(data);

// Unpack with strip_components = 1 should fail
var root = std.testing.tmpDir(.{});
defer root.cleanup();
try testing.expectError(
error.PathAlreadyExists,
tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }),
);

// Unpack with strip_components = 0 should pass
fsb.reset();
var root2 = std.testing.tmpDir(.{});
defer root2.cleanup();
try tar.pipeToFileSystem(root2.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 0 });
}

Binary file added lib/std/tar/testdata/overwrite_file.tar
Binary file not shown.

0 comments on commit b84301c

Please sign in to comment.