Refactor read_data:

* New read_data_block is both sparse-file aware and uses zero-copy semantics
 * Push read_data_block down into specific formats (opens door to
   various encoded entry bodies, such as zip or gtar -S)
 * Reimplement read_data, read_data_skip, read_data_into_fd in terms
   of new read_data_block.
 * Update documentation
It's unfortunate that I couldn't just call the new interface
archive_read_data, but didn't want to upset the API that much.
This commit is contained in:
Tim Kientzle 2004-06-02 08:14:43 +00:00
parent aa0aa7a113
commit e250dd4fad
8 changed files with 299 additions and 130 deletions

View File

@ -166,6 +166,14 @@ int64_t archive_read_header_position(struct archive *);
/* Read data from the body of an entry. Similar to read(2). */
ssize_t archive_read_data(struct archive *, void *, size_t);
/*
* A zero-copy version of archive_read_data that also exposes the file offset
* of each returned block. Note that the client has no way to specify
* the desired size of the block. The API does gaurantee that offsets will
* be strictly increasing and that returned blocks will not overlap.
*/
int archive_read_data_block(struct archive *a,
const void **buff, size_t *size, off_t *offset);
/*-
* Some convenience functions that are built on archive_read_data:

View File

@ -166,6 +166,14 @@ int64_t archive_read_header_position(struct archive *);
/* Read data from the body of an entry. Similar to read(2). */
ssize_t archive_read_data(struct archive *, void *, size_t);
/*
* A zero-copy version of archive_read_data that also exposes the file offset
* of each returned block. Note that the client has no way to specify
* the desired size of the block. The API does gaurantee that offsets will
* be strictly increasing and that returned blocks will not overlap.
*/
int archive_read_data_block(struct archive *a,
const void **buff, size_t *size, off_t *offset);
/*-
* Some convenience functions that are built on archive_read_data:

View File

@ -54,12 +54,13 @@ struct archive {
size_t null_length;
/*
* Used to limit reads of entry data. Eventually, each reader
* will be able to register it's own read_data routine and these
* will move into the per-format data for the formats that use them.
* Used by archive_read_data() to track blocks and copy
* data to client buffers, filling gaps with zero bytes.
*/
off_t entry_bytes_remaining;
off_t entry_padding; /* Skip this much after entry data. */
const char *read_data_block;
off_t read_data_offset;
off_t read_data_output_offset;
size_t read_data_remaining;
uid_t user_uid; /* UID of current user. */
@ -151,6 +152,7 @@ struct archive {
struct archive_format_descriptor {
int (*bid)(struct archive *);
int (*read_header)(struct archive *, struct archive_entry *);
int (*read_data)(struct archive *, const void **, size_t *, off_t *);
int (*cleanup)(struct archive *);
void *format_data; /* Format-specific data for readers. */
} formats[4];
@ -168,9 +170,8 @@ struct archive {
void *format_data; /* Used by writers. */
/*
* Pointers to format-specific functions. On read, these are
* initialized in the bid process. On write, they're initialized by
* archive_write_set_format_XXX() calls.
* Pointers to format-specific functions for writing. They're
* initialized by archive_write_set_format_XXX() calls.
*/
int (*format_init)(struct archive *); /* Only used on write. */
int (*format_finish)(struct archive *);
@ -220,6 +221,7 @@ int __archive_read_register_format(struct archive *a,
void *format_data,
int (*bid)(struct archive *),
int (*read_header)(struct archive *, struct archive_entry *),
int (*read_data)(struct archive *, const void **, size_t *, off_t *),
int (*cleanup)(struct archive *));
int __archive_read_register_compression(struct archive *a,

View File

@ -43,9 +43,10 @@
.Nm archive_read_open_file ,
.Nm archive_read_next_header ,
.Nm archive_read_data ,
.Nm archive_read_data_block ,
.Nm archive_read_data_skip ,
.Nm archive_read_data_into_buffer ,
.Nm archive_read_data_into_file ,
.Nm archive_read_data_into_fd ,
.Nm archive_read_extract ,
.Nm archive_read_extract_set_progress_callback ,
.Nm archive_read_finish
@ -83,11 +84,13 @@
.Ft ssize_t
.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
.Ft int
.Fn archive_read_data_block "struct archive *" "const void **buff" "size_t *len" "off_t *offset"
.Ft int
.Fn archive_read_data_skip "struct archive *"
.Ft int
.Fn archive_read_data_into_buffer "struct archive *" "void *"
.Ft int
.Fn archive_read_data_into_file "struct archive *" "int fd"
.Fn archive_read_data_into_fd "struct archive *" "int fd"
.Ft int
.Fn archive_read_extract "struct archive *" "int flags"
.Ft void
@ -165,18 +168,30 @@ a
.Tn struct archive_entry .
.It Fn archive_read_data
Read data associated with the header just read.
Internally, this is a convenience function that uses
.Fn archive_read_data_block .
.It Fn archive_read_data_block
Return the next available block of data for this entry.
Unlike
.Fn archive_read_data ,
the
.Fn archive_read_data_block
function avoids copying data and allows you to correctly handle
sparse files, as supported by some archive formats.
The library gaurantees that offsets will increase and that blocks
will not overlap.
.It Fn archive_read_data_skip
A convenience function that repeatedly calls
.Fn archive_read_data
.Fn archive_read_data_block
to skip all of the data for this archive entry.
.It Fn archive_read_data_into_buffer
A convenience function that repeatedly calls
.Fn archive_read_data
.Fn archive_read_data_block
to copy the entire entry into the client-supplied buffer.
Note that the client is responsible for sizing the buffer appropriately.
.It Fn archive_read_data_into_file
.It Fn archive_read_data_into_fd
A convenience function that repeatedly calls
.Fn archive_read_data
.Fn archive_read_data_block
to copy the entire entry to the provided file descriptor.
.It Fn archive_read_extract
A convenience function that recreates the specified object on

View File

@ -319,42 +319,61 @@ archive_read_header_position(struct archive *a)
}
/*
* Read data from an archive entry.
* Read data from an archive entry, using a read(2)-style interface.
* This is a convenience routine that just calls
* archive_read_data_block and copies the results into the client
* buffer, filling any gaps with zero bytes. Clients using this
* API can be completely ignorant of sparse-file issues; sparse files
* will simply be padded with nulls.
*/
ssize_t
archive_read_data(struct archive *a, void *buff, size_t s)
{
const void *data;
ssize_t bytes_read;
off_t remaining;
char *dest;
size_t bytes_read;
size_t len;
int r;
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA);
/*
* off_t is generally at least as wide as size_t, so widen for
* comparison and narrow for the assignment. Otherwise, on
* platforms with 32-bit size_t and 64-bit off_t, we won't be
* able to correctly read archives with entries larger than
* 4gig.
*/
if ((off_t)s > a->entry_bytes_remaining)
s = (size_t)a->entry_bytes_remaining;
if (s > 0) {
bytes_read = (a->compression_read_ahead)(a, &data, 1);
if (bytes_read < 0) {
a->state = ARCHIVE_STATE_FATAL;
return (bytes_read);
bytes_read = 0;
dest = buff;
while (s > 0) {
if (a->read_data_remaining <= 0) {
r = archive_read_data_block(a,
(const void **)&a->read_data_block,
&a->read_data_remaining,
&a->read_data_offset);
if (r == ARCHIVE_EOF)
return (bytes_read);
if (r != ARCHIVE_OK)
return (r);
}
if ((size_t)bytes_read > s)
bytes_read = s;
} else
bytes_read = 0;
if (bytes_read > 0) {
memcpy(buff, data, bytes_read);
(a->compression_read_consume)(a, bytes_read);
if (a->read_data_offset < a->read_data_output_offset) {
remaining =
a->read_data_output_offset - a->read_data_offset;
if (remaining > (off_t)s)
remaining = (off_t)s;
len = (size_t)remaining;
memset(dest, 0, len);
a->read_data_output_offset += len;
s -= len;
bytes_read += len;
} else {
len = a->read_data_remaining;
if (len > s)
len = s;
memcpy(dest, a->read_data_block, len);
s -= len;
a->read_data_remaining -= len;
a->read_data_output_offset += len;
a->read_data_offset += len;
dest += len;
bytes_read += len;
}
}
a->entry_bytes_remaining -= bytes_read;
return (bytes_read);
return (ARCHIVE_OK);
}
/*
@ -363,33 +382,46 @@ archive_read_data(struct archive *a, void *buff, size_t s)
int
archive_read_data_skip(struct archive *a)
{
int r;
const void *buff;
ssize_t bytes_read, to_skip;
ssize_t size;
off_t offset;
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA);
to_skip = a->entry_bytes_remaining + a->entry_padding;
a->entry_bytes_remaining = 0;
while ((r = archive_read_data_block(a, &buff, &size, &offset)) ==
ARCHIVE_OK)
;
if (r == ARCHIVE_EOF)
r = ARCHIVE_OK;
for (; to_skip > 0; to_skip -= bytes_read) {
/* TODO: Optimize skip in compression layer. */
bytes_read = (a->compression_read_ahead)(a, &buff, to_skip);
if (bytes_read < 0) {
a->entry_padding = to_skip;
return (ARCHIVE_FATAL);
}
if (bytes_read == 0) {
archive_set_error(a, EIO,
"Premature end of archive entry");
return (ARCHIVE_FATAL);
}
if (bytes_read > to_skip)
bytes_read = to_skip;
(a->compression_read_consume)(a, bytes_read);
}
a->entry_padding = 0;
a->state = ARCHIVE_STATE_HEADER;
return (ARCHIVE_OK);
return (r);
}
/*
* Read the next block of entry data from the archive.
* This is a zero-copy interface; the client receives a pointer,
* size, and file offset of the next available block of data.
*
* Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if
* the end of entry is encountered.
*/
int
archive_read_data_block(struct archive *a,
const void **buff, size_t *size, off_t *offset)
{
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA);
if (a->format->read_data == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
"No format_read_data_block function registered");
return (ARCHIVE_FATAL);
}
return (a->format->read_data)(a, buff, size, offset);
}
/*
@ -445,6 +477,7 @@ __archive_read_register_format(struct archive *a,
void *format_data,
int (*bid)(struct archive *),
int (*read_header)(struct archive *, struct archive_entry *),
int (*read_data)(struct archive *, const void **, size_t *, off_t *),
int (*cleanup)(struct archive *))
{
int i, number_slots;
@ -459,6 +492,7 @@ __archive_read_register_format(struct archive *a,
if (a->formats[i].bid == NULL) {
a->formats[i].bid = bid;
a->formats[i].read_header = read_header;
a->formats[i].read_data = read_data;
a->formats[i].cleanup = cleanup;
a->formats[i].format_data = format_data;
return (ARCHIVE_OK);

View File

@ -33,36 +33,49 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
/* Maximum amount of data to write at one time. */
#define MAX_WRITE (1024 * 1024)
/*
* This implementation minimizes copying of data.
* This implementation minimizes copying of data and is sparse-file aware.
*/
ssize_t
archive_read_data_into_fd(struct archive *a, int fd)
{
ssize_t bytes_read, bytes_written, total_written;
int r;
const void *buff;
ssize_t size, bytes_to_write;
ssize_t bytes_written, total_written;
off_t offset;
off_t output_offset;
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA);
total_written = 0;
while (a->entry_bytes_remaining > 0) {
/* Remember: '1' here is minimum, not maximum. */
/* Read-ahead function will return as much as is convenient. */
bytes_read = (a->compression_read_ahead)(a, &buff, 1);
if (bytes_read < 0)
return (-1);
if (bytes_read > a->entry_bytes_remaining)
bytes_read = (ssize_t)a->entry_bytes_remaining;
/* Don't copy more than 1 megabyte at a time. */
if (bytes_read > (1024*1024))
bytes_read = 1024*1024;
output_offset = 0;
bytes_written = write(fd, buff, bytes_read);
if (bytes_written < 0)
return (-1);
(a->compression_read_consume)(a, bytes_written);
total_written += bytes_written;
a->entry_bytes_remaining -= bytes_written;
if (a->extract_progress != NULL)
(*a->extract_progress)(a->extract_progress_user_data);
while ((r = archive_read_data_block(a, &buff, &size, &offset)) ==
ARCHIVE_OK) {
if (offset > output_offset) {
lseek(fd, offset - output_offset, SEEK_CUR);
output_offset = offset;
}
while (size > 0) {
bytes_to_write = size;
if (bytes_to_write > MAX_WRITE)
bytes_to_write = MAX_WRITE;
bytes_written = write(fd, buff, bytes_to_write);
if (bytes_written < 0)
return (-1);
output_offset += bytes_written;
total_written += bytes_written;
size -= bytes_written;
if (a->extract_progress != NULL)
(*a->extract_progress)(a->extract_progress_user_data);
}
}
if (r != ARCHIVE_EOF)
return (-1);
return (total_written);
}

