mirror of
https://github.com/SimoneN64/Kaizen.git
synced 2025-04-02 10:41:53 -04:00
93 lines
2.7 KiB
C
93 lines
2.7 KiB
C
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
|
License: LGPLv3 */
|
|
|
|
#include "tar.h"
|
|
|
|
static void tar_close(ar_archive *ar)
|
|
{
|
|
ar_archive_tar *tar = (ar_archive_tar *)ar;
|
|
free(tar->entry.name);
|
|
}
|
|
|
|
static bool tar_parse_entry(ar_archive *ar, off64_t offset)
|
|
{
|
|
ar_archive_tar *tar = (ar_archive_tar *)ar;
|
|
|
|
if (!ar_seek(ar->stream, offset, SEEK_SET)) {
|
|
warn("Couldn't seek to offset %" PRIi64, offset);
|
|
return false;
|
|
}
|
|
if (!tar_parse_header(tar)) {
|
|
warn("Invalid tar header data @%" PRIi64, offset);
|
|
return false;
|
|
}
|
|
if (!tar->entry.checksum) {
|
|
ar->at_eof = true;
|
|
return false;
|
|
}
|
|
|
|
ar->entry_offset = offset;
|
|
ar->entry_offset_next = offset + TAR_BLOCK_SIZE + (tar->entry.filesize + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE * TAR_BLOCK_SIZE;
|
|
ar->entry_size_uncompressed = tar->entry.filesize;
|
|
ar->entry_filetime = tar->entry.mtime;
|
|
tar->bytes_done = 0;
|
|
|
|
if (tar->last_seen_dir > offset)
|
|
tar->last_seen_dir = 0;
|
|
|
|
switch (tar->entry.filetype) {
|
|
case TYPE_FILE:
|
|
case TYPE_FILE_OLD:
|
|
return true;
|
|
case TYPE_DIRECTORY:
|
|
log("Skipping directory entry \"%s\"", tar_get_name(ar, false));
|
|
tar->last_seen_dir = ar->entry_offset;
|
|
return tar_parse_entry(ar, ar->entry_offset_next);
|
|
case TYPE_PAX_GLOBAL:
|
|
log("Skipping PAX global extended header record");
|
|
return tar_parse_entry(ar, ar->entry_offset_next);
|
|
case TYPE_PAX_EXTENDED:
|
|
return tar_handle_pax_extended(ar);
|
|
case TYPE_GNU_LONGNAME:
|
|
return tar_handle_gnu_longname(ar);
|
|
default:
|
|
warn("Unknown entry type '%c'", tar->entry.filetype);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static bool tar_uncompress(ar_archive *ar, void *buffer, size_t count)
|
|
{
|
|
ar_archive_tar *tar = (ar_archive_tar *)ar;
|
|
if (count > ar->entry_size_uncompressed - tar->bytes_done) {
|
|
warn("Requesting too much data (%" PRIuPTR " < %" PRIuPTR ")", ar->entry_size_uncompressed - tar->bytes_done, count);
|
|
return false;
|
|
}
|
|
if (ar_read(ar->stream, buffer, count) != count) {
|
|
warn("Unexpected EOF in stored data");
|
|
return false;
|
|
}
|
|
tar->bytes_done += count;
|
|
return true;
|
|
}
|
|
|
|
ar_archive *ar_open_tar_archive(ar_stream *stream)
|
|
{
|
|
ar_archive *ar;
|
|
ar_archive_tar *tar;
|
|
|
|
if (!ar_seek(stream, 0, SEEK_SET))
|
|
return NULL;
|
|
|
|
ar = ar_open_archive(stream, sizeof(ar_archive_tar), tar_close, tar_parse_entry, tar_get_name, tar_uncompress, NULL, 0);
|
|
if (!ar)
|
|
return NULL;
|
|
|
|
tar = (ar_archive_tar *)ar;
|
|
if (!tar_parse_header(tar) || !tar->entry.checksum) {
|
|
free(ar);
|
|
return NULL;
|
|
}
|
|
|
|
return ar;
|
|
}
|