| ... | ... | @@ -1,4 +1,7 @@ |
| 1 | | pub const Options = struct {}; |
| 1 | pub const Options = struct { |
| 2 | /// Number of directory levels to skip when extracting files. |
| 3 | strip_components: u32 = 0, |
| 4 | }; |
| 2 | 5 | |
| 3 | 6 | pub const Header = struct { |
| 4 | 7 | bytes: *const [512]u8, |
| ... | ... | @@ -69,7 +72,6 @@ pub const Header = struct { |
| 69 | 72 | }; |
| 70 | 73 | |
| 71 | 74 | pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void { |
| 72 | | _ = options; |
| 73 | 75 | var file_name_buffer: [255]u8 = undefined; |
| 74 | 76 | var buffer: [512 * 8]u8 = undefined; |
| 75 | 77 | var start: usize = 0; |
| ... | ... | @@ -92,13 +94,17 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi |
| 92 | 94 | const file_size = try header.fileSize(); |
| 93 | 95 | const rounded_file_size = std.mem.alignForwardGeneric(u64, file_size, 512); |
| 94 | 96 | const pad_len = rounded_file_size - file_size; |
| 95 | | const file_name = try header.fullFileName(&file_name_buffer); |
| 97 | const unstripped_file_name = try header.fullFileName(&file_name_buffer); |
| 96 | 98 | switch (header.fileType()) { |
| 97 | 99 | .directory => { |
| 98 | | try dir.makeDir(file_name); |
| 100 | const file_name = try stripComponents(unstripped_file_name, options.strip_components); |
| 101 | if (file_name.len != 0) { |
| 102 | try dir.makeDir(file_name); |
| 103 | } |
| 99 | 104 | }, |
| 100 | 105 | .normal => { |
| 101 | | if (file_size == 0 and file_name.len == 0) return; |
| 106 | if (file_size == 0 and unstripped_file_name.len == 0) return; |
| 107 | const file_name = try stripComponents(unstripped_file_name, options.strip_components); |
| 102 | 108 | |
| 103 | 109 | var file = try dir.createFile(file_name, .{}); |
| 104 | 110 | defer file.close(); |
| ... | ... | @@ -140,5 +146,25 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi |
| 140 | 146 | } |
| 141 | 147 | } |
| 142 | 148 | |
| 149 | fn stripComponents(path: []const u8, count: u32) ![]const u8 { |
| 150 | var i: usize = 0; |
| 151 | var c = count; |
| 152 | while (c > 0) : (c -= 1) { |
| 153 | if (std.mem.indexOfScalarPos(u8, path, i, '/')) |pos| { |
| 154 | i = pos + 1; |
| 155 | } else { |
| 156 | return error.TarComponentsOutsideStrippedPrefix; |
| 157 | } |
| 158 | } |
| 159 | return path[i..]; |
| 160 | } |
| 161 | |
| 162 | test stripComponents { |
| 163 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 164 | try expectEqualStrings("a/b/c", try stripComponents("a/b/c", 0)); |
| 165 | try expectEqualStrings("b/c", try stripComponents("a/b/c", 1)); |
| 166 | try expectEqualStrings("c", try stripComponents("a/b/c", 2)); |
| 167 | } |
| 168 | |
| 143 | 169 | const std = @import("std.zig"); |
| 144 | 170 | const assert = std.debug.assert; |