diff options
| author | Igor Anić <igor.anic@gmail.com> | 2024-03-02 10:59:25 +0100 |
|---|---|---|
| committer | Igor Anić <igor.anic@gmail.com> | 2024-03-11 12:22:12 +0100 |
| commit | 5ccbb196ad08fd5e58fc8874917a20f9a220d729 (patch) | |
| tree | 6fc7e2dcbbd745696058892b30ff384dab2767b4 /lib | |
| parent | 10add7c677d368501691178ea0c073a9766cd498 (diff) | |
| download | zig-5ccbb196ad08fd5e58fc8874917a20f9a220d729.tar.gz zig-5ccbb196ad08fd5e58fc8874917a20f9a220d729.zip | |
std.tar: don't return in iterator init
Don't assert min buffer size on iterator init. That was changing public
interface. This way we don't break that interface.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/tar.zig | 34 | ||||
| -rw-r--r-- | lib/std/tar/test.zig | 600 |
2 files changed, 320 insertions, 314 deletions
diff --git a/lib/std/tar.zig b/lib/std/tar.zig index 0eab2456d7..6bf46ad507 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -115,9 +115,10 @@ pub const Header = struct { /// Includes prefix concatenated, if any. /// TODO: check against "../" and other nefarious things - pub fn fullName(header: Header, buffer: *[MAX_NAME_SIZE]u8) ![]const u8 { + pub fn fullName(header: Header, buffer: []u8) ![]const u8 { const n = name(header); const p = prefix(header); + if (buffer.len < n.len + p.len + 1) return error.TarInsufficientBuffer; if (!is_ustar(header) or p.len == 0) { @memcpy(buffer[0..n.len], n); return buffer[0..n.len]; @@ -130,11 +131,12 @@ pub const Header = struct { /// When kind is symbolic_link linked-to name (target_path) is specified in /// the linkname field. - pub fn linkName(header: Header, buffer: *[LINK_NAME_SIZE]u8) []const u8 { + pub fn linkName(header: Header, buffer: []u8) ![]const u8 { const link_name = header.str(157, 100); if (link_name.len == 0) { return buffer[0..0]; } + if (buffer.len < link_name.len) return error.TarInsufficientBuffer; const buf = buffer[0..link_name.len]; @memcpy(buf, link_name); return buf; @@ -248,13 +250,7 @@ pub const IteratorOptions = struct { /// Iterates over files in tar archive. /// `next` returns each file in `reader` tar archive. -/// Provided buffers should be at least 256 bytes for file_name and 100 bytes -/// for link_name. -pub fn iterator(reader: anytype, options: IteratorOptions) !Iterator(@TypeOf(reader)) { - if (options.file_name_buffer.len < Header.MAX_NAME_SIZE or - options.link_name_buffer.len < Header.LINK_NAME_SIZE) - return error.TarInsufficientBuffer; - +pub fn iterator(reader: anytype, options: IteratorOptions) Iterator(@TypeOf(reader)) { return .{ .reader = reader, .diagnostics = options.diagnostics, @@ -372,10 +368,10 @@ fn Iterator(comptime ReaderType: type) type { self.file.size = size; } if (self.file.link_name.len == 0) { - self.file.link_name = header.linkName(self.link_name_buffer[0..Header.LINK_NAME_SIZE]); + self.file.link_name = try header.linkName(self.link_name_buffer); } if (self.file.name.len == 0) { - self.file.name = try header.fullName(self.file_name_buffer[0..Header.MAX_NAME_SIZE]); + self.file.name = try header.fullName(self.file_name_buffer); } self.padding = blockPadding(self.file.size); @@ -565,7 +561,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi var file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; var link_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - var iter = try iterator(reader, .{ + var iter = iterator(reader, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, .diagnostics = options.diagnostics, @@ -871,17 +867,3 @@ test "create file and symlink" { _ = try createDirAndSymlink(root.dir, "../../../g/h/i/file4", "j/k/l/symlink3"); _ = try createDirAndFile(root.dir, "g/h/i/file4"); } - -test "insufficient buffer for iterator" { - var file_name_buffer: [10]u8 = undefined; - var link_name_buffer: [10]u8 = undefined; - - var fsb = std.io.fixedBufferStream(""); - try std.testing.expectError( - error.TarInsufficientBuffer, - iterator(fsb.reader(), .{ - .file_name_buffer = &file_name_buffer, - .link_name_buffer = &link_name_buffer, - }), - ); -} diff --git a/lib/std/tar/test.zig b/lib/std/tar/test.zig index 9532306728..7cd0cb7544 100644 --- a/lib/std/tar/test.zig +++ b/lib/std/tar/test.zig @@ -2,333 +2,352 @@ const std = @import("std"); const tar = @import("../tar.zig"); const testing = std.testing; -test "run test cases" { - const Case = struct { - const File = struct { - name: []const u8, - size: u64 = 0, - mode: u32 = 0, - link_name: []const u8 = &[0]u8{}, - kind: tar.Header.Kind = .normal, - truncated: bool = false, // when there is no file body, just header, usefull for huge files - }; - - data: []const u8, // testdata file content - files: []const File = &[_]@This().File{}, // expected files to found in archive - chksums: []const []const u8 = &[_][]const u8{}, // chksums of each file content - err: ?anyerror = null, // parsing should fail with this error +const Case = struct { + const File = struct { + name: []const u8, + size: u64 = 0, + mode: u32 = 0, + link_name: []const u8 = &[0]u8{}, + kind: tar.Header.Kind = .normal, + truncated: bool = false, // when there is no file body, just header, usefull for huge files }; - const cases = [_]Case{ - .{ - .data = @embedFile("testdata/gnu.tar"), - .files = &[_]Case.File{ - .{ - .name = "small.txt", - .size = 5, - .mode = 0o640, - }, - .{ - .name = "small2.txt", - .size = 11, - .mode = 0o640, - }, + data: []const u8, // testdata file content + files: []const File = &[_]@This().File{}, // expected files to found in archive + chksums: []const []const u8 = &[_][]const u8{}, // chksums of each file content + err: ?anyerror = null, // parsing should fail with this error +}; + +const cases = [_]Case{ + .{ + .data = @embedFile("testdata/gnu.tar"), + .files = &[_]Case.File{ + .{ + .name = "small.txt", + .size = 5, + .mode = 0o640, }, - .chksums = &[_][]const u8{ - "e38b27eaccb4391bdec553a7f3ae6b2f", - "c65bd2e50a56a2138bf1716f2fd56fe9", + .{ + .name = "small2.txt", + .size = 11, + .mode = 0o640, }, }, - .{ - .data = @embedFile("testdata/sparse-formats.tar"), - .err = error.TarUnsupportedHeader, + .chksums = &[_][]const u8{ + "e38b27eaccb4391bdec553a7f3ae6b2f", + "c65bd2e50a56a2138bf1716f2fd56fe9", }, - .{ - .data = @embedFile("testdata/star.tar"), - .files = &[_]Case.File{ - .{ - .name = "small.txt", - .size = 5, - .mode = 0o640, - }, - .{ - .name = "small2.txt", - .size = 11, - .mode = 0o640, - }, + }, + .{ + .data = @embedFile("testdata/sparse-formats.tar"), + .err = error.TarUnsupportedHeader, + }, + .{ + .data = @embedFile("testdata/star.tar"), + .files = &[_]Case.File{ + .{ + .name = "small.txt", + .size = 5, + .mode = 0o640, }, - .chksums = &[_][]const u8{ - "e38b27eaccb4391bdec553a7f3ae6b2f", - "c65bd2e50a56a2138bf1716f2fd56fe9", + .{ + .name = "small2.txt", + .size = 11, + .mode = 0o640, }, }, - .{ - .data = @embedFile("testdata/v7.tar"), - .files = &[_]Case.File{ - .{ - .name = "small.txt", - .size = 5, - .mode = 0o444, - }, - .{ - .name = "small2.txt", - .size = 11, - .mode = 0o444, - }, - }, - .chksums = &[_][]const u8{ - "e38b27eaccb4391bdec553a7f3ae6b2f", - "c65bd2e50a56a2138bf1716f2fd56fe9", - }, + .chksums = &[_][]const u8{ + "e38b27eaccb4391bdec553a7f3ae6b2f", + "c65bd2e50a56a2138bf1716f2fd56fe9", }, - .{ - .data = @embedFile("testdata/pax.tar"), - .files = &[_]Case.File{ - .{ - .name = "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", - .size = 7, - .mode = 0o664, - }, - .{ - .name = "a/b", - .size = 0, - .kind = .symbolic_link, - .mode = 0o777, - .link_name = "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", - }, + }, + .{ + .data = @embedFile("testdata/v7.tar"), + .files = &[_]Case.File{ + .{ + .name = "small.txt", + .size = 5, + .mode = 0o444, }, - .chksums = &[_][]const u8{ - "3c382e8f5b6631aa2db52643912ffd4a", + .{ + .name = "small2.txt", + .size = 11, + .mode = 0o444, }, }, - .{ - // pax attribute don't end with \n - .data = @embedFile("testdata/pax-bad-hdr-file.tar"), - .err = error.PaxInvalidAttributeEnd, + .chksums = &[_][]const u8{ + "e38b27eaccb4391bdec553a7f3ae6b2f", + "c65bd2e50a56a2138bf1716f2fd56fe9", }, - .{ - // size is in pax attribute - .data = @embedFile("testdata/pax-pos-size-file.tar"), - .files = &[_]Case.File{ - .{ - .name = "foo", - .size = 999, - .kind = .normal, - .mode = 0o640, - }, + }, + .{ + .data = @embedFile("testdata/pax.tar"), + .files = &[_]Case.File{ + .{ + .name = "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", + .size = 7, + .mode = 0o664, }, - .chksums = &[_][]const u8{ - "0afb597b283fe61b5d4879669a350556", + .{ + .name = "a/b", + .size = 0, + .kind = .symbolic_link, + .mode = 0o777, + .link_name = "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", }, }, - .{ - // has pax records which we are not interested in - .data = @embedFile("testdata/pax-records.tar"), - .files = &[_]Case.File{ - .{ - .name = "file", - }, + .chksums = &[_][]const u8{ + "3c382e8f5b6631aa2db52643912ffd4a", + }, + }, + .{ + // pax attribute don't end with \n + .data = @embedFile("testdata/pax-bad-hdr-file.tar"), + .err = error.PaxInvalidAttributeEnd, + }, + .{ + // size is in pax attribute + .data = @embedFile("testdata/pax-pos-size-file.tar"), + .files = &[_]Case.File{ + .{ + .name = "foo", + .size = 999, + .kind = .normal, + .mode = 0o640, }, }, - .{ - // has global records which we are ignoring - .data = @embedFile("testdata/pax-global-records.tar"), - .files = &[_]Case.File{ - .{ - .name = "file1", - }, - .{ - .name = "file2", - }, - .{ - .name = "file3", - }, - .{ - .name = "file4", - }, + .chksums = &[_][]const u8{ + "0afb597b283fe61b5d4879669a350556", + }, + }, + .{ + // has pax records which we are not interested in + .data = @embedFile("testdata/pax-records.tar"), + .files = &[_]Case.File{ + .{ + .name = "file", }, }, - .{ - .data = @embedFile("testdata/nil-uid.tar"), - .files = &[_]Case.File{ - .{ - .name = "P1050238.JPG.log", - .size = 14, - .kind = .normal, - .mode = 0o664, - }, + }, + .{ + // has global records which we are ignoring + .data = @embedFile("testdata/pax-global-records.tar"), + .files = &[_]Case.File{ + .{ + .name = "file1", }, - .chksums = &[_][]const u8{ - "08d504674115e77a67244beac19668f5", + .{ + .name = "file2", }, - }, - .{ - // has xattrs and pax records which we are ignoring - .data = @embedFile("testdata/xattrs.tar"), - .files = &[_]Case.File{ - .{ - .name = "small.txt", - .size = 5, - .kind = .normal, - .mode = 0o644, - }, - .{ - .name = "small2.txt", - .size = 11, - .kind = .normal, - .mode = 0o644, - }, + .{ + .name = "file3", }, - .chksums = &[_][]const u8{ - "e38b27eaccb4391bdec553a7f3ae6b2f", - "c65bd2e50a56a2138bf1716f2fd56fe9", + .{ + .name = "file4", }, }, - .{ - .data = @embedFile("testdata/gnu-multi-hdrs.tar"), - .files = &[_]Case.File{ - .{ - .name = "GNU2/GNU2/long-path-name", - .link_name = "GNU4/GNU4/long-linkpath-name", - .kind = .symbolic_link, - }, + }, + .{ + .data = @embedFile("testdata/nil-uid.tar"), + .files = &[_]Case.File{ + .{ + .name = "P1050238.JPG.log", + .size = 14, + .kind = .normal, + .mode = 0o664, }, }, - .{ - // has gnu type D (directory) and S (sparse) blocks - .data = @embedFile("testdata/gnu-incremental.tar"), - .err = error.TarUnsupportedHeader, + .chksums = &[_][]const u8{ + "08d504674115e77a67244beac19668f5", }, - .{ - // should use values only from last pax header - .data = @embedFile("testdata/pax-multi-hdrs.tar"), - .files = &[_]Case.File{ - .{ - .name = "bar", - .link_name = "PAX4/PAX4/long-linkpath-name", - .kind = .symbolic_link, - }, + }, + .{ + // has xattrs and pax records which we are ignoring + .data = @embedFile("testdata/xattrs.tar"), + .files = &[_]Case.File{ + .{ + .name = "small.txt", + .size = 5, + .kind = .normal, + .mode = 0o644, }, - }, - .{ - .data = @embedFile("testdata/gnu-long-nul.tar"), - .files = &[_]Case.File{ - .{ - .name = "0123456789", - .mode = 0o644, - }, + .{ + .name = "small2.txt", + .size = 11, + .kind = .normal, + .mode = 0o644, }, }, - .{ - .data = @embedFile("testdata/gnu-utf8.tar"), - .files = &[_]Case.File{ - .{ - .name = "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹", - .mode = 0o644, - }, - }, + .chksums = &[_][]const u8{ + "e38b27eaccb4391bdec553a7f3ae6b2f", + "c65bd2e50a56a2138bf1716f2fd56fe9", }, - .{ - .data = @embedFile("testdata/gnu-not-utf8.tar"), - .files = &[_]Case.File{ - .{ - .name = "hi\x80\x81\x82\x83bye", - .mode = 0o644, - }, + }, + .{ + .data = @embedFile("testdata/gnu-multi-hdrs.tar"), + .files = &[_]Case.File{ + .{ + .name = "GNU2/GNU2/long-path-name", + .link_name = "GNU4/GNU4/long-linkpath-name", + .kind = .symbolic_link, }, }, - .{ - // null in pax key - .data = @embedFile("testdata/pax-nul-xattrs.tar"), - .err = error.PaxNullInKeyword, - }, - .{ - .data = @embedFile("testdata/pax-nul-path.tar"), - .err = error.PaxNullInValue, - }, - .{ - .data = @embedFile("testdata/neg-size.tar"), - .err = error.TarHeader, - }, - .{ - .data = @embedFile("testdata/issue10968.tar"), - .err = error.TarHeader, - }, - .{ - .data = @embedFile("testdata/issue11169.tar"), - .err = error.TarHeader, + }, + .{ + // has gnu type D (directory) and S (sparse) blocks + .data = @embedFile("testdata/gnu-incremental.tar"), + .err = error.TarUnsupportedHeader, + }, + .{ + // should use values only from last pax header + .data = @embedFile("testdata/pax-multi-hdrs.tar"), + .files = &[_]Case.File{ + .{ + .name = "bar", + .link_name = "PAX4/PAX4/long-linkpath-name", + .kind = .symbolic_link, + }, }, - .{ - .data = @embedFile("testdata/issue12435.tar"), - .err = error.TarHeaderChksum, + }, + .{ + .data = @embedFile("testdata/gnu-long-nul.tar"), + .files = &[_]Case.File{ + .{ + .name = "0123456789", + .mode = 0o644, + }, }, - .{ - // has magic with space at end instead of null - .data = @embedFile("testdata/invalid-go17.tar"), - .files = &[_]Case.File{ - .{ - .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", - }, + }, + .{ + .data = @embedFile("testdata/gnu-utf8.tar"), + .files = &[_]Case.File{ + .{ + .name = "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹", + .mode = 0o644, }, }, - .{ - .data = @embedFile("testdata/ustar-file-devs.tar"), - .files = &[_]Case.File{ - .{ - .name = "file", - .mode = 0o644, - }, + }, + .{ + .data = @embedFile("testdata/gnu-not-utf8.tar"), + .files = &[_]Case.File{ + .{ + .name = "hi\x80\x81\x82\x83bye", + .mode = 0o644, }, }, - .{ - .data = @embedFile("testdata/trailing-slash.tar"), - .files = &[_]Case.File{ - .{ - .name = "123456789/" ** 30, - .kind = .directory, - }, + }, + .{ + // null in pax key + .data = @embedFile("testdata/pax-nul-xattrs.tar"), + .err = error.PaxNullInKeyword, + }, + .{ + .data = @embedFile("testdata/pax-nul-path.tar"), + .err = error.PaxNullInValue, + }, + .{ + .data = @embedFile("testdata/neg-size.tar"), + .err = error.TarHeader, + }, + .{ + .data = @embedFile("testdata/issue10968.tar"), + .err = error.TarHeader, + }, + .{ + .data = @embedFile("testdata/issue11169.tar"), + .err = error.TarHeader, + }, + .{ + .data = @embedFile("testdata/issue12435.tar"), + .err = error.TarHeaderChksum, + }, + .{ + // has magic with space at end instead of null + .data = @embedFile("testdata/invalid-go17.tar"), + .files = &[_]Case.File{ + .{ + .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", }, }, - .{ - // Has size in gnu extended format. To represent size bigger than 8 GB. - .data = @embedFile("testdata/writer-big.tar"), - .files = &[_]Case.File{ - .{ - .name = "tmp/16gig.txt", - .size = 16 * 1024 * 1024 * 1024, - .truncated = true, - .mode = 0o640, - }, + }, + .{ + .data = @embedFile("testdata/ustar-file-devs.tar"), + .files = &[_]Case.File{ + .{ + .name = "file", + .mode = 0o644, }, }, - .{ - // Size in gnu extended format, and name in pax attribute. - .data = @embedFile("testdata/writer-big-long.tar"), - .files = &[_]Case.File{ - .{ - .name = "longname/" ** 15 ++ "16gig.txt", - .size = 16 * 1024 * 1024 * 1024, - .mode = 0o644, - .truncated = true, - }, + }, + .{ + .data = @embedFile("testdata/trailing-slash.tar"), + .files = &[_]Case.File{ + .{ + .name = "123456789/" ** 30, + .kind = .directory, }, }, - .{ - .data = @embedFile("testdata/fuzz1.tar"), - .err = error.TarInsufficientBuffer, + }, + .{ + // Has size in gnu extended format. To represent size bigger than 8 GB. + .data = @embedFile("testdata/writer-big.tar"), + .files = &[_]Case.File{ + .{ + .name = "tmp/16gig.txt", + .size = 16 * 1024 * 1024 * 1024, + .truncated = true, + .mode = 0o640, + }, }, - .{ - .data = @embedFile("testdata/fuzz2.tar"), - .err = error.PaxSizeAttrOverflow, + }, + .{ + // Size in gnu extended format, and name in pax attribute. + .data = @embedFile("testdata/writer-big-long.tar"), + .files = &[_]Case.File{ + .{ + .name = "longname/" ** 15 ++ "16gig.txt", + .size = 16 * 1024 * 1024 * 1024, + .mode = 0o644, + .truncated = true, + }, }, - }; + }, + .{ + .data = @embedFile("testdata/fuzz1.tar"), + .err = error.TarInsufficientBuffer, + }, + .{ + .data = @embedFile("testdata/fuzz2.tar"), + .err = error.PaxSizeAttrOverflow, + }, +}; + +// used in test to calculate file chksum +const Md5Writer = struct { + h: std.crypto.hash.Md5 = std.crypto.hash.Md5.init(.{}), + + pub fn writeAll(self: *Md5Writer, buf: []const u8) !void { + self.h.update(buf); + } + + pub fn writeByte(self: *Md5Writer, byte: u8) !void { + self.h.update(&[_]u8{byte}); + } + pub fn chksum(self: *Md5Writer) [32]u8 { + var s = [_]u8{0} ** 16; + self.h.final(&s); + return std.fmt.bytesToHex(s, .lower); + } +}; + +test "run test cases" { var file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; var link_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; for (cases) |case| { var fsb = std.io.fixedBufferStream(case.data); - var iter = try tar.iterator(fsb.reader(), .{ + var iter = tar.iterator(fsb.reader(), .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, }); @@ -359,6 +378,10 @@ test "run test cases" { } try testing.expectEqual(case.files.len, i); } +} + +test "pax/gnu long names with small buffer" { + // should fail with insufficient buffer error var min_file_name_buffer: [tar.Header.MAX_NAME_SIZE]u8 = undefined; var min_link_name_buffer: [tar.Header.LINK_NAME_SIZE]u8 = undefined; @@ -366,7 +389,7 @@ test "run test cases" { for (long_name_cases) |case| { var fsb = std.io.fixedBufferStream(case.data); - var iter = try tar.iterator(fsb.reader(), .{ + var iter = tar.iterator(fsb.reader(), .{ .file_name_buffer = &min_file_name_buffer, .link_name_buffer = &min_link_name_buffer, }); @@ -382,24 +405,25 @@ test "run test cases" { } } -// used in test to calculate file chksum -const Md5Writer = struct { - h: std.crypto.hash.Md5 = std.crypto.hash.Md5.init(.{}), +test "insufficient buffer in Header name filed" { + var min_file_name_buffer: [9]u8 = undefined; + var min_link_name_buffer: [tar.Header.LINK_NAME_SIZE]u8 = undefined; - pub fn writeAll(self: *Md5Writer, buf: []const u8) !void { - self.h.update(buf); - } + var fsb = std.io.fixedBufferStream(cases[0].data); + var iter = tar.iterator(fsb.reader(), .{ + .file_name_buffer = &min_file_name_buffer, + .link_name_buffer = &min_link_name_buffer, + }); - pub fn writeByte(self: *Md5Writer, byte: u8) !void { - self.h.update(&[_]u8{byte}); - } + var iter_err: ?anyerror = null; + while (iter.next() catch |err| brk: { + iter_err = err; + break :brk null; + }) |_| {} - pub fn chksum(self: *Md5Writer) [32]u8 { - var s = [_]u8{0} ** 16; - self.h.final(&s); - return std.fmt.bytesToHex(s, .lower); - } -}; + try testing.expect(iter_err != null); + try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); +} test "should not overwrite existing file" { // Starting from this folder structure: |
