summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2006-11-26 19:00:50 +0000
committerkientzle <kientzle@FreeBSD.org>2006-11-26 19:00:50 +0000
commit0f8fa3629e664a8cdfd6022cc1840102e3ff8c2c (patch)
treeebb3f03dd6640df049cc9396f4d753c10aa6ccc4
parent24b0d3f0fdb86f7a4f9ecc9d9a8d01046094ed63 (diff)
downloadFreeBSD-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/Makefile4
-rw-r--r--lib/libarchive/archive.h.in3
-rw-r--r--lib/libarchive/archive_read.38
-rw-r--r--lib/libarchive/archive_write.324
-rw-r--r--lib/libarchive/archive_write.c33
-rw-r--r--lib/libarchive/archive_write_open_fd.c4
-rw-r--r--lib/libarchive/archive_write_open_file.c4
-rw-r--r--lib/libarchive/archive_write_open_filename.c4
-rw-r--r--lib/libarchive/archive_write_open_memory.c4
-rw-r--r--lib/libarchive/archive_write_set_compression_none.c37
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.
OpenPOWER on IntegriCloud