bsdtar doesn't detect end of tape

Tim Kientzle kientzle at freebsd.org
Thu Sep 23 08:24:34 PDT 2004


Oliver Lehmann wrote:
> Hi,
> 
> I can store more files on tape with bsdtar than I'm able to read back.
> 
> root at nudel dds2> tar -c -b 64 -v -f /dev/sa3 .
> [writes more files than the tape can handle - w/o an error!!]
> root at nudel dds2> tar -x -b 64 -v -f /dev/sa3
> [...]
> x nudel/pics/selftreffen_2001.tar.bz2
> x nudel/pics/selftreffen_2002.tar.bz2: (null)
> tar: (null)
> Exit 1
> root at nudel dds2> 

Oliver,

The libarchive in 5.3 does have a bug where
it fails to correctly propagate write errors
back to the caller.  In this case, bsdtar never
sees the write error and keeps going beyond
end-of-tape.

Try the attached patch to src/lib/libarchive,
rebuild libarchive and bsdtar and let me
know if it fixes it for you.

My current plan is to put this into 6-CURRENT
just after 5.3 gets released and MFC them a
few weeks later.  If there's enough demand,
I'll reconsider this plan.

Tim

P.S.  This is a hastily-done diff between the
5-stable version of libarchive and my current
development version, which has a bit more
than just the write error fix.  It would take
me a day or so to separate it out into the two
different patches it really should be.
-------------- next part --------------
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive.h.in libarchive-stable/archive.h.in
--- libarchive/archive.h.in	Tue Aug 31 22:14:10 2004
+++ libarchive-stable/archive.h.in	Sat Aug  7 12:22:50 2004
@@ -291,7 +291,7 @@
  */
 int		 archive_write_header(struct archive *,
 		     struct archive_entry *);
-ssize_t		 archive_write_data(struct archive *, const void *, size_t);
+int		 archive_write_data(struct archive *, const void *, size_t);
 int		 archive_write_close(struct archive *);
 void		 archive_write_finish(struct archive *);
 
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_read_extract.c libarchive-stable/archive_read_extract.c
--- libarchive/archive_read_extract.c	Fri Aug 27 22:29:47 2004
+++ libarchive-stable/archive_read_extract.c	Wed Sep  1 21:00:12 2004
@@ -488,7 +488,6 @@
 
 	if (extract->pst != NULL) {
 		extract->pst = &extract->st;
-		/* If dir already exists, don't reset permissions. */
 		if (S_ISDIR(extract->pst->st_mode))
 			return (ARCHIVE_OK);
 		/* It exists but isn't a dir. */
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_read_support_compression_bzip2.c libarchive-stable/archive_read_support_compression_bzip2.c
--- libarchive/archive_read_support_compression_bzip2.c	Mon Aug 30 21:42:13 2004
+++ libarchive-stable/archive_read_support_compression_bzip2.c	Fri Aug 13 20:45:45 2004
@@ -29,7 +29,6 @@
 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.6 2004/08/14 03:45:45 kientzle Exp $");
 
 #include <errno.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_read_support_compression_compress.c libarchive-stable/archive_read_support_compression_compress.c
--- libarchive/archive_read_support_compression_compress.c	Fri Aug 13 21:12:55 2004
+++ libarchive-stable/archive_read_support_compression_compress.c	Fri Aug 13 20:45:45 2004
@@ -295,10 +295,8 @@
 				read_avail++;
 			} else {
 				ret = next_code(a, state);
-				if (ret == ARCHIVE_EOF)
+				if (ret)
 					state->end_of_stream = ret;
-				else if (ret != ARCHIVE_OK)
-					return (ret);
 			}
 		}
 	}
@@ -348,8 +346,7 @@
 
 /*
  * Process the next code and fill the stack with the expansion
- * of the code.  Returns ARCHIVE_FATAL if there is a fatal I/O or
- * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
+ * of the code.  Returns TRUE if we hit the end of the data.
  */
 static int
 next_code(struct archive *a, struct private_data *state)
@@ -394,11 +391,9 @@
 		return (next_code(a, state));
 	}
 
