Package: dump
Version: 0.4b47-4+~tjw12r5
Severity: important

Dear Maintainer,

Dump includes data read from EXT2_EXTENT_FLAGS_UNINIT extents in the
dump instead of writing zeros (or nothing) to the tape.

This means that restores are corrupted.

The attached patch is a quick fix for this. Better would be to not write
the blocks to the tape at all and to try to reserve the blocks without writing
on restore. (I think this will depend on blocksize on the restore FS and
whether this is supported at all)

I do intend to rework this so that the empty blocks aren't written to
the tape but I recently switched to ext4 from ext3 and was getting
corrupted backups that I needed to fix quickly.

-- System Information:
Debian Release: 12.7
  APT prefers stable-security
  APT policy: (500, 'stable-security'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 6.1.0-25-amd64 (SMP w/4 CPU threads; PREEMPT)
Kernel taint flags: TAINT_WARN
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: sysvinit (via /sbin/init)

Versions of packages dump depends on:
ii  libblkid1     2.38.1-5+deb12u1
ii  libbz2-1.0    1.0.8-5+b1
ii  libc6         2.36-9+deb12u8
ii  libcom-err2   1.47.0-2
ii  libext2fs2    1.47.0-2
ii  liblzo2-2     2.10-2
ii  libreadline8  8.2-1.3
ii  libselinux1   3.4-1+b6
ii  tar           1.34+dfsg-1.2+deb12u1
ii  zlib1g        1:1.2.13.dfsg-1

dump recommends no packages.

dump suggests no packages.

-- no debconf information
diff -urN dump-0.4b47.orig/common/slave.h dump-0.4b47/common/slave.h
--- dump-0.4b47.orig/common/slave.h     2021-01-01 15:05:15.000000000 +0000
+++ dump-0.4b47/common/slave.h  2021-01-01 15:05:15.000000000 +0000
@@ -17,6 +17,7 @@
 struct req {
        ext2_loff_t dblk;
        int count;
+       int uninit;
 };
 
 #define SLAVES 3               /* 1 slave writing, 1 reading, 1 for slack */
diff -urN dump-0.4b47.orig/dump/dump.h dump-0.4b47/dump/dump.h
--- dump-0.4b47.orig/dump/dump.h        2022-05-03 10:02:27.000000000 +0000
+++ dump-0.4b47/dump/dump.h     2022-05-03 10:02:27.000000000 +0000
@@ -140,7 +140,7 @@
 int    mapdirs (dump_ino_t maxino, long long *tapesize);
 
 /* file dumping routines */
-void   blksout (blk64_t *blkp, int frags, dump_ino_t ino);
+void   blksout (blk64_t *blkp, int frags, dump_ino_t ino, int uninit);
 void   bread (ext2_loff_t blkno, char *buf, size_t size);
 void   dumpino (struct dinode *dp, dump_ino_t ino, int metaonly);
 #ifdef __linux__
@@ -153,7 +153,7 @@
 /* tape writing routines */
 int    alloctape (void);
 void   close_rewind (void);
-void   dumpblock (blk64_t blkno, int size);
+void   dumpblock (blk64_t blkno, int size, int uninit);
 void   startnewtape (int top);
 time_t trewind (void);
 void   writerec (const void *dp, int isspcl);
diff -urN dump-0.4b47.orig/dump/tape.c dump-0.4b47/dump/tape.c
--- dump-0.4b47.orig/dump/tape.c        2022-05-03 10:02:27.000000000 +0000
+++ dump-0.4b47/dump/tape.c     2022-05-03 10:02:27.000000000 +0000
@@ -238,6 +238,7 @@
 {
        slp->req[trecno].dblk = (ext2_loff_t)0;
        slp->req[trecno].count = 1;
+       slp->req[trecno].uninit = 0;
        /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
        *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
 
@@ -254,7 +255,7 @@
 }
 
 void
-dumpblock(blk64_t blkno, int size)
+dumpblock(blk64_t blkno, int size, int uninit)
 {
        int avail, tpblks;
        ext2_loff_t dblkno;
@@ -264,6 +265,7 @@
        while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
                slp->req[trecno].dblk = dblkno;
                slp->req[trecno].count = avail;
+               slp->req[trecno].uninit = uninit;
                trecno += avail;
                spcl.c_tapea += avail;
                if (trecno >= ntrec)
@@ -1220,8 +1222,12 @@
                     trecno += p->count, p += p->count) {
 
                        if (p->dblk) {  /* read a disk block */
-                               bread(p->dblk, slp->tblock[trecno],
-                                       p->count * TP_BSIZE);
+                               if(p->uninit) {
+                                       memset(slp->tblock[trecno], 0, p->count 
* TP_BSIZE);
+                               } else {
+                                       bread(p->dblk, slp->tblock[trecno],
+                                               p->count * TP_BSIZE);
+                               }
                        } else {        /* read record from pipe */
                                if (p->count != 1 || dump_atomic_read( cmd,
                                    (char *)slp->tblock[trecno],
diff -urN dump-0.4b47.orig/dump/traverse.c dump-0.4b47/dump/traverse.c
--- dump-0.4b47.orig/dump/traverse.c    2021-01-01 16:28:57.000000000 +0000
+++ dump-0.4b47/dump/traverse.c 2021-01-01 16:28:57.000000000 +0000
@@ -752,6 +752,7 @@
        int     cnt;
        int     max;
        int     next_block;
+       int     uninit;
 };
 
 /*
@@ -768,13 +769,13 @@
        for (i = p->next_block; i < blockcnt; i++) {
                p->buf[p->cnt++] = 0;
                if (p->cnt == p->max) {
-                       blksout (p->buf, p->cnt, p->ino);
+                       blksout (p->buf, p->cnt, p->ino, p->uninit);
                        p->cnt = 0;
                }
        }
        p->buf[p->cnt++] = *blocknr;
        if (p->cnt == p->max) {
-               blksout (p->buf, p->cnt, p->ino);
+               blksout (p->buf, p->cnt, p->ino, p->uninit);
                p->cnt = 0;
        }
        p->next_block = blockcnt + 1;
@@ -840,12 +841,56 @@
                spcl.c_dinode.di_size = sblock->fs_bsize;
                spcl.c_flags |= DR_EXTATTRIBUTES;
                spcl.c_extattributes = EXT_XATTR;
-               blksout((blk64_t *)&dp->di_file_acl, 
EXT2_FRAGS_PER_BLOCK(fs->super), ino);
+               blksout((blk64_t *)&dp->di_file_acl, 
EXT2_FRAGS_PER_BLOCK(fs->super), ino, 0);
                spcl.c_flags &= ~DR_EXTATTRIBUTES;
                spcl.c_extattributes = 0;
        }
 }
 
+#ifdef __linux__
+/* TODO - see bread for how dump deals with errors */
+static void iterate_extents(struct block_context* bc, ext2_filsys fs, 
ext2_ino_t ino) {
+       ext2_extent_handle_t handle = NULL;
+       struct ext2fs_extent extent;
+       int op = EXT2_EXTENT_ROOT;
+       errcode_t errcode;
+       int ret = 0;
+
+       errcode = ext2fs_extent_open(fs, ino, &handle);
+       if (errcode) {
+               msg("failed to open ext2 inode %u: %s\n", ino, 
error_message(errcode));
+               return;
+       }
+       while (1) {
+
+               errcode = ext2fs_extent_get(handle, op, &extent);
+               if (errcode == EXT2_ET_EXTENT_NO_NEXT)
+                       break;
+               if (errcode) {
+                       msg("failed to get extents inode %u: %s\n", ino, 
error_message(errcode));
+                       goto out;
+               }
+               op = EXT2_EXTENT_NEXT;
+
+               if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) {
+                       continue;
+               }
+               if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
+                       continue;
+               }
+
+               bc->uninit = extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? 1 : 0;
+               blk64_t start = extent.e_pblk;
+               e2_blkcnt_t blockcnt = extent.e_lblk;
+               for(blk64_t blocknr = start; blocknr < start + extent.e_len; 
++blocknr, ++blockcnt) {
+                       dumponeblock(fs, &blocknr, blockcnt, 0, 0, bc);
+               }
+       }
+out:
+       ext2fs_extent_free(handle);
+}
+#endif
+
 /*
  * Dump passes 3 and 4.
  *
@@ -982,21 +1027,29 @@
        bc.cnt = 0;
        bc.ino = ino;
        bc.next_block = 0;
+       bc.uninit = 0;
 
-       ext2fs_block_iterate3(fs, (ext2_ino_t)ino, BLOCK_FLAG_DATA_ONLY, NULL, 
dumponeblock, (void *)&bc);
+       if (dp->di_mode & S_IFREG && dp->di_flags & EXT4_EXTENTS_FL) {
+               iterate_extents(&bc, fs, (ext2_ino_t)ino);
+       } else if (dp->di_mode & S_IFREG && dp->di_flags & EXT4_INLINE_DATA_FL) 
{
+               /* Untested - Can we ever get here? */
+               msg("Unexpectedly got EXT4_INLINE_DATA_FL while dumping inode 
%lu\n", ino);
+       } else {
+               ext2fs_block_iterate3(fs, (ext2_ino_t)ino, 
BLOCK_FLAG_DATA_ONLY, NULL, dumponeblock, (void *)&bc);
+       }
        /* deal with holes at the end of the inode */
        if (i_size > ((uint64_t)bc.next_block) * sblock->fs_fsize) {
                remaining = i_size - ((uint64_t)bc.next_block) * 
sblock->fs_fsize;
                for (i = 0; i < (int)howmany(remaining, sblock->fs_fsize); i++) 
{
                        bc.buf[bc.cnt++] = 0;
                        if (bc.cnt == bc.max) {
-                               blksout (bc.buf, bc.cnt, bc.ino);
+                               blksout (bc.buf, bc.cnt, bc.ino, bc.uninit);
                                bc.cnt = 0;
                        }
                }
        }
        if (bc.cnt > 0) {
-               blksout (bc.buf, bc.cnt, bc.ino);
+               blksout (bc.buf, bc.cnt, bc.ino, bc.uninit);
        }
        free(bc.buf);
        dump_xattr(ino, dp);
@@ -1005,7 +1058,7 @@
                cnt = NDADDR * sblock->fs_frag;
        else
                cnt = howmany(i_size, sblock->fs_fsize);
-       blksout(&dp->di_db[0], cnt, ino);
+       blksout(&dp->di_db[0], cnt, ino, 0);
        if ((int64_t) (size = i_size - NDADDR * sblock->fs_bsize) <= 0) {
                dump_xattr(ino, dp);
                return;
@@ -1245,7 +1298,7 @@
                        cnt = NINDIR(sblock) * sblock->fs_frag;
 #endif
                *size -= NINDIR(sblock) * sblock->fs_bsize;
-               blksout(&idblk[0], cnt, ino);
+               blksout(&idblk[0], cnt, ino, 0);
                return;
        }
        ind_level--;
@@ -1261,7 +1314,7 @@
  * Collect up the data into tape record sized buffers and output them.
  */
 void
-blksout(blk64_t *blkp, int frags, dump_ino_t ino)
+blksout(blk64_t *blkp, int frags, dump_ino_t ino, int uninit)
 {
        blk64_t *bp;
        int i, j, count, blks, tbperdb;
@@ -1284,9 +1337,9 @@
                for (j = i; j < count; j += tbperdb, bp++) {
                        if (*bp != 0) {
                                if (j + tbperdb <= count)
-                                       dumpblock(*bp, (int)sblock->fs_bsize);
+                                       dumpblock(*bp, (int)sblock->fs_bsize, 
uninit);
                                else
-                                       dumpblock(*bp, (count - j) * TP_BSIZE);
+                                       dumpblock(*bp, (count - j) * TP_BSIZE, 
uninit);
                        }
                }
                spcl.c_type = TS_ADDR;

Reply via email to