Clean up the error handling in the
write path. In particular, this should solve some problems people have seen with bsdtar not exiting on various write errors.
This commit is contained in:
parent
9fb9f10286
commit
3ede53f3e1
@ -190,6 +190,7 @@ Build and write a header using the data in the provided
|
||||
structure.
|
||||
.It Fn archive_write_data
|
||||
Write data corresponding to the header just written.
|
||||
Returns number of bytes written or -1 on error.
|
||||
.It Fn archive_write_close
|
||||
Complete the archive and invoke the close callback.
|
||||
.It Fn archive_write_finish
|
||||
@ -321,20 +322,19 @@ and
|
||||
.Fn archive_error_string
|
||||
functions will return appropriate values.
|
||||
Note that if the client-provided write callback function
|
||||
returns -1, that error will be propagated back to the caller
|
||||
returns a non-zero value, that error will be propagated back to the caller
|
||||
through whatever API function resulted in that call, which
|
||||
may include
|
||||
.Fn archive_write_header ,
|
||||
.Fn archive_write_data ,
|
||||
or
|
||||
.Fn archive_write_close .
|
||||
In such a case, the
|
||||
The client callback can call
|
||||
.Fn archive_set_error
|
||||
to provide values that can then be retrieved by
|
||||
.Fn archive_errno
|
||||
or
|
||||
.Fn archive_error_string
|
||||
fields will not return useful information; you should use
|
||||
client-private data to return error information
|
||||
back to your mainline code.
|
||||
and
|
||||
.Fn archive_error_string .
|
||||
.Sh SEE ALSO
|
||||
.Xr tar 1 ,
|
||||
.Xr libarchive 3 ,
|
||||
|
@ -215,9 +215,12 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
|
||||
/*
|
||||
* Note that the compressor is responsible for blocking.
|
||||
*/
|
||||
/* Should be "ssize_t", but that breaks the ABI. <sigh> */
|
||||
int
|
||||
archive_write_data(struct archive *a, const void *buff, size_t s)
|
||||
{
|
||||
int ret;
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA);
|
||||
return (a->format_write_data(a, buff, s));
|
||||
ret = (a->format_write_data)(a, buff, s);
|
||||
return (ret == ARCHIVE_OK ? (ssize_t)s : -1);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <bzlib.h>
|
||||
@ -153,15 +154,17 @@ archive_compressor_bzip2_init(struct archive *a)
|
||||
|
||||
/*
|
||||
* Write data to the compressed stream.
|
||||
*
|
||||
* Returns ARCHIVE_OK if all data written, error otherwise.
|
||||
*/
|
||||
static ssize_t
|
||||
static int
|
||||
archive_compressor_bzip2_write(struct archive *a, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *state;
|
||||
|
||||
state = a->compression_data;
|
||||
if (!a->client_writer) {
|
||||
if (a->client_writer == NULL) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"No write callback is registered? "
|
||||
"This is probably an internal programming error.");
|
||||
@ -175,9 +178,9 @@ archive_compressor_bzip2_write(struct archive *a, const void *buff,
|
||||
SET_NEXT_IN(state, buff);
|
||||
state->stream.avail_in = length;
|
||||
if (drive_compressor(a, state, 0))
|
||||
return (-1);
|
||||
return (ARCHIVE_FATAL);
|
||||
a->file_position += length;
|
||||
return (length);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
||||
@ -191,6 +194,7 @@ archive_compressor_bzip2_finish(struct archive *a)
|
||||
int ret;
|
||||
struct private_data *state;
|
||||
ssize_t target_block_length;
|
||||
ssize_t bytes_written;
|
||||
unsigned tocopy;
|
||||
|
||||
state = a->compression_data;
|
||||
@ -246,12 +250,16 @@ archive_compressor_bzip2_finish(struct archive *a)
|
||||
}
|
||||
|
||||
/* Write the last block */
|
||||
ret = (a->client_writer)(a, a->client_data, state->compressed,
|
||||
block_length);
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->compressed, block_length);
|
||||
|
||||
a->raw_position += ret;
|
||||
if (ret != 0)
|
||||
goto cleanup;
|
||||
/* TODO: Handle short write of final block. */
|
||||
if (bytes_written <= 0)
|
||||
ret = ARCHIVE_FATAL;
|
||||
else {
|
||||
a->raw_position += ret;
|
||||
ret = ARCHIVE_OK;
|
||||
}
|
||||
|
||||
/* Cleanup: shut down compressor, release memory, etc. */
|
||||
cleanup:
|
||||
@ -284,27 +292,28 @@ cleanup:
|
||||
static int
|
||||
drive_compressor(struct archive *a, struct private_data *state, int finishing)
|
||||
{
|
||||
size_t ret;
|
||||
ssize_t bytes_written;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
if (state->stream.avail_out == 0) {
|
||||
ret = (a->client_writer)(a, a->client_data,
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->compressed, state->compressed_buffer_size);
|
||||
if (ret <= 0) {
|
||||
if (bytes_written <= 0) {
|
||||
/* TODO: Handle this write failure */
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if (ret < state->compressed_buffer_size) {
|
||||
} else if ((size_t)bytes_written < state->compressed_buffer_size) {
|
||||
/* Short write: Move remainder to
|
||||
* front and keep filling */
|
||||
memmove(state->compressed,
|
||||
state->compressed + ret,
|
||||
state->compressed_buffer_size - ret);
|
||||
state->compressed + bytes_written,
|
||||
state->compressed_buffer_size - bytes_written);
|
||||
}
|
||||
|
||||
a->raw_position += ret;
|
||||
a->raw_position += bytes_written;
|
||||
state->stream.next_out = state->compressed +
|
||||
state->compressed_buffer_size - ret;
|
||||
state->stream.avail_out = ret;
|
||||
state->compressed_buffer_size - bytes_written;
|
||||
state->stream.avail_out = bytes_written;
|
||||
}
|
||||
|
||||
ret = BZ2_bzCompress(&(state->stream),
|
||||
|
@ -179,7 +179,7 @@ archive_compressor_gzip_init(struct archive *a)
|
||||
/*
|
||||
* Write data to the compressed stream.
|
||||
*/
|
||||
static ssize_t
|
||||
static int
|
||||
archive_compressor_gzip_write(struct archive *a, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
@ -187,7 +187,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
|
||||
int ret;
|
||||
|
||||
state = a->compression_data;
|
||||
if (!a->client_writer) {
|
||||
if (a->client_writer == NULL) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"No write callback is registered? "
|
||||
"This is probably an internal programming error.");
|
||||
@ -205,7 +205,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
|
||||
return (ret);
|
||||
|
||||
a->file_position += length;
|
||||
return (length);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
||||
@ -215,7 +215,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
|
||||
static int
|
||||
archive_compressor_gzip_finish(struct archive *a)
|
||||
{
|
||||
ssize_t block_length, target_block_length;
|
||||
ssize_t block_length, target_block_length, bytes_written;
|
||||
int ret;
|
||||
struct private_data *state;
|
||||
unsigned tocopy;
|
||||
@ -273,9 +273,13 @@ archive_compressor_gzip_finish(struct archive *a)
|
||||
|
||||
/* If it overflowed, flush and start a new block. */
|
||||
if (tocopy < 8) {
|
||||
ret = (a->client_writer)(a, a->client_data, state->compressed,
|
||||
state->compressed_buffer_size);
|
||||
a->raw_position += ret;
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->compressed, state->compressed_buffer_size);
|
||||
if (bytes_written <= 0) {
|
||||
ret = ARCHIVE_FATAL;
|
||||
goto cleanup;
|
||||
}
|
||||
a->raw_position += bytes_written;
|
||||
state->stream.next_out = state->compressed;
|
||||
state->stream.avail_out = state->compressed_buffer_size;
|
||||
memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
|
||||
@ -306,9 +310,13 @@ archive_compressor_gzip_finish(struct archive *a)
|
||||
}
|
||||
|
||||
/* Write the last block */
|
||||
ret = (a->client_writer)(a, a->client_data, state->compressed,
|
||||
block_length);
|
||||
a->raw_position += ret;
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->compressed, block_length);
|
||||
if (bytes_written <= 0) {
|
||||
ret = ARCHIVE_FATAL;
|
||||
goto cleanup;
|
||||
}
|
||||
a->raw_position += bytes_written;
|
||||
|
||||
/* Cleanup: shut down compressor, release memory, etc. */
|
||||
cleanup:
|
||||
@ -340,27 +348,28 @@ cleanup:
|
||||
static int
|
||||
drive_compressor(struct archive *a, struct private_data *state, int finishing)
|
||||
{
|
||||
size_t ret;
|
||||
ssize_t bytes_written;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
if (state->stream.avail_out == 0) {
|
||||
ret = (a->client_writer)(a, a->client_data,
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->compressed, state->compressed_buffer_size);
|
||||
if (ret <= 0) {
|
||||
if (bytes_written <= 0) {
|
||||
/* TODO: Handle this write failure */
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if (ret < state->compressed_buffer_size) {
|
||||
} else if ((size_t)bytes_written < state->compressed_buffer_size) {
|
||||
/* Short write: Move remaining to
|
||||
* front of block and keep filling */
|
||||
memmove(state->compressed,
|
||||
state->compressed + ret,
|
||||
state->compressed_buffer_size - ret);
|
||||
state->compressed + bytes_written,
|
||||
state->compressed_buffer_size - bytes_written);
|
||||
}
|
||||
a->raw_position += ret;
|
||||
a->raw_position += bytes_written;
|
||||
state->stream.next_out
|
||||
= state->compressed +
|
||||
state->compressed_buffer_size - ret;
|
||||
state->stream.avail_out = ret;
|
||||
state->compressed_buffer_size - bytes_written;
|
||||
state->stream.avail_out = bytes_written;
|
||||
}
|
||||
|
||||
ret = deflate(&(state->stream),
|
||||
|
@ -104,13 +104,13 @@ archive_compressor_none_init(struct archive *a)
|
||||
/*
|
||||
* Write data to the stream.
|
||||
*/
|
||||
static ssize_t
|
||||
static int
|
||||
archive_compressor_none_write(struct archive *a, const void *vbuff,
|
||||
size_t length)
|
||||
{
|
||||
const char *buff;
|
||||
ssize_t remaining, to_copy;
|
||||
int ret;
|
||||
ssize_t bytes_written;
|
||||
struct archive_none *state;
|
||||
|
||||
state = a->compression_data;
|
||||
@ -129,10 +129,12 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
|
||||
* output buffer.
|
||||
*/
|
||||
if (state->avail == 0) {
|
||||
ret = (a->client_writer)(a, a->client_data,
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->buffer, state->buffer_size);
|
||||
/* XXX TODO: if ret < state->buffer_size XXX */
|
||||
a->raw_position += ret;
|
||||
if (bytes_written <= 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
/* XXX TODO: if bytes_written < state->buffer_size */
|
||||
a->raw_position += bytes_written;
|
||||
state->next = state->buffer;
|
||||
state->avail = state->buffer_size;
|
||||
}
|
||||
@ -147,7 +149,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
|
||||
remaining -= to_copy;
|
||||
}
|
||||
a->file_position += length;
|
||||
return (length);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
||||
@ -159,6 +161,7 @@ archive_compressor_none_finish(struct archive *a)
|
||||
{
|
||||
ssize_t block_length;
|
||||
ssize_t target_block_length;
|
||||
ssize_t bytes_written;
|
||||
int ret;
|
||||
int ret2;
|
||||
struct archive_none *state;
|
||||
@ -193,9 +196,14 @@ archive_compressor_none_finish(struct archive *a)
|
||||
target_block_length - block_length);
|
||||
block_length = target_block_length;
|
||||
}
|
||||
ret = (a->client_writer)(a, a->client_data, state->buffer,
|
||||
block_length);
|
||||
a->raw_position += ret;
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
state->buffer, block_length);
|
||||
if (bytes_written <= 0)
|
||||
ret = ARCHIVE_FATAL;
|
||||
else {
|
||||
a->raw_position += bytes_written;
|
||||
ret = ARCHIVE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the output */
|
||||
|
@ -99,7 +99,7 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
const char *p, *path;
|
||||
int pathlength, ret, written;
|
||||
int pathlength, ret;
|
||||
const struct stat *st;
|
||||
struct cpio_header h;
|
||||
|
||||
@ -142,19 +142,19 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
|
||||
else
|
||||
format_octal(st->st_size, &h.c_filesize, sizeof(h.c_filesize));
|
||||
|
||||
written = (a->compression_write)(a, &h, sizeof(h));
|
||||
if (written < (int)sizeof(h))
|
||||
ret = (a->compression_write)(a, &h, sizeof(h));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
written = (a->compression_write)(a, path, pathlength);
|
||||
if (written < (int)pathlength)
|
||||
ret = (a->compression_write)(a, path, pathlength);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
cpio->entry_bytes_remaining = st->st_size;
|
||||
|
||||
/* Write the symlink now. */
|
||||
if (p != NULL && *p != '\0')
|
||||
(a->compression_write)(a, p, strlen(p));
|
||||
ret = (a->compression_write)(a, p, strlen(p));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -233,13 +233,13 @@ archive_write_cpio_finish_entry(struct archive *a)
|
||||
int to_write, ret;
|
||||
|
||||
cpio = a->format_data;
|
||||
ret = 0;
|
||||
ret = ARCHIVE_OK;
|
||||
while (cpio->entry_bytes_remaining > 0) {
|
||||
to_write = cpio->entry_bytes_remaining < a->null_length ?
|
||||
cpio->entry_bytes_remaining : a->null_length;
|
||||
ret = (a->compression_write)(a, a->nulls, to_write);
|
||||
if (ret < to_write)
|
||||
return (-1);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
cpio->entry_bytes_remaining -= to_write;
|
||||
}
|
||||
return (ret);
|
||||
|
@ -622,7 +622,7 @@ archive_write_pax_header(struct archive *a,
|
||||
__archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0);
|
||||
|
||||
/* If we built any extended attributes, write that entry first. */
|
||||
ret = 0;
|
||||
ret = ARCHIVE_OK;
|
||||
if (archive_strlen(&(pax->pax_header)) > 0) {
|
||||
struct stat st;
|
||||
struct archive_entry *pax_attr_entry;
|
||||
@ -663,7 +663,7 @@ archive_write_pax_header(struct archive *a,
|
||||
exit(1);
|
||||
}
|
||||
r = (a->compression_write)(a, paxbuff, 512);
|
||||
if (r < 512) {
|
||||
if (r != ARCHIVE_OK) {
|
||||
pax->entry_bytes_remaining = 0;
|
||||
pax->entry_padding = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
@ -677,7 +677,7 @@ archive_write_pax_header(struct archive *a,
|
||||
r = archive_write_data(a, pax->pax_header.s,
|
||||
archive_strlen(&(pax->pax_header)));
|
||||
a->state = oldstate;
|
||||
if (r < (int)archive_strlen(&(pax->pax_header))) {
|
||||
if (r != ARCHIVE_OK) {
|
||||
/* If a write fails, we're pretty much toast. */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@ -687,8 +687,8 @@ archive_write_pax_header(struct archive *a,
|
||||
|
||||
/* Write the header for main entry. */
|
||||
r = (a->compression_write)(a, ustarbuff, 512);
|
||||
if (ret != ARCHIVE_OK)
|
||||
ret = (r < 512) ? ARCHIVE_FATAL : ARCHIVE_OK;
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
|
||||
/*
|
||||
* Inform the client of the on-disk size we're using, so
|
||||
@ -839,9 +839,9 @@ write_nulls(struct archive *a, size_t padding)
|
||||
while (padding > 0) {
|
||||
to_write = padding < a->null_length ? padding : a->null_length;
|
||||
ret = (a->compression_write)(a, a->nulls, to_write);
|
||||
if (ret <= 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
padding -= ret;
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
padding -= to_write;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ struct shar {
|
||||
int uuavail;
|
||||
char uubuffer[3];
|
||||
int wrote_header;
|
||||
char *work;
|
||||
size_t work_len;
|
||||
struct archive_string work;
|
||||
};
|
||||
|
||||
static int archive_write_shar_finish(struct archive *);
|
||||
@ -70,23 +69,13 @@ shar_printf(struct archive *a, const char *fmt, ...)
|
||||
{
|
||||
struct shar *shar;
|
||||
va_list ap;
|
||||
int required;
|
||||
int ret;
|
||||
|
||||
shar = a->format_data;
|
||||
if (shar->work_len <= 0) {
|
||||
shar->work_len = 1024;
|
||||
shar->work = malloc(shar->work_len);
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
required = vsnprintf(shar->work, shar->work_len, fmt, ap);
|
||||
if ((size_t)required >= shar->work_len) {
|
||||
shar->work_len = required + 256;
|
||||
realloc(shar->work, shar->work_len);
|
||||
required = vsnprintf(shar->work, shar->work_len, fmt, ap);
|
||||
}
|
||||
ret = ((a->compression_write)(a, shar->work, strlen(shar->work)));
|
||||
archive_string_empty(&(shar->work));
|
||||
archive_string_vsprintf(&(shar->work), fmt, ap);
|
||||
ret = ((a->compression_write)(a, shar->work.s, strlen(shar->work.s)));
|
||||
va_end(ap);
|
||||
return (ret);
|
||||
}
|
||||
@ -149,11 +138,16 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
char *p, *pp;
|
||||
struct shar *shar;
|
||||
const struct stat *st;
|
||||
int ret;
|
||||
|
||||
shar = a->format_data;
|
||||
if (!shar->wrote_header) {
|
||||
shar_printf(a, "#!/bin/sh\n");
|
||||
shar_printf(a, "# This is a shell archive\n");
|
||||
ret = shar_printf(a, "#!/bin/sh\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = shar_printf(a, "# This is a shell archive\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
shar->wrote_header = 1;
|
||||
}
|
||||
|
||||
@ -192,7 +186,9 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
}
|
||||
|
||||
/* Stock preparation for all file types. */
|
||||
shar_printf(a, "echo x %s\n", name);
|
||||
ret = shar_printf(a, "echo x %s\n", name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
|
||||
if (!S_ISDIR(st->st_mode)) {
|
||||
/* Try to create the dir. */
|
||||
@ -206,8 +202,10 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
if (strcmp(p, ".") == 0) {
|
||||
/* Don't try to "mkdir ." */
|
||||
} else if (shar->last_dir == NULL) {
|
||||
shar_printf(a,
|
||||
ret = shar_printf(a,
|
||||
"mkdir -p %s > /dev/null 2>&1\n", p);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
shar->last_dir = p;
|
||||
} else if (strcmp(p, shar->last_dir) == 0) {
|
||||
/* We've already created this exact dir. */
|
||||
@ -217,8 +215,10 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
/* We've already created a subdir. */
|
||||
free(p);
|
||||
} else {
|
||||
shar_printf(a,
|
||||
ret = shar_printf(a,
|
||||
"mkdir -p %s > /dev/null 2>&1\n", p);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
free(shar->last_dir);
|
||||
shar->last_dir = p;
|
||||
}
|
||||
@ -227,27 +227,41 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
|
||||
/* Handle file-type specific issues. */
|
||||
shar->has_data = 0;
|
||||
if ((linkname = archive_entry_hardlink(entry)) != NULL)
|
||||
shar_printf(a, "ln -f %s %s\n", linkname, name);
|
||||
else if ((linkname = archive_entry_symlink(entry)) != NULL)
|
||||
shar_printf(a, "ln -fs %s %s\n", linkname, name);
|
||||
else {
|
||||
if ((linkname = archive_entry_hardlink(entry)) != NULL) {
|
||||
ret = shar_printf(a, "ln -f %s %s\n", linkname, name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
} else if ((linkname = archive_entry_symlink(entry)) != NULL) {
|
||||
ret = shar_printf(a, "ln -fs %s %s\n", linkname, name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
} else {
|
||||
switch(st->st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
if (archive_entry_size(entry) == 0)
|
||||
shar_printf(a, "touch %s\n", name);
|
||||
else {
|
||||
if (archive_entry_size(entry) == 0) {
|
||||
/* More portable than "touch." */
|
||||
ret = shar_printf(a, "test -e \"%s\" || :> \"%s\"\n", name, name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
} else {
|
||||
if (shar->dump) {
|
||||
shar_printf(a,
|
||||
ret = shar_printf(a,
|
||||
"uudecode -o %s << 'SHAR_END'\n",
|
||||
name);
|
||||
shar_printf(a, "begin %o %s\n",
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = shar_printf(a, "begin %o %s\n",
|
||||
archive_entry_mode(entry) & 0777,
|
||||
name);
|
||||
} else
|
||||
shar_printf(a,
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
} else {
|
||||
ret = shar_printf(a,
|
||||
"sed 's/^X//' > %s << 'SHAR_END'\n",
|
||||
name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
shar->has_data = 1;
|
||||
shar->end_of_line = 1;
|
||||
shar->outpos = 0;
|
||||
@ -255,7 +269,10 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
}
|
||||
break;
|
||||
case S_IFDIR:
|
||||
shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n", name);
|
||||
ret = shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n",
|
||||
name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
/* Record that we just created this directory. */
|
||||
if (shar->last_dir != NULL)
|
||||
free(shar->last_dir);
|
||||
@ -271,17 +288,23 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
*/
|
||||
break;
|
||||
case S_IFIFO:
|
||||
shar_printf(a, "mkfifo %s\n", name);
|
||||
ret = shar_printf(a, "mkfifo %s\n", name);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
break;
|
||||
case S_IFCHR:
|
||||
shar_printf(a, "mknod %s c %d %d\n", name,
|
||||
ret = shar_printf(a, "mknod %s c %d %d\n", name,
|
||||
archive_entry_rdevmajor(entry),
|
||||
archive_entry_rdevminor(entry));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
break;
|
||||
case S_IFBLK:
|
||||
shar_printf(a, "mknod %s b %d %d\n", name,
|
||||
ret = shar_printf(a, "mknod %s b %d %d\n", name,
|
||||
archive_entry_rdevmajor(entry),
|
||||
archive_entry_rdevminor(entry));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
break;
|
||||
default:
|
||||
return (ARCHIVE_WARN);
|
||||
@ -293,18 +316,18 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
|
||||
|
||||
/* XXX TODO: This could be more efficient XXX */
|
||||
static int
|
||||
archive_write_shar_data_sed(struct archive *a, const void *buff, size_t length)
|
||||
archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
|
||||
{
|
||||
struct shar *shar;
|
||||
const char *src;
|
||||
size_t n;
|
||||
int ret;
|
||||
|
||||
shar = a->format_data;
|
||||
if (!shar->has_data)
|
||||
return (0);
|
||||
|
||||
src = buff;
|
||||
n = length;
|
||||
ret = ARCHIVE_OK;
|
||||
shar->outpos = 0;
|
||||
while (n-- > 0) {
|
||||
if (shar->end_of_line) {
|
||||
@ -316,14 +339,17 @@ archive_write_shar_data_sed(struct archive *a, const void *buff, size_t length)
|
||||
shar->outbuff[shar->outpos++] = *src++;
|
||||
|
||||
if (shar->outpos > sizeof(shar->outbuff) - 2) {
|
||||
(a->compression_write)(a, shar->outbuff, shar->outpos);
|
||||
ret = (a->compression_write)(a, shar->outbuff,
|
||||
shar->outpos);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
shar->outpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (shar->outpos > 0)
|
||||
(a->compression_write)(a, shar->outbuff, shar->outpos);
|
||||
return (length);
|
||||
ret = (a->compression_write)(a, shar->outbuff, shar->outpos);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`')
|
||||
@ -357,6 +383,7 @@ archive_write_shar_data_uuencode(struct archive *a, const void *buff,
|
||||
struct shar *shar;
|
||||
const char *src;
|
||||
size_t n;
|
||||
int ret;
|
||||
|
||||
shar = a->format_data;
|
||||
if (!shar->has_data)
|
||||
@ -367,8 +394,10 @@ archive_write_shar_data_uuencode(struct archive *a, const void *buff,
|
||||
if (shar->uuavail == 3)
|
||||
uuencode_group(shar);
|
||||
if (shar->outpos >= 60) {
|
||||
shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
|
||||
ret = shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
|
||||
shar->outbuff);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
shar->outpos = 0;
|
||||
shar->outbytes = 0;
|
||||
}
|
||||
@ -376,7 +405,7 @@ archive_write_shar_data_uuencode(struct archive *a, const void *buff,
|
||||
shar->uubuffer[shar->uuavail++] = *src++;
|
||||
shar->outbytes++;
|
||||
}
|
||||
return (length);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -384,6 +413,7 @@ archive_write_shar_finish_entry(struct archive *a)
|
||||
{
|
||||
const char *g, *p, *u;
|
||||
struct shar *shar;
|
||||
int ret;
|
||||
|
||||
shar = a->format_data;
|
||||
if (shar->entry == NULL)
|
||||
@ -395,37 +425,51 @@ archive_write_shar_finish_entry(struct archive *a)
|
||||
if (shar->uuavail > 0)
|
||||
uuencode_group(shar);
|
||||
if (shar->outpos > 0) {
|
||||
shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
|
||||
shar->outbuff);
|
||||
ret = shar_printf(a, "%c%s\n",
|
||||
UUENC(shar->outbytes), shar->outbuff);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
shar->outpos = 0;
|
||||
shar->uuavail = 0;
|
||||
shar->outbytes = 0;
|
||||
}
|
||||
shar_printf(a, "%c\n", UUENC(0));
|
||||
shar_printf(a, "end\n", UUENC(0));
|
||||
shar_printf(a, "SHAR_END\n");
|
||||
ret = shar_printf(a, "%c\n", UUENC(0));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = shar_printf(a, "end\n", UUENC(0));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = shar_printf(a, "SHAR_END\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
/* Restore file mode, owner, flags. */
|
||||
/*
|
||||
* TODO: Don't immediately restore mode for
|
||||
* directories; defer that to end of script.
|
||||
*/
|
||||
shar_printf(a, "chmod %o %s\n",
|
||||
ret = shar_printf(a, "chmod %o %s\n",
|
||||
archive_entry_mode(shar->entry) & 07777,
|
||||
archive_entry_pathname(shar->entry));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
|
||||
u = archive_entry_uname(shar->entry);
|
||||
g = archive_entry_gname(shar->entry);
|
||||
if (u != NULL || g != NULL) {
|
||||
shar_printf(a, "chown %s%s%s %s\n",
|
||||
ret = shar_printf(a, "chown %s%s%s %s\n",
|
||||
(u != NULL) ? u : "",
|
||||
(g != NULL) ? ":" : "", (g != NULL) ? g : "",
|
||||
archive_entry_pathname(shar->entry));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
|
||||
shar_printf(a, "chflags %s %s\n", p,
|
||||
ret = shar_printf(a, "chflags %s %s\n", p,
|
||||
archive_entry_pathname(shar->entry));
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* TODO: restore ACLs */
|
||||
@ -433,9 +477,14 @@ archive_write_shar_finish_entry(struct archive *a)
|
||||
} else {
|
||||
if (shar->has_data) {
|
||||
/* Finish sed-encoded data: ensure last line ends. */
|
||||
if (!shar->end_of_line)
|
||||
shar_printf(a, "\n");
|
||||
shar_printf(a, "SHAR_END\n");
|
||||
if (!shar->end_of_line) {
|
||||
ret = shar_printf(a, "\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
ret = shar_printf(a, "SHAR_END\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,6 +497,7 @@ static int
|
||||
archive_write_shar_finish(struct archive *a)
|
||||
{
|
||||
struct shar *shar;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* TODO: Accumulate list of directory names/modes and
|
||||
@ -463,7 +513,9 @@ archive_write_shar_finish(struct archive *a)
|
||||
* shar_finish to free the format-specific data).
|
||||
*/
|
||||
if (shar->wrote_header) {
|
||||
shar_printf(a, "exit\n");
|
||||
ret = shar_printf(a, "exit\n");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
/* Shar output is never padded. */
|
||||
archive_write_set_bytes_in_last_block(a, 1);
|
||||
/*
|
||||
@ -475,8 +527,7 @@ archive_write_shar_finish(struct archive *a)
|
||||
archive_entry_free(shar->entry);
|
||||
if (shar->last_dir != NULL)
|
||||
free(shar->last_dir);
|
||||
if (shar->work != NULL)
|
||||
free(shar->work);
|
||||
archive_string_free(&(shar->work));
|
||||
free(shar);
|
||||
a->format_data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
|
@ -157,8 +157,8 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = (a->compression_write)(a, buff, 512);
|
||||
if (ret < 512)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
|
||||
ustar->entry_bytes_remaining = archive_entry_size(entry);
|
||||
ustar->entry_padding = 0x1ff & (- ustar->entry_bytes_remaining);
|
||||
@ -469,8 +469,8 @@ write_nulls(struct archive *a, size_t padding)
|
||||
while (padding > 0) {
|
||||
to_write = padding < a->null_length ? padding : a->null_length;
|
||||
ret = (a->compression_write)(a, a->nulls, to_write);
|
||||
if (ret < to_write)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
padding -= to_write;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
|
Loading…
x
Reference in New Issue
Block a user