DoxigAlpha

next

Iterates through the tar archive as if it is a series of files. Internally, the tar format often uses entries (header with optional content) to add meta data that describes the next file. These entries should not normally be visible to the outside. As such, this loop iterates through one or more entries until it collects a all file attributes.

Function parameters

Parameters

#
self:*Iterator

Type definitions in this namespace

Types

#
Diagnostics
Provide this to receive detailed error messages.
PipeOptions
pipeToFileSystem options
FileKind
Type of the file returned by iterator `next` method.
Iterator
Iterator over entries in the tar file represented by reader.

Saves tar file content to the file systems.

Functions

#
pipeToFileSystem
Saves tar file content to the file systems.

Source

Implementation

#
pub fn next(self: *Iterator) !?File {
    if (self.unread_file_bytes > 0) {
        // If file content was not consumed by caller
        try self.reader.discardAll64(self.unread_file_bytes);
        self.unread_file_bytes = 0;
    }
    var file: File = self.newFile();

    while (try self.readHeader()) |header| {
        const kind = header.kind();
        const size: u64 = try header.size();
        self.padding = blockPadding(size);

        switch (kind) {
            // File types to return upstream
            .directory, .normal, .symbolic_link => {
                file.kind = switch (kind) {
                    .directory => .directory,
                    .normal => .file,
                    .symbolic_link => .sym_link,
                    else => unreachable,
                };
                file.mode = try header.mode();

                // set file attributes if not already set by prefix/extended headers
                if (file.size == 0) {
                    file.size = size;
                }
                if (file.link_name.len == 0) {
                    file.link_name = try header.linkName(self.link_name_buffer);
                }
                if (file.name.len == 0) {
                    file.name = try header.fullName(self.file_name_buffer);
                }

                self.padding = blockPadding(file.size);
                self.unread_file_bytes = file.size;
                return file;
            },
            // Prefix header types
            .gnu_long_name => {
                file.name = try self.readString(@intCast(size), self.file_name_buffer);
            },
            .gnu_long_link => {
                file.link_name = try self.readString(@intCast(size), self.link_name_buffer);
            },
            .extended_header => {
                // Use just attributes from last extended header.
                file = self.newFile();

                var rdr: PaxIterator = .{
                    .reader = self.reader,
                    .size = @intCast(size),
                };
                while (try rdr.next()) |attr| {
                    switch (attr.kind) {
                        .path => {
                            file.name = try attr.value(self.file_name_buffer);
                        },
                        .linkpath => {
                            file.link_name = try attr.value(self.link_name_buffer);
                        },
                        .size => {
                            var buf: [pax_max_size_attr_len]u8 = undefined;
                            file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10);
                        },
                    }
                }
            },
            // Ignored header type
            .global_extended_header => {
                self.reader.discardAll64(size) catch return error.TarHeadersTooBig;
            },
            // All other are unsupported header types
            else => {
                const d = self.diagnostics orelse return error.TarUnsupportedHeader;
                try d.errors.append(d.allocator, .{ .unsupported_file_type = .{
                    .file_name = try d.allocator.dupe(u8, header.name()),
                    .file_type = kind,
                } });
                if (kind == .gnu_sparse) {
                    try self.skipGnuSparseExtendedHeaders(header);
                }
                self.reader.discardAll64(size) catch return error.TarHeadersTooBig;
            },
        }
    }
    return null;
}