Annotation of embedaddon/rsync/patches/checksum-xattr.diff, revision 1.1

1.1     ! misho       1: This patch is the start of storing/using checksum information from
        !             2: extended attribute values.  The rsync code only reads the values
        !             3: at the moment.  There is also a perl script that can create them.
        !             4: 
        !             5: To use this patch, run these commands for a successful build:
        !             6: 
        !             7:     patch -p1 <patches/checksum-xattr.diff
        !             8:     ./configure                               (optional if already run)
        !             9:     make
        !            10: 
        !            11: based-on: e94bad1c156fc3910f24e2b3b71a81b0b0bdeb70
        !            12: diff --git a/flist.c b/flist.c
        !            13: --- a/flist.c
        !            14: +++ b/flist.c
        !            15: @@ -1368,7 +1368,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
        !            16:  #endif
        !            17:  
        !            18:        if (always_checksum && am_sender && S_ISREG(st.st_mode)) {
        !            19: -              file_checksum(thisname, &st, tmp_sum);
        !            20: +              if (!get_sum_xattr(thisname, &st, tmp_sum))
        !            21: +                      file_checksum(thisname, &st, tmp_sum);
        !            22:                if (sender_keeps_checksum)
        !            23:                        extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
        !            24:        }
        !            25: diff --git a/generator.c b/generator.c
        !            26: --- a/generator.c
        !            27: +++ b/generator.c
        !            28: @@ -610,7 +610,8 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
        !            29:           of the file time to determine whether to sync */
        !            30:        if (always_checksum > 0 && S_ISREG(st->st_mode)) {
        !            31:                char sum[MAX_DIGEST_LEN];
        !            32: -              file_checksum(fn, st, sum);
        !            33: +              if (!get_sum_xattr(fn, st, sum))
        !            34: +                      file_checksum(fn, st, sum);
        !            35:                return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
        !            36:        }
        !            37:  
        !            38: diff --git a/support/xsums b/support/xsums
        !            39: new file mode 100755
        !            40: --- /dev/null
        !            41: +++ b/support/xsums
        !            42: @@ -0,0 +1,204 @@
        !            43: +#!/usr/bin/perl -w
        !            44: +use strict;
        !            45: +
        !            46: +use Getopt::Long;
        !            47: +use Cwd qw(abs_path cwd);
        !            48: +use Digest::MD4;
        !            49: +use Digest::MD5;
        !            50: +use File::ExtAttr ':all';
        !            51: +
        !            52: +&Getopt::Long::Configure('bundling');
        !            53: +&usage if !&GetOptions(
        !            54: +    'recurse|r' => \( my $recurse_opt ),
        !            55: +    'list|l' => \( my $list_opt ),
        !            56: +    'check|c' => \( my $check_opt ),
        !            57: +    'verbose|v+' => \( my $verbosity = 0 ),
        !            58: +    'help|h' => \( my $help_opt ),
        !            59: +);
        !            60: +&usage if $help_opt;
        !            61: +
        !            62: +my $start_dir = cwd();
        !            63: +
        !            64: +my @dirs = @ARGV;
        !            65: +@dirs = '.' unless @dirs;
        !            66: +foreach (@dirs) {
        !            67: +    $_ = abs_path($_);
        !            68: +}
        !            69: +
        !            70: +$| = 1;
        !            71: +
        !            72: +my $exit_code = 0;
        !            73: +
        !            74: +my $md4 = Digest::MD4->new;
        !            75: +my $md5 = Digest::MD5->new;
        !            76: +
        !            77: +while (@dirs) {
        !            78: +    my $dir = shift @dirs;
        !            79: +
        !            80: +    if (!chdir($dir)) {
        !            81: +      warn "Unable to chdir to $dir: $!\n";
        !            82: +      next;
        !            83: +    }
        !            84: +    if (!opendir(DP, '.')) {
        !            85: +      warn "Unable to opendir $dir: $!\n";
        !            86: +      next;
        !            87: +    }
        !            88: +
        !            89: +    my $reldir = $dir;
        !            90: +    $reldir =~ s#^$start_dir(/|$)# $1 ? '' : '.' #eo;
        !            91: +    print "$reldir ... " if $verbosity;
        !            92: +
        !            93: +    my @subdirs;
        !            94: +    my $d_cnt = 0;
        !            95: +    my $need_newline = $verbosity;
        !            96: +    while (defined(my $fn = readdir(DP))) {
        !            97: +      next if $fn =~ /^\.\.?$/ || -l $fn;
        !            98: +      if (-d _) {
        !            99: +          push(@subdirs, "$dir/$fn");
        !           100: +          next;
        !           101: +      }
        !           102: +      next unless -f _;
        !           103: +      $d_cnt++;
        !           104: +
        !           105: +      my($size,$mtime,$ctime) = (stat(_))[7,9,10];
        !           106: +
        !           107: +      my $xsum4 = getfattr($fn, 'rsync.%md4');
        !           108: +      my $xsum5 = getfattr($fn, 'rsync.%md5');
        !           109: +
        !           110: +      my $sum_count = 0;
        !           111: +      foreach ($xsum4, $xsum5) {
        !           112: +          if (defined $_) {
        !           113: +              if (length($_) == 24) {
        !           114: +                  my($sz,$mt,$sum) = unpack('V2a16', $_);
        !           115: +                  if ($sz != ($size & 0xFFFFFFFF)
        !           116: +                   || $mt != ($mtime & 0xFFFFFFFF)) {
        !           117: +                      $_ = undef;
        !           118: +                  } else {
        !           119: +                      $_ = $sum;
        !           120: +                      $sum_count++;
        !           121: +                  }
        !           122: +              } else {
        !           123: +                  $_ = undef;
        !           124: +              }
        !           125: +          }
        !           126: +      }
        !           127: +
        !           128: +      if ($list_opt) {
        !           129: +          if ($need_newline) {
        !           130: +              print "\n";
        !           131: +              $need_newline = 0;
        !           132: +          }
        !           133: +          if (defined $xsum4) {
        !           134: +              print ' ', unpack('H32', $xsum4);
        !           135: +          } else {
        !           136: +              print ' ' x (1 + 32);
        !           137: +          }
        !           138: +          if (defined $xsum5) {
        !           139: +              print ' ', unpack('H32', $xsum5);
        !           140: +          } else {
        !           141: +              print ' ' x (1 + 32);
        !           142: +          }
        !           143: +          print $verbosity ? ' ' : " $reldir/";
        !           144: +          print $fn, "\n";
        !           145: +          next;
        !           146: +      }
        !           147: +
        !           148: +      if ($check_opt) {
        !           149: +          if (!$sum_count) {
        !           150: +              if ($need_newline) {
        !           151: +                  print "\n";
        !           152: +                  $need_newline = 0;
        !           153: +              }
        !           154: +              print ' ' x (1 + 32 + 1 + 32) if $verbosity > 2;
        !           155: +              print $verbosity ? ' ' : "$reldir/";
        !           156: +              print $fn, " MISSING\n";
        !           157: +              next;
        !           158: +          }
        !           159: +      } else {
        !           160: +          next if $sum_count == 2;
        !           161: +          print 'UPDATING' if $need_newline && $verbosity == 1;
        !           162: +      }
        !           163: +
        !           164: +      if ($need_newline && (!$check_opt || $verbosity > 1)) {
        !           165: +          print "\n";
        !           166: +          $need_newline = 0;
        !           167: +      }
        !           168: +
        !           169: +      if (!open(IN, $fn)) {
        !           170: +          print STDERR "Unable to read $fn: $!\n";
        !           171: +          next;
        !           172: +      }
        !           173: +
        !           174: +      my($sum4, $sum5);
        !           175: +      while (1) {
        !           176: +          while (sysread(IN, $_, 64*1024)) {
        !           177: +              $md4->add($_);
        !           178: +              $md5->add($_);
        !           179: +          }
        !           180: +          $sum4 = $md4->digest;
        !           181: +          $sum5 = $md5->digest;
        !           182: +          print ' ', unpack('H32', $sum4), ' ', unpack('H32', $sum5) if $verbosity > 2;
        !           183: +          print " $fn" if $verbosity > 1;
        !           184: +          my($size2,$mtime2,$ctime2) = (stat(IN))[7,9,10];
        !           185: +          last if $size == $size2 && $mtime == $mtime2 && $ctime == $ctime2;
        !           186: +          $size = $size2;
        !           187: +          $mtime = $mtime2;
        !           188: +          $ctime = $ctime2;
        !           189: +          sysseek(IN, 0, 0);
        !           190: +          print " REREADING\n" if $verbosity > 1;
        !           191: +      }
        !           192: +
        !           193: +      close IN;
        !           194: +
        !           195: +      if ($check_opt) {
        !           196: +          if ((!defined $xsum4 || $xsum4 eq $sum4) && (!defined $xsum5 || $xsum5 eq $sum5)) {
        !           197: +              print " OK\n" if $verbosity > 1;
        !           198: +              next;
        !           199: +          }
        !           200: +          if ($need_newline) {
        !           201: +              print "\n";
        !           202: +              $need_newline = 0;
        !           203: +          }
        !           204: +          if ($verbosity < 2) {
        !           205: +              print $verbosity ? ' ' : "$reldir/";
        !           206: +              print $fn;
        !           207: +          }
        !           208: +          print " FAILED\n";
        !           209: +          $exit_code = 1;
        !           210: +      } else {
        !           211: +          print "\n" if $verbosity > 1;
        !           212: +          my $szmt = pack('V2', $size, $mtime); # 32-bits, may truncate
        !           213: +          setfattr($fn, 'rsync.%md4', $szmt.$sum4);
        !           214: +          setfattr($fn, 'rsync.%md5', $szmt.$sum5);
        !           215: +          #utime $mtime, $mtime, $fn; # Set mtime if it changes.
        !           216: +      }
        !           217: +    }
        !           218: +
        !           219: +    if ($need_newline) {
        !           220: +      if ($d_cnt) {
        !           221: +          print "ok\n";
        !           222: +      } else {
        !           223: +          print "empty\n";
        !           224: +      }
        !           225: +    }
        !           226: +
        !           227: +    closedir DP;
        !           228: +
        !           229: +    unshift(@dirs, sort @subdirs) if $recurse_opt;
        !           230: +}
        !           231: +
        !           232: +exit $exit_code;
        !           233: +
        !           234: +sub usage
        !           235: +{
        !           236: +    die <<EOT;
        !           237: +Usage: rsyncsums [OPTIONS] [DIRS]
        !           238: +
        !           239: +Options:
        !           240: + -r, --recurse     Update checksums in subdirectories too.
        !           241: + -l, --list        List the checksums for each file (doesn't update).
        !           242: + -c, --check       Check if the checksums are right (doesn't update).
        !           243: + -v, --verbose     Mention what we're doing.  Repeat for more info.
        !           244: + -h, --help        Display this help message.
        !           245: +EOT
        !           246: +}
        !           247: diff --git a/xattrs.c b/xattrs.c
        !           248: --- a/xattrs.c
        !           249: +++ b/xattrs.c
        !           250: @@ -36,7 +36,9 @@ extern int preserve_xattrs;
        !           251:  extern int preserve_links;
        !           252:  extern int preserve_devices;
        !           253:  extern int preserve_specials;
        !           254: +extern int checksum_type;
        !           255:  extern int checksum_seed;
        !           256: +extern int flist_csum_len;
        !           257:  extern int saw_xattr_filter;
        !           258:  
        !           259:  #define RSYNC_XAL_INITIAL 5
        !           260: @@ -72,6 +74,10 @@ extern int saw_xattr_filter;
        !           261:  #define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
        !           262:  #define XDEF_ACL_SUFFIX "dacl"
        !           263:  #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
        !           264: +#define MD4_SUFFIX "md4"
        !           265: +#define MD4_ATTR RSYNC_PREFIX "%" MD4_SUFFIX
        !           266: +#define MD5_SUFFIX "md5"
        !           267: +#define MD5_ATTR RSYNC_PREFIX "%" MD5_SUFFIX
        !           268:  
        !           269:  typedef struct {
        !           270:        char *datum, *name;
        !           271: @@ -259,7 +265,9 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
        !           272:                         || (am_root < 0
        !           273:                          && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
        !           274:                           || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
        !           275: -                         || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
        !           276: +                         || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0
        !           277: +                         || strcmp(name+RPRE_LEN+1, MD4_SUFFIX) == 0
        !           278: +                         || strcmp(name+RPRE_LEN+1, MD5_SUFFIX) == 0)))
        !           279:                                continue;
        !           280:                }
        !           281:  
        !           282: @@ -1116,6 +1124,38 @@ int del_def_xattr_acl(const char *fname)
        !           283:  }
        !           284:  #endif
        !           285:  
        !           286: +int get_sum_xattr(const char *fname, STRUCT_STAT *stp, char *sum)
        !           287: +{
        !           288: +      const char *mdattr = checksum_type == 5 ? MD5_ATTR : MD4_ATTR;
        !           289: +      char buf[256];
        !           290: +      uint32 file_length, mtime;
        !           291: +      int len;
        !           292: +
        !           293: +      len = sys_lgetxattr(fname, mdattr, buf, sizeof buf);
        !           294: +      if (len < 0) {
        !           295: +              if (errno == ENOTSUP || errno == ENOATTR)
        !           296: +                      return 0;
        !           297: +              rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
        !           298: +                      mdattr, full_fname(fname));
        !           299: +              return 0;
        !           300: +      }
        !           301: +      if (len != 4 + 4 + flist_csum_len) {
        !           302: +              rprintf(FERROR, "Corrupt %s xattr attached to %s -- skipping\n",
        !           303: +                      mdattr, full_fname(fname));
        !           304: +              return 0;
        !           305: +      }
        !           306: +
        !           307: +      file_length = IVAL(buf, 0); /* 32-bit values -- trunctions are OK */
        !           308: +      mtime = IVAL(buf, 4);
        !           309: +
        !           310: +      if ((uint32)stp->st_size != file_length || (uint32)stp->st_mtime != mtime)
        !           311: +              return 0;
        !           312: +
        !           313: +      memcpy(sum, buf + 8, flist_csum_len);
        !           314: +
        !           315: +      return 1;
        !           316: +}
        !           317: +
        !           318:  int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
        !           319:  {
        !           320:        int mode, rdev_major, rdev_minor, uid, gid, len;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>