-	if (code > state->free_ent) {
-		/* An invalid code is a fatal error. */
-		archive_set_error(a, -1, "Invalid compressed data");
-		return (ARCHIVE_FATAL);
-	}
+	if (code > state->free_ent)
+		/* XXX invalid code?  This is fatal. XXX */
+		return (1);
 
 	/* Special case for KwKwK string. */
 	if (code >= state->free_ent) {
@@ -431,7 +426,7 @@
 
 	/* Remember previous code. */
 	state->oldcode = newcode;
-	return (ARCHIVE_OK);
+	return (0);
 }
 
 /*
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_read_support_format_tar.c libarchive-stable/archive_read_support_format_tar.c
--- libarchive/archive_read_support_format_tar.c	Sat Sep  4 13:59:40 2004
+++ libarchive-stable/archive_read_support_format_tar.c	Thu Sep  9 21:30:24 2004
@@ -534,7 +534,6 @@
 		}
 	}
 	--tar->header_recursion_depth;
-
 	return (err);
 }
 
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_string.c libarchive-stable/archive_string.c
--- libarchive/archive_string.c	Fri Aug 27 21:46:36 2004
+++ libarchive-stable/archive_string.c	Fri Aug 13 20:45:45 2004
@@ -96,18 +96,3 @@
 {
 	return (__archive_string_append(as, &c, 1));
 }
-
-struct archive_string *
-__archive_strappend_int(struct archive_string *as, int d, int base)
-{
-	static const char *digits = "0123457890abcdef";
-
-	if (d < 0) {
-		__archive_strappend_char(as, '-');
-		d = -d;
-	}
-	if (d >= base)
-		__archive_strappend_int(as, d/base, base);
-	__archive_strappend_char(as, digits[d % base]);
-	return (as);
-}
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_string.h libarchive-stable/archive_string.h
--- libarchive/archive_string.h	Fri Aug 27 21:47:20 2004
+++ libarchive-stable/archive_string.h	Sun May  2 18:40:34 2004
@@ -64,10 +64,6 @@
 __archive_strappend_char_UTF8(struct archive_string *, int);
 #define	archive_strappend_char_UTF8 __archive_strappend_char_UTF8
 
-/* Append an integer in the specified base (2 <= base <= 16). */
-struct archive_string *
-__archive_strappend_int(struct archive_string *as, int d, int base);
-
 /* Basic append operation. */
 struct archive_string *
 __archive_string_append(struct archive_string *as, const char *p, size_t s);
@@ -107,5 +103,10 @@
 void	__archive_string_vsprintf(struct archive_string *, const char *,
 	    va_list);
 #define	archive_string_vsprintf	__archive_string_vsprintf
+
+/* Like 'sprintf', but resizes the underlying string as necessary. */
+void	__archive_string_sprintf(struct archive_string *, const char *, ...);
+#define	archive_string_sprintf	__archive_string_sprintf
+
 
 #endif
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_string_sprintf.c libarchive-stable/archive_string_sprintf.c
--- libarchive/archive_string_sprintf.c	Sun Aug 29 12:53:34 2004
+++ libarchive-stable/archive_string_sprintf.c	Mon Aug 30 22:10:36 2004
@@ -46,56 +46,34 @@
 __archive_string_vsprintf(struct archive_string *as, const char *fmt,
     va_list ap)
 {
-	int long_flag, d;
-	long l;
-	const char *p, *s;
-
-	__archive_string_ensure(as, 64);
+	size_t l;
+	va_list ap1;
 
 	if (fmt == NULL) {
 		as->s[0] = 0;
 		return;
 	}
 
-	long_flag = 0;
-	for (p = fmt; *p != '\0'; p++) {
-		if (*p != '%') {
-			archive_strappend_char(as, *p);
-			continue;
-		}
-
-		p++;
-
-		switch(*p) {
-		case 'l':
-			long_flag = 1;
-			p++;
-			break;
-		}
-
-		switch (*p) {
-		case 's':
-			s = va_arg(ap, char *);
-			archive_strcat(as, s);
-			break;
-		case 'd':
-			if (long_flag) {
-				l = va_arg(ap, long);
-				__archive_strappend_int(as, l, 10);
-			} else {
-				d = va_arg(ap, int);
-				__archive_strappend_int(as, d, 10);
-			}
-			break;
-		case 'o':
-			if (long_flag) {
-				l = va_arg(ap, long);
-				__archive_strappend_int(as, l, 8);
-			} else {
-				d = va_arg(ap, int);
-				__archive_strappend_int(as, d, 8);
-			}
-			break;
-		}
+	va_copy(ap1, ap);
+	l = vsnprintf(as->s, as->buffer_length, fmt, ap);
+	/* If output is bigger than the buffer, resize and try again. */
+	if (l+1 >= as->buffer_length) {
+		__archive_string_ensure(as, l + 1);
+		l = vsnprintf(as->s, as->buffer_length, fmt, ap1);
 	}
+	as->length = l;
+	va_end(ap1);
+}
+
+/*
+ * Corresponding 'sprintf' interface.
+ */
+void
+__archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__archive_string_vsprintf(as, fmt, ap);
+	va_end(ap);
 }
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write.3 libarchive-stable/archive_write.3
--- libarchive/archive_write.3	Tue Aug 31 22:17:02 2004
+++ libarchive-stable/archive_write.3	Sat Aug  7 12:22:50 2004
@@ -80,7 +80,7 @@
 .Fn archive_write_open_file "struct archive *" "const char *filename"
 .Ft int
 .Fn archive_write_header "struct archive *"
