Annotation of embedaddon/rsync/patches/checksum-xattr.diff, revision 1.1.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>