diff options
author | kientzle <kientzle@FreeBSD.org> | 2006-11-26 19:00:50 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2006-11-26 19:00:50 +0000 |
commit | 0f8fa3629e664a8cdfd6022cc1840102e3ff8c2c (patch) | |
tree | ebb3f03dd6640df049cc9396f4d753c10aa6ccc4 | |
parent | 24b0d3f0fdb86f7a4f9ecc9d9a8d01046094ed63 (diff) | |
download | FreeBSD-src-0f8fa3629e664a8cdfd6022cc1840102e3ff8c2c.zip FreeBSD-src-0f8fa3629e664a8cdfd6022cc1840102e3ff8c2c.tar.gz |
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
-rw-r--r-- | lib/libarchive/Makefile | 4 | ||||
-rw-r--r-- | lib/libarchive/archive.h.in | 3 | ||||
-rw-r--r-- | lib/libarchive/archive_read.3 | 8 | ||||
-rw-r--r-- | lib/libarchive/archive_write.3 | 24 | ||||
-rw-r--r-- | lib/libarchive/archive_write.c | 33 | ||||
-rw-r--r-- | lib/libarchive/archive_write_open_fd.c | 4 | ||||
-rw-r--r-- | lib/libarchive/archive_write_open_file.c | 4 | ||||
-rw-r--r-- | lib/libarchive/archive_write_open_filename.c | 4 | ||||
-rw-r--r-- | lib/libarchive/archive_write_open_memory.c | 4 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_compression_none.c | 37 |
10 files changed, 91 insertions, 34 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile index a024f9a..ac67026 100644 --- a/lib/libarchive/Makefile +++ b/lib/libarchive/Makefile @@ -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 diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in index 4567de7..e0fe3e0 100644 --- a/lib/libarchive/archive.h.in +++ b/lib/libarchive/archive.h.in @@ -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 *); diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3 index 7beb90e..cde80c9 100644 --- a/lib/libarchive/archive_read.3 +++ b/lib/libarchive/archive_read.3 @@ -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. diff --git a/lib/libarchive/archive_write.3 b/lib/libarchive/archive_write.3 index cb2b6a0..756d67d 100644 --- a/lib/libarchive/archive_write.3 +++ b/lib/libarchive/archive_write.3 @@ -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 diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c index aa50c70..4b288bf 100644 --- a/lib/libarchive/archive_write.c +++ b/lib/libarchive/archive_write.c @@ -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)); } diff --git a/lib/libarchive/archive_write_open_fd.c b/lib/libarchive/archive_write_open_fd.c index 8f979f5..bf4a26b 100644 --- a/lib/libarchive/archive_write_open_fd.c +++ b/lib/libarchive/archive_write_open_fd.c @@ -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; diff --git a/lib/libarchive/archive_write_open_file.c b/lib/libarchive/archive_write_open_file.c index 0eb1a03..b95693b 100644 --- a/lib/libarchive/archive_write_open_file.c +++ b/lib/libarchive/archive_write_open_file.c @@ -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; diff --git a/lib/libarchive/archive_write_open_filename.c b/lib/libarchive/archive_write_open_filename.c index c37caeb..8f2ece6 100644 --- a/lib/libarchive/archive_write_open_filename.c +++ b/lib/libarchive/archive_write_open_filename.c @@ -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; diff --git a/lib/libarchive/archive_write_open_memory.c b/lib/libarchive/archive_write_open_memory.c index 58baebd..120a79a 100644 --- a/lib/libarchive/archive_write_open_memory.c +++ b/lib/libarchive/archive_write_open_memory.c @@ -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; diff --git a/lib/libarchive/archive_write_set_compression_none.c b/lib/libarchive/archive_write_set_compression_none.c index 9e43365..3fdaa67 100644 --- a/lib/libarchive/archive_write_set_compression_none.c +++ b/lib/libarchive/archive_write_set_compression_none.c @@ -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. |