Preserve sparseness of output file.
authorRichard W.M. Jones <rjones@redhat.com>
Mon, 21 Oct 2013 13:12:40 +0000 (14:12 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Mon, 21 Oct 2013 13:12:40 +0000 (14:12 +0100)
pxzcat.c

index befc2c0..18cc751 100644 (file)
--- a/pxzcat.c
+++ b/pxzcat.c
@@ -325,6 +325,26 @@ parse_indexes (const char *filename, int fd)
   return combined_index;
 }
 
+#define BUFFER_SIZE (64*1024)
+
+/* Return true iff the buffer is all zero bytes.
+ *
+ * Note that gcc is smart enough to optimize this properly:
+ * http://stackoverflow.com/questions/1493936/faster-means-of-checking-for-an-empty-buffer-in-c/1493989#1493989
+ */
+static inline int
+is_zero (const char *buffer, size_t size)
+{
+  size_t i;
+
+  for (i = 0; i < size; ++i) {
+    if (buffer[i] != 0)
+      return 0;
+  }
+
+  return 1;
+}
+
 /* Iterate over the blocks and uncompress. */
 static void
 iter_blocks (lzma_index *idx,
@@ -337,7 +357,7 @@ iter_blocks (lzma_index *idx,
   lzma_filter filters[LZMA_FILTERS_MAX + 1];
   lzma_ret r;
   lzma_stream strm = LZMA_STREAM_INIT;
-  char outbuf[BUFSIZ];
+  char outbuf[BUFFER_SIZE];
   size_t i;
 
   lzma_index_iter_init (&iter, idx);
@@ -400,7 +420,7 @@ iter_blocks (lzma_index *idx,
     strm.avail_out = sizeof outbuf;
 
     for (;;) {
-      uint8_t buf[BUFSIZ];
+      uint8_t buf[BUFFER_SIZE];
       lzma_action action = LZMA_RUN;
 
       if (strm.avail_in == 0) {
@@ -417,9 +437,16 @@ iter_blocks (lzma_index *idx,
 
       if (strm.avail_out == 0 || r == LZMA_STREAM_END) {
         size_t wsz = sizeof outbuf - strm.avail_out;
-        if (write (ofd, outbuf, wsz) != wsz)
-          /* XXX Handle short writes. */
-          error (EXIT_FAILURE, errno, "%s: write", filename);
+
+        if (is_zero (outbuf, wsz)) { /* Seek to preserve sparseness. */
+          if (lseek (ofd, wsz, SEEK_CUR) == (off_t) -1)
+            error (EXIT_FAILURE, errno, "%s: seek", filename);
+        } else {
+          if (write (ofd, outbuf, wsz) != wsz)
+            /* XXX Handle short writes. */
+            error (EXIT_FAILURE, errno, "%s: write", filename);
+        }
+
         strm.next_out = outbuf;
         strm.avail_out = sizeof outbuf;
       }