-.Ft ssize_t
+.Ft int
 .Fn archive_write_data "struct archive *" "const void *" "size_t"
 .Ft int
 .Fn archive_write_close "struct archive *"
@@ -190,7 +190,6 @@
 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
@@ -322,19 +321,20 @@
 .Fn archive_error_string
 functions will return appropriate values.
 Note that if the client-provided write callback function
-returns a non-zero value, that error will be propagated back to the caller
+returns -1, 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 .
-The client callback can call
-.Fn archive_set_error
-to provide values that can then be retrieved by
+In such a case, the
 .Fn archive_errno
-and
-.Fn archive_error_string .
+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.
 .Sh SEE ALSO
 .Xr tar 1 ,
 .Xr libarchive 3 ,
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write.c libarchive-stable/archive_write.c
--- libarchive/archive_write.c	Sat Sep  4 13:45:22 2004
+++ libarchive-stable/archive_write.c	Fri Aug 13 20:43:35 2004
@@ -215,11 +215,9 @@
 /*
  * Note that the compressor is responsible for blocking.
  */
-ssize_t
+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);
-	ret = (a->format_write_data)(a, buff, s);
-	return (ret == ARCHIVE_OK ? (ssize_t)s : -1);
+	return (a->format_write_data(a, buff, s));
 }
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_compression_bzip2.c libarchive-stable/archive_write_set_compression_bzip2.c
--- libarchive/archive_write_set_compression_bzip2.c	Mon Aug 30 21:42:00 2004
+++ libarchive-stable/archive_write_set_compression_bzip2.c	Thu Jul 29 21:14:47 2004
@@ -32,7 +32,6 @@
 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_bzip2.c,v 1.5 2004/07/30 04:14:47 kientzle Exp $");
 
 #include <errno.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <bzlib.h>
@@ -154,17 +153,15 @@
 
 /*
  * Write data to the compressed stream.
- *
- * Returns ARCHIVE_OK if all data written, error otherwise.
  */
-static int
+static ssize_t
 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 == NULL) {
+	if (!a->client_writer) {
 		archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
 		    "No write callback is registered?  "
 		    "This is probably an internal programming error.");
@@ -178,9 +175,9 @@
 	SET_NEXT_IN(state, buff);
 	state->stream.avail_in = length;
 	if (drive_compressor(a, state, 0))
-		return (ARCHIVE_FATAL);
+		return (-1);
 	a->file_position += length;
-	return (ARCHIVE_OK);
+	return (length);
 }
 
 
@@ -194,7 +191,6 @@
 	int ret;
 	struct private_data *state;
 	ssize_t target_block_length;
-	ssize_t bytes_written;
 	unsigned tocopy;
 
 	state = a->compression_data;
@@ -250,16 +246,12 @@
 	}
 
 	/* Write the last block */
-	bytes_written = (a->client_writer)(a, a->client_data,
-	    state->compressed, block_length);
+	ret = (a->client_writer)(a, a->client_data, state->compressed,
+	    block_length);
 
-	/* TODO: Handle short write of final block. */
-	if (bytes_written <= 0)
-		ret = ARCHIVE_FATAL;
-	else {
-		a->raw_position += ret;
-		ret = ARCHIVE_OK;
-	}
+	a->raw_position += ret;
+	if (ret != 0)
+		goto cleanup;
 
 	/* Cleanup: shut down compressor, release memory, etc. */
 cleanup:
