struct PaxIterator [src]

Fields

size: usize
reader: *std.Io.Reader

Members

Source

pub const PaxIterator = struct { size: usize, // cumulative size of all pax attributes reader: *std.Io.Reader, const Self = @This(); const Attribute = struct { kind: PaxAttributeKind, len: usize, // length of the attribute value reader: *std.Io.Reader, // reader positioned at value start // Copies pax attribute value into destination buffer. // Must be called with destination buffer of size at least Attribute.len. pub fn value(self: Attribute, dst: []u8) ![]const u8 { if (self.len > dst.len) return error.TarInsufficientBuffer; // assert(self.len <= dst.len); const buf = dst[0..self.len]; const n = try self.reader.readSliceShort(buf); if (n < self.len) return error.UnexpectedEndOfStream; try validateAttributeEnding(self.reader); if (hasNull(buf)) return error.PaxNullInValue; return buf; } }; // Iterates over pax attributes. Returns known only known attributes. // Caller has to call value in Attribute, to advance reader across value. pub fn next(self: *Self) !?Attribute { // Pax extended header consists of one or more attributes, each constructed as follows: // "%d %s=%s\n", , , while (self.size > 0) { const length_buf = try self.reader.takeSentinel(' '); const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes const keyword = try self.reader.takeSentinel('='); if (hasNull(keyword)) return error.PaxNullInKeyword; // calculate value_len const value_start = length_buf.len + keyword.len + 2; // 2 separators if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream; const value_len = length - value_start - 1; // \n separator at end self.size -= length; const kind: PaxAttributeKind = if (eql(keyword, "path")) .path else if (eql(keyword, "linkpath")) .linkpath else if (eql(keyword, "size")) .size else { try self.reader.discardAll(value_len); try validateAttributeEnding(self.reader); continue; }; if (kind == .size and value_len > pax_max_size_attr_len) { return error.PaxSizeAttrOverflow; } return .{ .kind = kind, .len = value_len, .reader = self.reader, }; } return null; } fn eql(a: []const u8, b: []const u8) bool { return std.mem.eql(u8, a, b); } fn hasNull(str: []const u8) bool { return (std.mem.indexOfScalar(u8, str, 0)) != null; } // Checks that each record ends with new line. fn validateAttributeEnding(reader: *std.Io.Reader) !void { if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd; } }