View File

@ -97,27 +97,32 @@ struct links_entry {
#define CPIO_MAGIC 0x13141516
struct cpio {
int magic;
int (*read_header)(struct archive *, struct stat *,
size_t *, size_t *);
int (*read_header)(struct archive *, struct cpio *,
struct stat *, size_t *, size_t *);
struct links_entry *links_head;
struct archive_string entry_name;
struct archive_string entry_linkname;
off_t entry_bytes_remaining;
off_t entry_offset;
off_t entry_padding;
};
static int64_t atol16(const char *, unsigned);
static int64_t atol8(const char *, unsigned);
static int archive_read_format_cpio_bid(struct archive *);
static int archive_read_format_cpio_cleanup(struct archive *);
static int archive_read_format_cpio_read_data(struct archive *,
const void **, size_t *, off_t *);
static int archive_read_format_cpio_read_header(struct archive *,
struct archive_entry *);
static int be4(const unsigned char *);
static int header_bin_be(struct archive *, struct stat *,
static int header_bin_be(struct archive *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_bin_le(struct archive *, struct stat *,
static int header_bin_le(struct archive *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_newc(struct archive *, struct stat *,
static int header_newc(struct archive *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_odc(struct archive *, struct stat *,
static int header_odc(struct archive *, struct cpio *, struct stat *,
size_t *, size_t *);
static int le4(const unsigned char *);
static void record_hardlink(struct cpio *cpio, struct archive_entry *entry,
@ -137,6 +142,7 @@ archive_read_support_format_cpio(struct archive *a)
cpio,
archive_read_format_cpio_bid,
archive_read_format_cpio_read_header,
archive_read_format_cpio_read_data,
archive_read_format_cpio_cleanup);
if (r != ARCHIVE_OK)
@ -216,7 +222,7 @@ archive_read_format_cpio_read_header(struct archive *a,
memset(&st, 0, sizeof(st));
cpio = *(a->pformat_data);
r = (cpio->read_header(a, &st, &namelength, &name_pad));
r = (cpio->read_header(a, cpio, &st, &namelength, &name_pad));
if (r != ARCHIVE_OK)
return (r);
@ -231,18 +237,19 @@ archive_read_format_cpio_read_header(struct archive *a,
(a->compression_read_consume)(a, namelength + name_pad);
archive_strncpy(&cpio->entry_name, h, namelength);
archive_entry_set_pathname(entry, cpio->entry_name.s);
cpio->entry_offset = 0;
/* If this is a symlink, read the link contents. */
if (S_ISLNK(st.st_mode)) {
bytes = (a->compression_read_ahead)(a, &h,
a->entry_bytes_remaining);
if ((off_t)bytes < a->entry_bytes_remaining)
cpio->entry_bytes_remaining);
if ((off_t)bytes < cpio->entry_bytes_remaining)
return (ARCHIVE_FATAL);
(a->compression_read_consume)(a, a->entry_bytes_remaining);
(a->compression_read_consume)(a, cpio->entry_bytes_remaining);
archive_strncpy(&cpio->entry_linkname, h,
a->entry_bytes_remaining);
cpio->entry_bytes_remaining);
archive_entry_set_symlink(entry, cpio->entry_linkname.s);
a->entry_bytes_remaining = 0;
cpio->entry_bytes_remaining = 0;
}
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
@ -259,7 +266,44 @@ archive_read_format_cpio_read_header(struct archive *a,
}
static int
header_newc(struct archive *a, struct stat *st,
archive_read_format_cpio_read_data(struct archive *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
struct cpio *cpio;
cpio = *(a->pformat_data);
if (cpio->entry_bytes_remaining > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_bytes_remaining)
bytes_read = cpio->entry_bytes_remaining;
*size = bytes_read;
*offset = cpio->entry_offset;
cpio->entry_offset += bytes_read;
cpio->entry_bytes_remaining -= bytes_read;
(a->compression_read_consume)(a, bytes_read);
return (ARCHIVE_OK);
} else {
while (cpio->entry_padding > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_padding)
bytes_read = cpio->entry_padding;
(a->compression_read_consume)(a, bytes_read);
cpio->entry_padding -= bytes_read;
}
*buff = NULL;
*size = 0;
*offset = cpio->entry_offset;
return (ARCHIVE_EOF);
}
}
static int
header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@ -293,16 +337,16 @@ header_newc(struct archive *a, struct stat *st,
* size. struct stat.st_size may only be 32 bits, so
* assigning there first could lose information.
*/
a->entry_bytes_remaining =
cpio->entry_bytes_remaining =
atol16(header->c_filesize, sizeof(header->c_filesize));
st->st_size = a->entry_bytes_remaining;
st->st_size = cpio->entry_bytes_remaining;
/* Pad file contents to a multiple of 4. */
a->entry_padding = 3 & -a->entry_bytes_remaining;
cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
return (ARCHIVE_OK);
}
static int
header_odc(struct archive *a, struct stat *st,
header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@ -338,15 +382,15 @@ header_odc(struct archive *a, struct stat *st,
* size. struct stat.st_size may only be 32 bits, so
* assigning there first could lose information.
*/
a->entry_bytes_remaining =
cpio->entry_bytes_remaining =
atol8(header->c_filesize, sizeof(header->c_filesize));
st->st_size = a->entry_bytes_remaining;
a->entry_padding = 0;
st->st_size = cpio->entry_bytes_remaining;
cpio->entry_padding = 0;
return (ARCHIVE_OK);
}
static int
header_bin_le(struct archive *a, struct stat *st,
header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@ -376,14 +420,14 @@ header_bin_le(struct archive *a, struct stat *st,
*namelength = header->c_namesize[0] + header->c_namesize[1] * 256;
*name_pad = *namelength & 1; /* Pad to even. */
a->entry_bytes_remaining = le4(header->c_filesize);
st->st_size = a->entry_bytes_remaining;
a->entry_padding = a->entry_bytes_remaining & 1; /* Pad to even. */
cpio->entry_bytes_remaining = le4(header->c_filesize);
st->st_size = cpio->entry_bytes_remaining;
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
return (ARCHIVE_OK);
}
static int
header_bin_be(struct archive *a, struct stat *st,
header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@ -413,9 +457,9 @@ header_bin_be(struct archive *a, struct stat *st,
*namelength = header->c_namesize[0] * 256 + header->c_namesize[1];
*name_pad = *namelength & 1; /* Pad to even. */
a->entry_bytes_remaining = be4(header->c_filesize);
st->st_size = a->entry_bytes_remaining;
a->entry_padding = a->entry_bytes_remaining & 1; /* Pad to even. */
cpio->entry_bytes_remaining = be4(header->c_filesize);
st->st_size = cpio->entry_bytes_remaining;
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
return (ARCHIVE_OK);
}

View File

@ -76,6 +76,9 @@ struct tar {
wchar_t *pax_entry;
size_t pax_entry_length;
int header_recursion_depth;
off_t entry_bytes_remaining;
off_t entry_offset;
off_t entry_padding;
};
static size_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
@ -102,6 +105,8 @@ static int header_gnutar(struct archive *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int archive_read_format_tar_bid(struct archive *);
static int archive_read_format_tar_cleanup(struct archive *);
static int archive_read_format_tar_read_data(struct archive *a,
const void **buff, size_t *size, off_t *offset);
static int archive_read_format_tar_read_header(struct archive *,
struct archive_entry *);
static int checksum(struct archive *, const void *);
@ -110,8 +115,8 @@ static int pax_attribute(struct archive_entry *, struct stat *,
static int pax_header(struct archive *, struct tar *,
struct archive_entry *, struct stat *, char *attr);
static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
static int read_body_to_string(struct archive *, struct archive_string *,
const void *h);
static int read_body_to_string(struct archive *, struct tar *,
struct archive_string *, const void *h);
static int64_t tar_atol(const char *, unsigned);
static int64_t tar_atol10(const wchar_t *, unsigned);
static int64_t tar_atol256(const char *, unsigned);
@ -139,6 +144,7 @@ archive_read_support_format_tar(struct archive *a)
r = __archive_read_register_format(a, tar,
archive_read_format_tar_bid,
archive_read_format_tar_read_header,
archive_read_format_tar_read_data,
archive_read_format_tar_cleanup);
if (r != ARCHIVE_OK)
@ -261,10 +267,48 @@ archive_read_format_tar_read_header(struct archive *a,
memset(&st, 0, sizeof(st));
tar = *(a->pformat_data);
tar->entry_offset = 0;
return (tar_read_header(a, tar, entry, &st));
}
static int
archive_read_format_tar_read_data(struct archive *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
struct tar *tar;
tar = *(a->pformat_data);
if (tar->entry_bytes_remaining > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > tar->entry_bytes_remaining)
bytes_read = tar->entry_bytes_remaining;
*size = bytes_read;
*offset = tar->entry_offset;
tar->entry_offset += bytes_read;
tar->entry_bytes_remaining -= bytes_read;
(a->compression_read_consume)(a, bytes_read);
return (ARCHIVE_OK);
} else {
while (tar->entry_padding > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > tar->entry_padding)
bytes_read = tar->entry_padding;
(a->compression_read_consume)(a, bytes_read);
tar->entry_padding -= bytes_read;
}
*buff = NULL;
*size = 0;
*offset = tar->entry_offset;
return (ARCHIVE_EOF);
}
}
/*
* This function recursively interprets all of the headers associated
* with a single entry.
@ -436,7 +480,7 @@ header_Solaris_ACL(struct archive *a, struct tar *tar,
char *p;
wchar_t *wp;
err = read_body_to_string(a, &(tar->acl_text), h);
err = read_body_to_string(a, tar, &(tar->acl_text), h);
err2 = tar_read_header(a, tar, entry, st);
err = err_combine(err, err2);
@ -470,7 +514,7 @@ header_longlink(struct archive *a, struct tar *tar,
{
int err, err2;
err = read_body_to_string(a, &(tar->longlink), h);
err = read_body_to_string(a, tar, &(tar->longlink), h);
err2 = tar_read_header(a, tar, entry, st);
if (err == ARCHIVE_OK && err2 == ARCHIVE_OK) {
/* Set symlink if symlink already set, else hardlink. */
@ -488,7 +532,7 @@ header_longname(struct archive *a, struct tar *tar,
{
int err, err2;
err = read_body_to_string(a, &(tar->longname), h);
err = read_body_to_string(a, tar, &(tar->longname), h);
/* Read and parse "real" header, then override name. */
err2 = tar_read_header(a, tar, entry, st);
if (err == ARCHIVE_OK && err2 == ARCHIVE_OK)
@ -514,7 +558,8 @@ header_volume(struct archive *a, struct tar *tar,
* Read body of an archive entry into an archive_string object.
*/
static int
read_body_to_string(struct archive *a, struct archive_string *as, const void *h)
read_body_to_string(struct archive *a, struct tar *tar,
struct archive_string *as, const void *h)
{
const struct archive_entry_header_ustar *header;
off_t size;
@ -529,8 +574,8 @@ read_body_to_string(struct archive *a, struct archive_string *as, const void *h)
a->state = ARCHIVE_STATE_DATA;
/* Read the body into the string. */
a->entry_bytes_remaining = size;
a->entry_padding = 0x1ff & -size;
tar->entry_bytes_remaining = size;
tar->entry_padding = 0x1ff & -size;
archive_string_ensure(as, size+1);
err = archive_read_data_into_buffer(a, as->s, size);
as->s[size] = 0; /* Null terminate name! */
@ -707,8 +752,8 @@ header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
st->st_mode |= S_IFDIR;
}
a->entry_bytes_remaining = st->st_size;
a->entry_padding = 0x1ff & (-a->entry_bytes_remaining);
tar->entry_bytes_remaining = st->st_size;
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (0);
}
@ -721,7 +766,7 @@ header_pax_global(struct archive *a, struct tar *tar,
{
int err, err2;
err = read_body_to_string(a, &(tar->pax_global), h);
err = read_body_to_string(a, tar, &(tar->pax_global), h);
err2 = tar_read_header(a, tar, entry, st);
return (err_combine(err, err2));
}
@ -732,7 +777,7 @@ header_pax_extensions(struct archive *a, struct tar *tar,
{
int err, err2;
read_body_to_string(a, &(tar->pax_header), h);
read_body_to_string(a, tar, &(tar->pax_header), h);
/* Parse the next header. */
err = tar_read_header(a, tar, entry, st);
@ -749,8 +794,8 @@ header_pax_extensions(struct archive *a, struct tar *tar,
*/
err2 = pax_header(a, tar, entry, st, tar->pax_header.s);
err = err_combine(err, err2);
a->entry_bytes_remaining = st->st_size;
a->entry_padding = 0x1ff & (-a->entry_bytes_remaining);
tar->entry_bytes_remaining = st->st_size;
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (err);
}
@ -799,8 +844,8 @@ header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
tar_atol(header->devminor, sizeof(header->devminor)));
}
a->entry_bytes_remaining = st->st_size;
a->entry_padding = 0x1ff & (-a->entry_bytes_remaining);
tar->entry_bytes_remaining = st->st_size;
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (0);
}
@ -1144,8 +1189,8 @@ header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
/* XXX TODO: Recognize and skip extra GNU header blocks. */
a->entry_bytes_remaining = st->st_size;
a->entry_padding = 0x1ff & (-a->entry_bytes_remaining);
tar->entry_bytes_remaining = st->st_size;
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (0);
}