@@ -292,28 +284,27 @@
 static int
 drive_compressor(struct archive *a, struct private_data *state, int finishing)
 {
-	size_t	bytes_written;
-	int ret;
+	size_t	ret;
 
 	for (;;) {
 		if (state->stream.avail_out == 0) {
-			bytes_written = (a->client_writer)(a, a->client_data,
+			ret = (a->client_writer)(a, a->client_data,
 			    state->compressed, state->compressed_buffer_size);
-			if (bytes_written <= 0) {
+			if (ret <= 0) {
 				/* TODO: Handle this write failure */
 				return (ARCHIVE_FATAL);
-			} else if (bytes_written < state->compressed_buffer_size) {
+			} else if (ret < state->compressed_buffer_size) {
 				/* Short write: Move remainder to
 				 * front and keep filling */
 				memmove(state->compressed,
-				    state->compressed + bytes_written,
-				    state->compressed_buffer_size - bytes_written);
+				    state->compressed + ret,
+				    state->compressed_buffer_size - ret);
 			}
 
-			a->raw_position += bytes_written;
+			a->raw_position += ret;
 			state->stream.next_out = state->compressed +
-			    state->compressed_buffer_size - bytes_written;
-			state->stream.avail_out = bytes_written;
+			    state->compressed_buffer_size - ret;
+			state->stream.avail_out = ret;
 		}
 
 		ret = BZ2_bzCompress(&(state->stream),
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_compression_gzip.c libarchive-stable/archive_write_set_compression_gzip.c
--- libarchive/archive_write_set_compression_gzip.c	Sat Aug 21 12:31:03 2004
+++ libarchive-stable/archive_write_set_compression_gzip.c	Sat Aug  7 12:21:18 2004
@@ -179,7 +179,7 @@
 /*
  * Write data to the compressed stream.
  */
-static int
+static ssize_t
 archive_compressor_gzip_write(struct archive *a, const void *buff,
     size_t length)
 {
@@ -187,7 +187,7 @@
 	int ret;
 
 	state = a->compression_data;
-	if (a->client_writer == NULL) {
+	if (!a->client_writer) {
 		archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
 		    "No write callback is registered?  "
 		    "This is probably an internal programming error.");
@@ -205,7 +205,7 @@
 		return (ret);
 
 	a->file_position += length;
-	return (ARCHIVE_OK);
+	return (length);
 }
 
 
@@ -215,7 +215,7 @@
 static int
 archive_compressor_gzip_finish(struct archive *a)
 {
-	ssize_t block_length, target_block_length, bytes_written;
+	ssize_t block_length, target_block_length;
 	int ret;
 	struct private_data *state;
 	unsigned tocopy;
@@ -273,13 +273,9 @@
 
 	/* If it overflowed, flush and start a new block. */
 	if (tocopy < 8) {
-		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;
+		ret = (a->client_writer)(a, a->client_data, state->compressed,
+		    state->compressed_buffer_size);
+		a->raw_position += ret;
 		state->stream.next_out = state->compressed;
 		state->stream.avail_out = state->compressed_buffer_size;
 		memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
@@ -310,13 +306,9 @@
 	}
 
 	/* Write the last block */
-	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;
+	ret = (a->client_writer)(a, a->client_data, state->compressed,
+	    block_length);
+	a->raw_position += ret;
 
 	/* Cleanup: shut down compressor, release memory, etc. */
 cleanup:
@@ -348,28 +340,27 @@
 static int
 drive_compressor(struct archive *a, struct private_data *state, int finishing)
 {
-	size_t bytes_written;
-	int ret;
+	size_t ret;
 
 	for (;;) {
 		if (state->stream.avail_out == 0) {
-			bytes_written = (a->client_writer)(a, a->client_data,
+			ret = (a->client_writer)(a, a->client_data,
 			    state->compressed, state->compressed_buffer_size);
-			if (bytes_written <= 0) {
+			if (ret <= 0) {
 				/* TODO: Handle this write failure */
 				return (ARCHIVE_FATAL);
-			} else if (bytes_written < state->compressed_buffer_size) {
+			} else if (ret < state->compressed_buffer_size) {
 				/* Short write: Move remaining to
 				 * front of block and keep filling */
 				memmove(state->compressed,
-				    state->compressed + bytes_written,
-				    state->compressed_buffer_size - bytes_written);
+				    state->compressed + ret,
+				    state->compressed_buffer_size - ret);
 			}
-			a->raw_position += bytes_written;
+			a->raw_position += ret;
 			state->stream.next_out
 			    = state->compressed +
-			    state->compressed_buffer_size - bytes_written;
-			state->stream.avail_out = bytes_written;
+			    state->compressed_buffer_size - ret;
+			state->stream.avail_out = ret;
 		}
 
 		ret = deflate(&(state->stream),
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_compression_none.c libarchive-stable/archive_write_set_compression_none.c
--- libarchive/archive_write_set_compression_none.c	Sat Aug 21 12:29:08 2004
+++ libarchive-stable/archive_write_set_compression_none.c	Sat Aug  7 12:21:18 2004
@@ -104,13 +104,13 @@
 /*
  * Write data to the stream.
  */
-static int
+static ssize_t
 archive_compressor_none_write(struct archive *a, const void *vbuff,
     size_t length)
 {
 	const char *buff;
 	ssize_t remaining, to_copy;
-	ssize_t bytes_written;
+	int ret;
 	struct archive_none *state;
 
 	state = a->compression_data;
@@ -129,12 +129,10 @@
 		 * output buffer.
 		 */
 		if (state->avail == 0) {
-			bytes_written = (a->client_writer)(a, a->client_data,
+			ret = (a->client_writer)(a, a->client_data,
 			    state->buffer, state->buffer_size);
-			if (bytes_written <= 0)
-				return (ARCHIVE_FATAL);
-			/* XXX TODO: if bytes_written < state->buffer_size */
-			a->raw_position += bytes_written;
+			/* XXX TODO: if ret < state->buffer_size XXX */
+			a->raw_position += ret;
 			state->next = state->buffer;
 			state->avail = state->buffer_size;
 		}
@@ -149,7 +147,7 @@
 		remaining -= to_copy;
 	}
 	a->file_position += length;
-	return (ARCHIVE_OK);
+	return (length);
 }
 
 
@@ -161,7 +159,6 @@
 {
 	ssize_t block_length;
 	ssize_t target_block_length;
-	ssize_t bytes_written;
 	int ret;
 	int ret2;
 	struct archive_none *state;
@@ -196,14 +193,9 @@
 			    target_block_length - block_length);
 			block_length = target_block_length;
 		}
-		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;
-		}
+		ret = (a->client_writer)(a, a->client_data, state->buffer,
+		    block_length);
+		a->raw_position += ret;
 	}
 
 	/* Close the output */
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_format_cpio.c libarchive-stable/archive_write_set_format_cpio.c
--- libarchive/archive_write_set_format_cpio.c	Sat Aug 21 13:42:49 2004
+++ libarchive-stable/archive_write_set_format_cpio.c	Tue Apr 13 16:45:37 2004
@@ -99,7 +99,7 @@
 {
 	struct cpio *cpio;
 	const char *p, *path;
-	int pathlength, ret;
+	int pathlength, ret, written;
 	const struct stat	*st;
 	struct cpio_header	 h;
 
@@ -142,19 +142,19 @@
 	else
 		format_octal(st->st_size, &h.c_filesize, sizeof(h.c_filesize));
 
-	ret = (a->compression_write)(a, &h, sizeof(h));
-	if (ret != ARCHIVE_OK)
+	written = (a->compression_write)(a, &h, sizeof(h));
+	if (written < (int)sizeof(h))
 		return (ARCHIVE_FATAL);
 
-	ret = (a->compression_write)(a, path, pathlength);
-	if (ret != ARCHIVE_OK)
+	written = (a->compression_write)(a, path, pathlength);
+	if (written < (int)pathlength)
 		return (ARCHIVE_FATAL);
 
 	cpio->entry_bytes_remaining = st->st_size;
 
 	/* Write the symlink now. */
 	if (p != NULL  &&  *p != '\0')
-		ret = (a->compression_write)(a, p, strlen(p));
+		(a->compression_write)(a, p, strlen(p));
 
 	return (ret);
 }
@@ -233,13 +233,13 @@
 	int to_write, ret;
 
 	cpio = a->format_data;
-	ret = ARCHIVE_OK;
+	ret = 0;
 	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 != ARCHIVE_OK)
-			return (ret);
+		if (ret < to_write)
+			return (-1);
 		cpio->entry_bytes_remaining -= to_write;
 	}
 	return (ret);
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_format_pax.c libarchive-stable/archive_write_set_format_pax.c
--- libarchive/archive_write_set_format_pax.c	Sat Aug 21 13:32:37 2004
+++ libarchive-stable/archive_write_set_format_pax.c	Mon Sep 20 20:38:06 2004
@@ -414,7 +414,7 @@
 	}
 
 	/* If numeric GID is too large, add 'gid' to pax extended attrs. */
-	if (st_main->st_gid >= (1 << 20)) {
+	if (st_main->st_gid >= (1 << 18)) {
 		add_pax_attr_int(&(pax->pax_header), "gid", st_main->st_gid);
 		need_extension = 1;
 	}
@@ -429,7 +429,7 @@
 	}
 
 	/* If numeric UID is too large, add 'uid' to pax extended attrs. */
-	if (st_main->st_uid >= (1 << 20)) {
+	if (st_main->st_uid >= (1 << 18)) {
 		add_pax_attr_int(&(pax->pax_header), "uid", st_main->st_uid);
 		need_extension = 1;
 	}
@@ -622,7 +622,7 @@
 	__archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0);
 
 	/* If we built any extended attributes, write that entry first. */
-	ret = ARCHIVE_OK;
+	ret = 0;
 	if (archive_strlen(&(pax->pax_header)) > 0) {
 		struct stat st;
 		struct archive_entry *pax_attr_entry;
@@ -636,7 +636,11 @@
 		archive_entry_set_pathname(pax_attr_entry, pax_attr_name);
 		st.st_size = archive_strlen(&(pax->pax_header));
 		st.st_uid = st_main->st_uid;
+		if (st.st_uid >= 1 << 18)
+			st.st_uid = (1 << 18) - 1;
 		st.st_gid = st_main->st_gid;
+		if (st.st_gid >= 1 << 18)
+			st.st_gid = (1 << 18) - 1;
 		st.st_mode = st_main->st_mode;
 		archive_entry_copy_stat(pax_attr_entry, &st);
 
@@ -659,7 +663,7 @@
 			exit(1);
 		}
 		r = (a->compression_write)(a, paxbuff, 512);
-		if (r != ARCHIVE_OK) {
+		if (r < 512) {
 			pax->entry_bytes_remaining = 0;
 			pax->entry_padding = 0;
 			return (ARCHIVE_FATAL);
@@ -673,7 +677,7 @@
 		r = archive_write_data(a, pax->pax_header.s,
 		    archive_strlen(&(pax->pax_header)));
 		a->state = oldstate;
-		if (r != ARCHIVE_OK) {
+		if (r < (int)archive_strlen(&(pax->pax_header))) {
 			/* If a write fails, we're pretty much toast. */
 			return (ARCHIVE_FATAL);
 		}
@@ -683,8 +687,8 @@
 
 	/* Write the header for main entry. */
 	r = (a->compression_write)(a, ustarbuff, 512);
-	if (r != ARCHIVE_OK)
-		return (r);
+	if (ret != ARCHIVE_OK)
+		ret = (r < 512) ? ARCHIVE_FATAL : ARCHIVE_OK;
 
 	/*
 	 * Inform the client of the on-disk size we're using, so
@@ -835,9 +839,9 @@
 	while (padding > 0) {
 		to_write = padding < a->null_length ? padding : a->null_length;
 		ret = (a->compression_write)(a, a->nulls, to_write);
-		if (ret != ARCHIVE_OK)
-			return (ret);
-		padding -= to_write;
+		if (ret <= 0)
+			return (ARCHIVE_FATAL);
+		padding -= ret;
 	}
 	return (ARCHIVE_OK);
 }
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_format_shar.c libarchive-stable/archive_write_set_format_shar.c
--- libarchive/archive_write_set_format_shar.c	Fri Aug 27 22:36:36 2004
+++ libarchive-stable/archive_write_set_format_shar.c	Sun Jun 27 11:38:13 2004
@@ -50,7 +50,8 @@
 	int			 uuavail;
 	char			 uubuffer[3];
 	int			 wrote_header;
-	struct archive_string	 work;
+	char			*work;
+	size_t			 work_len;
 };
 
 static int	archive_write_shar_finish(struct archive *);
@@ -69,13 +70,23 @@
 {
 	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);
-	archive_string_empty(&(shar->work));
-	archive_string_vsprintf(&(shar->work), fmt, ap);
-	ret = ((a->compression_write)(a, shar->work.s, strlen(shar->work.s)));
+	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)));
 	va_end(ap);
 	return (ret);
 }
@@ -138,16 +149,11 @@
 	char *p, *pp;
 	struct shar *shar;
 	const struct stat *st;
-	int ret;
 
 	shar = a->format_data;
 	if (!shar->wrote_header) {
-		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_printf(a, "#!/bin/sh\n");
+		shar_printf(a, "# This is a shell archive\n");
 		shar->wrote_header = 1;
 	}
 
@@ -186,9 +192,7 @@
 	}
 
 	/* Stock preparation for all file types. */
-	ret = shar_printf(a, "echo x %s\n", name);
-	if (ret != ARCHIVE_OK)
-		return (ret);
+	shar_printf(a, "echo x %s\n", name);
 
 	if (!S_ISDIR(st->st_mode)) {
 		/* Try to create the dir. */
@@ -202,10 +206,8 @@
 			if (strcmp(p, ".") == 0) {
 				/* Don't try to "mkdir ." */
 			} else if (shar->last_dir == NULL) {
-				ret = shar_printf(a,
+				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. */
@@ -215,10 +217,8 @@
 				/* We've already created a subdir. */
 				free(p);
 			} else {
-				ret = shar_printf(a,
+				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,40 +227,27 @@
 
 	/* Handle file-type specific issues. */
 	shar->has_data = 0;
-	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 {
+	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 {
 		switch(st->st_mode & S_IFMT) {
 		case S_IFREG:
-			if (archive_entry_size(entry) == 0) {
-				ret = shar_printf(a, "touch %s\n", name);
-				if (ret != ARCHIVE_OK)
-					return (ret);
-			} else {
+			if (archive_entry_size(entry) == 0)
+				shar_printf(a, "touch %s\n", name);
+			else {
 				if (shar->dump) {
-					ret = shar_printf(a,
+					shar_printf(a,
 					    "uudecode -o %s << 'SHAR_END'\n",
 					    name);
-					if (ret != ARCHIVE_OK)
-						return (ret);
-					ret = shar_printf(a, "begin %o %s\n",
+					shar_printf(a, "begin %o %s\n",
 					    archive_entry_mode(entry) & 0777,
 					    name);
-					if (ret != ARCHIVE_OK)
-						return (ret);
-				} else {
-					ret = shar_printf(a,
+				} else
+					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;
@@ -268,10 +255,7 @@
 			}
 			break;
 		case S_IFDIR:
-			ret = shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n",
-			    name);
-			if (ret != ARCHIVE_OK)
-				return (ret);
+			shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n", name);
 			/* Record that we just created this directory. */
 			if (shar->last_dir != NULL)
 				free(shar->last_dir);
@@ -287,23 +271,17 @@
 			 */
 			break;
 		case S_IFIFO:
-			ret = shar_printf(a, "mkfifo %s\n", name);
-			if (ret != ARCHIVE_OK)
-				return (ret);
+			shar_printf(a, "mkfifo %s\n", name);
 			break;
 		case S_IFCHR:
-			ret = shar_printf(a, "mknod %s c %d %d\n", name,
+			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:
-			ret = shar_printf(a, "mknod %s b %d %d\n", name,
+			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);
@@ -315,18 +293,18 @@
 
 /* XXX TODO: This could be more efficient XXX */
 static int
-archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
+archive_write_shar_data_sed(struct archive *a, const void *buff, size_t length)
 {
 	struct shar *shar;
 	const char *src;
-	int ret;
+	size_t n;
 
 	shar = a->format_data;
 	if (!shar->has_data)
 		return (0);
 
 	src = buff;
-	ret = ARCHIVE_OK;
+	n = length;
 	shar->outpos = 0;
 	while (n-- > 0) {
 		if (shar->end_of_line) {
@@ -338,17 +316,14 @@
 		shar->outbuff[shar->outpos++] = *src++;
 
 		if (shar->outpos > sizeof(shar->outbuff) - 2) {
-			ret = (a->compression_write)(a, shar->outbuff,
-			    shar->outpos);
-			if (ret != ARCHIVE_OK)
-				return (ret);
+			(a->compression_write)(a, shar->outbuff, shar->outpos);
 			shar->outpos = 0;
 		}
 	}
 
 	if (shar->outpos > 0)
-		ret = (a->compression_write)(a, shar->outbuff, shar->outpos);
-	return (ret);
+		(a->compression_write)(a, shar->outbuff, shar->outpos);
+	return (length);
 }
 
 #define	UUENC(c)	(((c)!=0) ? ((c) & 077) + ' ': '`')
@@ -382,7 +357,6 @@
 	struct shar *shar;
 	const char *src;
 	size_t n;
-	int ret;
 
 	shar = a->format_data;
 	if (!shar->has_data)
@@ -393,10 +367,8 @@
 		if (shar->uuavail == 3)
 			uuencode_group(shar);
 		if (shar->outpos >= 60) {
-			ret = shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
+			shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
 			    shar->outbuff);
-			if (ret != ARCHIVE_OK)
-				return (ret);
 			shar->outpos = 0;
 			shar->outbytes = 0;
 		}
@@ -404,7 +376,7 @@
 		shar->uubuffer[shar->uuavail++] = *src++;
 		shar->outbytes++;
 	}
-	return (ARCHIVE_OK);
+	return (length);
 }
 
 static int
@@ -412,7 +384,6 @@
 {
 	const char *g, *p, *u;
 	struct shar *shar;
-	int ret;
 
 	shar = a->format_data;
 	if (shar->entry == NULL)
@@ -424,51 +395,37 @@
 			if (shar->uuavail > 0)
 				uuencode_group(shar);
 			if (shar->outpos > 0) {
-				ret = shar_printf(a, "%c%s\n",
-				    UUENC(shar->outbytes), shar->outbuff);
-				if (ret != ARCHIVE_OK)
-					return (ret);
+				shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
+				    shar->outbuff);
 				shar->outpos = 0;
 				shar->uuavail = 0;
 				shar->outbytes = 0;
 			}
-			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);
+			shar_printf(a, "%c\n", UUENC(0));
+			shar_printf(a, "end\n", UUENC(0));
+			shar_printf(a, "SHAR_END\n");
 		}
 		/* Restore file mode, owner, flags. */
 		/*
 		 * TODO: Don't immediately restore mode for
 		 * directories; defer that to end of script.
 		 */
-		ret = shar_printf(a, "chmod %o %s\n",
+		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) {
-			ret = shar_printf(a, "chown %s%s%s %s\n",
+			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) {
-			ret = shar_printf(a, "chflags %s %s\n", p,
+			shar_printf(a, "chflags %s %s\n", p,
 			    archive_entry_pathname(shar->entry));
-			if (ret != ARCHIVE_OK)
-				return (ret);
 		}
 
 		/* TODO: restore ACLs */
@@ -476,14 +433,9 @@
 	} else {
 		if (shar->has_data) {
 			/* Finish sed-encoded data:  ensure last line ends. */
-			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);
+			if (!shar->end_of_line)
+				shar_printf(a, "\n");
+			shar_printf(a, "SHAR_END\n");
 		}
 	}
 
@@ -496,7 +448,6 @@
 archive_write_shar_finish(struct archive *a)
 {
 	struct shar *shar;
-	int ret;
 
 	/*
 	 * TODO: Accumulate list of directory names/modes and
@@ -512,9 +463,7 @@
 	 * shar_finish to free the format-specific data).
 	 */
 	if (shar->wrote_header) {
-		ret = shar_printf(a, "exit\n");
-		if (ret != ARCHIVE_OK)
-			return (ret);
+		shar_printf(a, "exit\n");
 		/* Shar output is never padded. */
 		archive_write_set_bytes_in_last_block(a, 1);
 		/*
@@ -526,7 +475,8 @@
 		archive_entry_free(shar->entry);
 	if (shar->last_dir != NULL)
 		free(shar->last_dir);
-	archive_string_free(&(shar->work));
+	if (shar->work != NULL)
+		free(shar->work);
 	free(shar);
 	a->format_data = NULL;
 	return (ARCHIVE_OK);
diff -u -x Makefile -x archive_check_magic.c -x CVS -I FreeBSD -r libarchive/archive_write_set_format_ustar.c libarchive-stable/archive_write_set_format_ustar.c
--- libarchive/archive_write_set_format_ustar.c	Sat Aug 21 13:41:49 2004
+++ libarchive-stable/archive_write_set_format_ustar.c	Fri Aug  6 19:24:20 2004
@@ -157,8 +157,8 @@
 	if (ret != ARCHIVE_OK)
 		return (ret);
 	ret = (a->compression_write)(a, buff, 512);
-	if (ret != ARCHIVE_OK)
-		return (ret);
+	if (ret < 512)
+		return (ARCHIVE_FATAL);
 
 	ustar->entry_bytes_remaining = archive_entry_size(entry);
 	ustar->entry_padding = 0x1ff & (- ustar->entry_bytes_remaining);


More information about the freebsd-current mailing list