Write-blocking cleanup, largely thanks to Colin Percival (cperciva@).
* If write block size is zero, don't block at all. This supports the unusual requirement of applications that need "no-delay" writes. * Expose _write_finish_entry() to give such applications more control over write boundaries. (Normal applications do not need this, as entries are completed automatically.) * Correct the type of write callbacks; this is a minor API change that does not affect the ABI. * Correct the error handling in _write_next_header() around completing the previous entry. * Correct the documentation for block-size markers: Remove docs for the long-defunct _read_set_block_size(); document all of the write block size manipulators. MFC after: 14 days
This commit is contained in:
parent
cc005bb92c
commit
dc46be1cbf
@ -161,7 +161,6 @@ MLINKS+= archive_read.3 archive_read_open_fd.3
|
||||
MLINKS+= archive_read.3 archive_read_open_file.3
|
||||
MLINKS+= archive_read.3 archive_read_open_filename.3
|
||||
MLINKS+= archive_read.3 archive_read_open_memory.3
|
||||
MLINKS+= archive_read.3 archive_read_set_bytes_per_block.3
|
||||
MLINKS+= archive_read.3 archive_read_support_compression_all.3
|
||||
MLINKS+= archive_read.3 archive_read_support_compression_bzip2.3
|
||||
MLINKS+= archive_read.3 archive_read_support_compression_compress.3
|
||||
@ -181,6 +180,9 @@ MLINKS+= archive_util.3 archive_format_name.3
|
||||
MLINKS+= archive_util.3 archive_set_error.3
|
||||
MLINKS+= archive_write.3 archive_write_data.3
|
||||
MLINKS+= archive_write.3 archive_write_finish.3
|
||||
MLINKS+= archive_write.3 archive_write_finish_entry.3
|
||||
MLINKS+= archive_write.3 archive_write_get_bytes_in_last_block.3
|
||||
MLINKS+= archive_write.3 archive_write_get_bytes_per_block.3
|
||||
MLINKS+= archive_write.3 archive_write_header.3
|
||||
MLINKS+= archive_write.3 archive_write_new.3
|
||||
MLINKS+= archive_write.3 archive_write_open.3
|
||||
|
@ -116,7 +116,7 @@ typedef ssize_t archive_skip_callback(struct archive *, void *_client_data,
|
||||
size_t request);
|
||||
/* Returns size actually written, zero on EOF, -1 on error. */
|
||||
typedef ssize_t archive_write_callback(struct archive *, void *_client_data,
|
||||
void *_buffer, size_t _length);
|
||||
const void *_buffer, size_t _length);
|
||||
typedef int archive_open_callback(struct archive *, void *_client_data);
|
||||
typedef int archive_close_callback(struct archive *, void *_client_data);
|
||||
|
||||
@ -358,6 +358,7 @@ int archive_write_header(struct archive *,
|
||||
struct archive_entry *);
|
||||
/* TODO: should be ssize_t, but that might require .so version bump? */
|
||||
int archive_write_data(struct archive *, const void *, size_t);
|
||||
int archive_write_finish_entry(struct archive *);
|
||||
int archive_write_close(struct archive *);
|
||||
void archive_write_finish(struct archive *);
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm archive_read_new ,
|
||||
.Nm archive_read_set_bytes_per_block ,
|
||||
.Nm archive_read_support_compression_all ,
|
||||
.Nm archive_read_support_compression_bzip2 ,
|
||||
.Nm archive_read_support_compression_compress ,
|
||||
@ -62,8 +61,6 @@
|
||||
.Ft struct archive *
|
||||
.Fn archive_read_new "void"
|
||||
.Ft int
|
||||
.Fn archive_read_set_bytes_per_block "struct archive *" "int"
|
||||
.Ft int
|
||||
.Fn archive_read_support_compression_all "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_compression_bzip2 "struct archive *"
|
||||
@ -129,11 +126,6 @@ order they would be used:
|
||||
Allocates and initializes a
|
||||
.Tn struct archive
|
||||
object suitable for reading from an archive.
|
||||
.It Fn archive_read_set_bytes_per_block
|
||||
Sets the block size used for reading the archive data.
|
||||
This controls the size that will be used when invoking the read
|
||||
callback function.
|
||||
The default is 20 records or 10240 bytes for tar formats.
|
||||
.It Fn archive_read_support_compression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none
|
||||
Enables auto-detection code and decompression support for the
|
||||
specified compression.
|
||||
|
@ -35,6 +35,7 @@
|
||||
.Nm archive_write_set_format_shar ,
|
||||
.Nm archive_write_set_format_shar_binary ,
|
||||
.Nm archive_write_set_format_ustar ,
|
||||
.Nm archive_write_get_bytes_per_block ,
|
||||
.Nm archive_write_set_bytes_per_block ,
|
||||
.Nm archive_write_set_bytes_in_last_block ,
|
||||
.Nm archive_write_set_compressor_gzip ,
|
||||
@ -46,6 +47,7 @@
|
||||
.Nm archive_write_open_memory ,
|
||||
.Nm archive_write_header ,
|
||||
.Nm archive_write_data ,
|
||||
.Nm archive_write_finish_entry ,
|
||||
.Nm archive_write_close ,
|
||||
.Nm archive_write_finish
|
||||
.Nd functions for creating archives
|
||||
@ -54,6 +56,8 @@
|
||||
.Ft struct archive *
|
||||
.Fn archive_write_new "void"
|
||||
.Ft int
|
||||
.Fn archive_write_get_bytes_per_block "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_bytes_per_block "struct archive *" "int bytes_per_block"
|
||||
.Ft int
|
||||
.Fn archive_write_set_bytes_in_last_block "struct archive *" "int"
|
||||
@ -88,6 +92,8 @@
|
||||
.Ft int
|
||||
.Fn archive_write_data "struct archive *" "const void *" "size_t"
|
||||
.Ft int
|
||||
.Fn archive_write_finish_entry "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_close "struct archive *"
|
||||
.Ft void
|
||||
.Fn archive_write_finish "struct archive *"
|
||||
@ -114,6 +120,12 @@ written will be padded to the full block size.
|
||||
If it is zero, the last block will not be padded.
|
||||
If it is non-zero, padding will be added both before and after compression.
|
||||
The default is to use a block size of 10240 bytes and to pad the last block.
|
||||
Note that a block size of zero will suppress internal blocking
|
||||
and cause writes to be sent directly to the write callback as they occur.
|
||||
.It Fn archive_write_get_bytes_per_block
|
||||
Retrieve the block size to be used for writing.
|
||||
A value of -1 here indicates that the library should use default values.
|
||||
A value of zero indicates that internal blocking is suppressed.
|
||||
.It Fn archive_write_set_bytes_in_last_block
|
||||
Sets the block size used for writing the last block.
|
||||
If this value is zero, the last block will be padded to the same size
|
||||
@ -129,6 +141,9 @@ will set this based on the file type).
|
||||
Unlike the other
|
||||
.Dq set
|
||||
functions, this function can be called after the archive is opened.
|
||||
.It Fn archive_write_get_bytes_in_last_block
|
||||
Retrieve the currently-set value for last block size.
|
||||
A value of -1 here indicates that the library should use default values.
|
||||
.It Fn archive_write_set_format_cpio , Fn archive_write_set_format_pax , Fn archive_write_set_format_pax_restricted , Fn archive_write_set_format_shar , Fn archive_write_set_format_shar_binary , Fn archive_write_set_format_ustar
|
||||
Sets the format that will be used for the archive.
|
||||
The library can write
|
||||
@ -230,6 +245,15 @@ objects.
|
||||
.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_finish_entry
|
||||
Close out the entry just written.
|
||||
In particular, this writes out the final padding required by some formats.
|
||||
Ordinarily, clients never need to call this, as it
|
||||
is called automatically by
|
||||
.Fn archive_write_next_header
|
||||
and
|
||||
.Fn archive_write_close
|
||||
as needed.
|
||||
.It Fn archive_write_close
|
||||
Complete the archive and invoke the close callback.
|
||||
.It Fn archive_write_finish
|
||||
|
@ -232,22 +232,22 @@ archive_write_finish(struct archive *a)
|
||||
free(a);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write the appropriate header.
|
||||
*/
|
||||
int
|
||||
archive_write_header(struct archive *a, struct archive_entry *entry)
|
||||
{
|
||||
int ret;
|
||||
int ret, r2;
|
||||
|
||||
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_header");
|
||||
ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header");
|
||||
archive_string_empty(&a->error_string);
|
||||
|
||||
/* Finish last entry. */
|
||||
if (a->state & ARCHIVE_STATE_DATA)
|
||||
((a->format_finish_entry)(a));
|
||||
/* In particular, "retry" and "fatal" get returned immediately. */
|
||||
ret = archive_write_finish_entry(a);
|
||||
if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
|
||||
return (ret);
|
||||
|
||||
if (a->skip_file_dev != 0 &&
|
||||
archive_entry_dev(entry) == a->skip_file_dev &&
|
||||
@ -258,12 +258,28 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
|
||||
}
|
||||
|
||||
/* Format and write header. */
|
||||
ret = ((a->format_write_header)(a, entry));
|
||||
r2 = ((a->format_write_header)(a, entry));
|
||||
if (r2 < ret)
|
||||
ret = r2;
|
||||
|
||||
a->state = ARCHIVE_STATE_DATA;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
archive_write_finish_entry(struct archive * a)
|
||||
{
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
||||
"archive_write_finish_entry");
|
||||
if (a->state & ARCHIVE_STATE_DATA)
|
||||
ret = (a->format_finish_entry)(a);
|
||||
a->state = ARCHIVE_STATE_HEADER;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that the compressor is responsible for blocking.
|
||||
*/
|
||||
@ -271,7 +287,8 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
|
||||
int
|
||||
archive_write_data(struct archive *a, const void *buff, size_t s)
|
||||
{
|
||||
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA, "archive_write_data");
|
||||
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_DATA, "archive_write_data");
|
||||
archive_string_empty(&a->error_string);
|
||||
return ((a->format_write_data)(a, buff, s));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ struct write_fd_data {
|
||||
|
||||
static int file_close(struct archive *, void *);
|
||||
static int file_open(struct archive *, void *);
|
||||
static ssize_t file_write(struct archive *, void *, void *buff, size_t);
|
||||
static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
|
||||
|
||||
int
|
||||
archive_write_open_fd(struct archive *a, int fd)
|
||||
@ -108,7 +108,7 @@ file_open(struct archive *a, void *client_data)
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
file_write(struct archive *a, void *client_data, void *buff, size_t length)
|
||||
file_write(struct archive *a, void *client_data, const void *buff, size_t length)
|
||||
{
|
||||
struct write_fd_data *mine;
|
||||
ssize_t bytesWritten;
|
||||
|
@ -54,7 +54,7 @@ struct write_FILE_data {
|
||||
|
||||
static int file_close(struct archive *, void *);
|
||||
static int file_open(struct archive *, void *);
|
||||
static ssize_t file_write(struct archive *, void *, void *buff, size_t);
|
||||
static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
|
||||
|
||||
int
|
||||
archive_write_open_FILE(struct archive *a, FILE *f)
|
||||
@ -81,7 +81,7 @@ file_open(struct archive *a, void *client_data)
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
file_write(struct archive *a, void *client_data, void *buff, size_t length)
|
||||
file_write(struct archive *a, void *client_data, const void *buff, size_t length)
|
||||
{
|
||||
struct write_FILE_data *mine;
|
||||
size_t bytesWritten;
|
||||
|
@ -55,7 +55,7 @@ struct write_file_data {
|
||||
|
||||
static int file_close(struct archive *, void *);
|
||||
static int file_open(struct archive *, void *);
|
||||
static ssize_t file_write(struct archive *, void *, void *buff, size_t);
|
||||
static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
|
||||
|
||||
int
|
||||
archive_write_open_file(struct archive *a, const char *filename)
|
||||
@ -143,7 +143,7 @@ file_open(struct archive *a, void *client_data)
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
file_write(struct archive *a, void *client_data, void *buff, size_t length)
|
||||
file_write(struct archive *a, void *client_data, const void *buff, size_t length)
|
||||
{
|
||||
struct write_file_data *mine;
|
||||
ssize_t bytesWritten;
|
||||
|
@ -54,7 +54,7 @@ struct write_memory_data {
|
||||
|
||||
static int memory_write_close(struct archive *, void *);
|
||||
static int memory_write_open(struct archive *, void *);
|
||||
static ssize_t memory_write(struct archive *, void *, void *buff, size_t);
|
||||
static ssize_t memory_write(struct archive *, void *, const void *buff, size_t);
|
||||
|
||||
/*
|
||||
* Client provides a pointer to a block of memory to receive
|
||||
@ -100,7 +100,7 @@ memory_write_open(struct archive *a, void *client_data)
|
||||
* how much has been written into their buffer at any time.
|
||||
*/
|
||||
static ssize_t
|
||||
memory_write(struct archive *a, void *client_data, void *buff, size_t length)
|
||||
memory_write(struct archive *a, void *client_data, const void *buff, size_t length)
|
||||
{
|
||||
struct write_memory_data *mine;
|
||||
mine = client_data;
|
||||
|
@ -89,13 +89,14 @@ archive_compressor_none_init(struct archive *a)
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
state->buffer_size = a->bytes_per_block;
|
||||
state->buffer = (char *)malloc(state->buffer_size);
|
||||
|
||||
if (state->buffer == NULL) {
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate output buffer");
|
||||
free(state);
|
||||
return (ARCHIVE_FATAL);
|
||||
if (state->buffer_size != 0) {
|
||||
state->buffer = (char *)malloc(state->buffer_size);
|
||||
if (state->buffer == NULL) {
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate output buffer");
|
||||
free(state);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
state->next = state->buffer;
|
||||
@ -129,7 +130,27 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
|
||||
}
|
||||
|
||||
remaining = length;
|
||||
while (remaining > 0) {
|
||||
|
||||
/*
|
||||
* If there is no buffer for blocking, just pass the data
|
||||
* straight through to the client write callback. In
|
||||
* particular, this supports "no write delay" operation for
|
||||
* special applications. Just set the block size to zero.
|
||||
*/
|
||||
if (state->buffer_size == 0) {
|
||||
while (remaining > 0) {
|
||||
bytes_written = (a->client_writer)(a, a->client_data,
|
||||
buff, remaining);
|
||||
if (bytes_written <= 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
remaining -= bytes_written;
|
||||
buff += bytes_written;
|
||||
}
|
||||
a->file_position += length;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
while ((remaining > 0) || (state->avail == 0)) {
|
||||
/*
|
||||
* If we have a full output block, write it and reset the
|
||||
* output buffer.
|
||||
|
Loading…
x
Reference in New Issue
Block a user