Hello,

Some time ago, I wrote a conv=sparse option for dd, attached is the
patch.  The goal is to recreate a sparse file from a file with 0s.
Typically, I use it to do this:

# mount /dev/hda6 /mnt/mnt
# dd bs=1M < /dev/zero > /mnt/mnt/foo
# rm -f /mnt/mnt/foo
# umount /mnt/mnt
# dd bs=1M conv=sparse < /dev/hda6 > /mnt/savhda6

Which creates a sparse file out of my not-so-filled partition.  Of
course, there may be other uses: re-sparsing a qemu image before tarring
it for public download, etc.

Maybe it could be useful to apply it mainstream?

Samuel
--- coreutils-5.2.1/src/dd.c    2005-06-26 22:31:51.000000000 +0200
+++ ../coreutils-mine/build-tree/coreutils-5.2.1/src/dd.c       2005-06-23 
22:49:33.000000000 +0200
@@ -80,6 +80,7 @@
 #define C_SYNC 02000
 /* Use separate input and output buffers, and combine partial input blocks. */
 #define C_TWOBUFS 04000
+#define C_SPARSE 010000
 
 /* The name this program was run with. */
 char *program_name;
@@ -168,9 +169,12 @@
   {"noerror", C_NOERROR},       /* Ignore i/o errors. */
   {"notrunc", C_NOTRUNC},       /* Do not truncate output file. */
   {"sync", C_SYNC},             /* Pad input records to ibs with NULs. */
+  {"sparse", C_SPARSE},                /* Generate sparse file */
   {NULL, 0}
 };
 
+size_t sparseblocksize;
+const char *zeroblock;
 
 /* Translation table formed by applying successive transformations. */
 static unsigned char trans_table[256];
@@ -1079,7 +1083,41 @@
 
       if (ibuf == obuf)                /* If not C_TWOBUFS. */
        {
-         size_t nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read);
+         size_t nwritten;
+
+         if (conversions_mask & C_SPARSE && (n_bytes_read % sparseblocksize) 
== 0)
+           {
+             size_t towrite = 0;
+             nwritten = 0;
+             if (memcmp(obuf, zeroblock, sparseblocksize))
+               goto firstnotzero;
+             while (nwritten < n_bytes_read) {
+               do {
+                 towrite += sparseblocksize;
+               } while (nwritten + towrite < n_bytes_read &&
+                   !memcmp (obuf + nwritten + towrite, zeroblock, 
sparseblocksize));
+               if (lseek (STDOUT_FILENO, towrite, SEEK_CUR) == -1)
+                 {
+                   error (0, errno, _("seeking %s"), quote (output_file));
+                   quit (EXIT_FAILURE);
+                 }
+               nwritten += towrite;
+               if (nwritten == n_bytes_read)
+                 break;
+               towrite = 0;
+firstnotzero:
+               do {
+                 towrite += sparseblocksize;
+               } while (nwritten + towrite < n_bytes_read &&
+                   memcmp (obuf + nwritten + towrite, zeroblock, 
sparseblocksize));
+               if (full_write (STDOUT_FILENO, obuf + nwritten, towrite) != 
towrite)
+                 break;
+               nwritten += towrite;
+               towrite = 0;
+             }
+           }
+         else
+           nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read);
 
          st.bytes += nwritten;
          
@@ -1261,6 +1299,18 @@
       output_file = _("standard output");
     }
 
+  if (conversions_mask & C_SPARSE)
+    {
+      struct stat stdout_stat;
+
+    if (fstat (STDOUT_FILENO, &stdout_stat) != 0)
+      error (EXIT_FAILURE, errno, _("cannot fstat %s"),
+            quote (output_file));
+
+      sparseblocksize = stdout_stat.st_blksize;
+      zeroblock = calloc(1,sparseblocksize);
+    }
+
   install_handler (SIGINT, interrupt_handler);
   install_handler (SIGQUIT, interrupt_handler);
   install_handler (SIGPIPE, interrupt_handler);
_______________________________________________
Bug-coreutils mailing list
Bug-coreutils@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to