Fixed compilation errors/warnings.
[rsync/rsync-patches.git] / link-by-hash.diff
index 52557c0..b6b7802 100644 (file)
@@ -1,44 +1,50 @@
-To: rsync@lists.samba.org
-From: "Jason M. Felice" <jfelice@cronosys.com>
-Subject: [patch] Add `--link-by-hash' option (rev 5).
-Date: Mon, 23 Feb 2004 13:29:08 -0500
+Jason M. Felice wrote:
 
 This patch adds the --link-by-hash=DIR option, which hard links received
 files in a link farm arranged by MD4 file hash.  The result is that the system
 will only store one copy of the unique contents of each file, regardless of
 the file's name.
 
 
 This patch adds the --link-by-hash=DIR option, which hard links received
 files in a link farm arranged by MD4 file hash.  The result is that the system
 will only store one copy of the unique contents of each file, regardless of
 the file's name.
 
-(rev 5)
-* Fixed silly logic error.
+To use this patch, run these commands for a successful build:
 
 
-(rev 4)
-* Updated for committed robust_rename() patch, other changes in CVS.
+    patch -p1 <patches/link-by-hash.diff
+    ./prepare-source
+    ./configure
+    make
 
 
-(rev 3)
-* Don't link empty files.
-* Roll over to new file when filesystem maximum link count is reached.
-* If link fails for another reason, leave non-linked file there.
-* Depends on rsync-rename.diff
-
-(rev 2)
-* This revision is actually against CVS HEAD (I didn't realize I was working
-  from a stale rsync'd CVS).
-* Apply permissions after linking (permissions were lost if we already had
-  a copy of the file in the link farm).
-
-Patch Summary:
-
-    -1   +1    Makefile.in
-    -0   +351  hashlink.c (new)
-    -1   +22   options.c
-    -0   +6    proto.h
-    -6   +21   receiver.c
-    -2   +8    rsync.c
-    -0   +8    rsync.h
-
---- hashlink.c 1969-12-31 19:00:00.000000000 -0500
-+++ hashlink.c 2004-02-23 10:30:45.000000000 -0500
-@@ -0,0 +1,351 @@
+--- old/Makefile.in
++++ new/Makefile.in
+@@ -35,7 +35,7 @@ OBJS1=flist.o rsync.o generator.o receiv
+       util.o main.o checksum.o match.o syscall.o log.o backup.o
+ OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
+       fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
+-OBJS3=progress.o pipe.o
++OBJS3=progress.o pipe.o hashlink.o
+ DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
+ popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
+       popt/popthelp.o popt/poptparse.o
+--- old/flist.c
++++ new/flist.c
+@@ -65,6 +65,7 @@ extern int protocol_version;
+ extern int sanitize_paths;
+ extern struct stats stats;
+ extern char *filesfrom_host;
++extern char *link_by_hash_dir;
+ extern char curr_dir[MAXPATHLEN];
+@@ -830,7 +831,7 @@ static struct file_struct *recv_file_ent
+               extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
+ #endif
+-      if (always_checksum && S_ISREG(mode))
++      if ((always_checksum || link_by_hash_dir) && S_ISREG(mode))
+               extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
+       if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
+--- old/hashlink.c
++++ new/hashlink.c
+@@ -0,0 +1,336 @@
 +/*
 +   Copyright (C) Cronosys, LLC 2004
 +
 +/*
 +   Copyright (C) Cronosys, LLC 2004
 +
@@ -65,14 +71,12 @@ Patch Summary:
 +
 +#ifdef HAVE_LINK
 +
 +
 +#ifdef HAVE_LINK
 +
-+charmake_hash_name(struct file_struct *file)
++char *make_hash_name(struct file_struct *file)
 +{
 +      char hash[33], *dst;
 +{
 +      char hash[33], *dst;
-+      unsigned char *src;
-+      unsigned char c;
++      uchar c, *src = (uchar*)F_SUM(file);
 +      int i;
 +
 +      int i;
 +
-+      src = (unsigned char*)file->u.sum;
 +      for (dst = hash, i = 0; i < 4; i++, src++) {
 +              c = *src >> 4;
 +              *(dst++) = (c >= 10) ? (c - 10 + 'a') : (c + '0');
 +      for (dst = hash, i = 0; i < 4; i++, src++) {
 +              c = *src >> 4;
 +              *(dst++) = (c >= 10) ? (c - 10 + 'a') : (c + '0');
@@ -125,12 +129,11 @@ Patch Summary:
 +      long this_fnbr;
 +
 +      *fnbr = 0;
 +      long this_fnbr;
 +
 +      *fnbr = 0;
-+      
++
 +      /* Build a list of potential candidates and open
 +       * them. */
 +      if ((d = opendir(hashname)) == NULL) {
 +      /* Build a list of potential candidates and open
 +       * them. */
 +      if ((d = opendir(hashname)) == NULL) {
-+              rprintf(FERROR,"opendir \"%s\": %s\n",
-+                      hashname, strerror(errno));
++              rsyserr(FERROR, errno, "opendir failed: \"%s\"", hashname);
 +              free(hashname);
 +              return NULL;
 +      }
 +              free(hashname);
 +              return NULL;
 +      }
@@ -145,12 +148,11 @@ Patch Summary:
 +              if (this_fnbr > *fnbr)
 +                      *fnbr = this_fnbr;
 +
 +              if (this_fnbr > *fnbr)
 +                      *fnbr = this_fnbr;
 +
-+              hashfile = (struct hashfile_struct*)malloc(sizeof(struct hashfile_struct));
++              hashfile = new_array(struct hashfile_struct, 1);
 +              asprintf(&hashfile->name,"%s/%s",hashname,
 +                       di->d_name);
 +              if (do_stat(hashfile->name,&st) == -1) {
 +              asprintf(&hashfile->name,"%s/%s",hashname,
 +                       di->d_name);
 +              if (do_stat(hashfile->name,&st) == -1) {
-+                      rprintf(FERROR,"%s: %s", hashfile->name,
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "stat failed: %s", hashfile->name);
 +                      kill_hashfile(hashfile);
 +                      continue;
 +              }
 +                      kill_hashfile(hashfile);
 +                      continue;
 +              }
@@ -161,8 +163,7 @@ Patch Summary:
 +              hashfile->nlink = st.st_nlink;
 +              hashfile->fd = open(hashfile->name,O_RDONLY|O_BINARY);
 +              if (hashfile->fd == -1) {
 +              hashfile->nlink = st.st_nlink;
 +              hashfile->fd = open(hashfile->name,O_RDONLY|O_BINARY);
 +              if (hashfile->fd == -1) {
-+                      rprintf(FERROR,"%s: %s\n", hashfile->name,
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "open failed: %s", hashfile->name);
 +                      kill_hashfile(hashfile);
 +                      continue;
 +              }
 +                      kill_hashfile(hashfile);
 +                      continue;
 +              }
@@ -227,11 +228,10 @@ Patch Summary:
 +                      /* There are no matches. */
 +                      return NULL;
 +              }
 +                      /* There are no matches. */
 +                      return NULL;
 +              }
-+              
 +      }
 +
 +      if (amt == -1) {
 +      }
 +
 +      if (amt == -1) {
-+              rprintf(FERROR,"%s",strerror(errno));
++              rsyserr(FERROR, errno, "read failed in compare_hashfiles()");
 +              kill_hashfiles(files);
 +              return NULL;
 +      }
 +              kill_hashfiles(files);
 +              return NULL;
 +      }
@@ -264,17 +264,16 @@ Patch Summary:
 +}
 +
 +
 +}
 +
 +
-+int link_by_hash(char *fnametmp,char *fname,struct file_struct *file)
++int link_by_hash(const char *fnametmp, const char *fname, struct file_struct *file)
 +{
 +      STRUCT_STAT st;
 +{
 +      STRUCT_STAT st;
-+      char *hashname = make_hash_name(file);          
++      char *hashname = make_hash_name(file);
 +      int first = 0, rc;
 +      char *linkname;
 +      long last_fnbr;
 +
 +      int first = 0, rc;
 +      char *linkname;
 +      long last_fnbr;
 +
-+      if (file->length == 0) {
-+              return robust_rename(fnametmp,fname,0644);
-+      }
++      if (F_LENGTH(file) == 0)
++              return robust_rename(fnametmp, fname, NULL, 0644);
 +
 +      if (do_stat(hashname, &st) == -1) {
 +              char *dirname;
 +
 +      if (do_stat(hashname, &st) == -1) {
 +              char *dirname;
@@ -283,31 +282,27 @@ Patch Summary:
 +              dirname = strdup(hashname);
 +              *strrchr(dirname,'/') = 0;
 +              if (do_mkdir(dirname, 0755) == -1 && errno != EEXIST) {
 +              dirname = strdup(hashname);
 +              *strrchr(dirname,'/') = 0;
 +              if (do_mkdir(dirname, 0755) == -1 && errno != EEXIST) {
-+                      rprintf(FERROR, "mkdir %s: %s\n", dirname,
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "mkdir failed: %s", dirname);
 +                      free(hashname);
 +                      free(dirname);
 +                      free(hashname);
 +                      free(dirname);
-+                      return robust_rename(fnametmp,fname,0644);
++                      return robust_rename(fnametmp, fname, NULL, 0644);
 +              }
 +              free(dirname);
 +
 +              if (do_mkdir(hashname, 0755) == -1 && errno != EEXIST) {
 +              }
 +              free(dirname);
 +
 +              if (do_mkdir(hashname, 0755) == -1 && errno != EEXIST) {
-+                      rprintf(FERROR, "mkdir %s: %s\n", hashname,
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "mkdir failed: %s", hashname);
 +                      free(hashname);
 +                      free(hashname);
-+                      return robust_rename(fnametmp,fname,0644);
++                      return robust_rename(fnametmp, fname, NULL, 0644);
 +              }
 +
 +              first = 1;
 +              asprintf(&linkname,"%s/0",hashname);
 +              rprintf(FINFO, "(1) linkname = %s\n", linkname);
 +              }
 +
 +              first = 1;
 +              asprintf(&linkname,"%s/0",hashname);
 +              rprintf(FINFO, "(1) linkname = %s\n", linkname);
-+                      
 +      } else {
 +              struct hashfile_struct *hashfiles, *hashfile;
 +      } else {
 +              struct hashfile_struct *hashfiles, *hashfile;
-+              int fd;
 +
 +              if (do_stat(fnametmp,&st) == -1) {
 +
 +              if (do_stat(fnametmp,&st) == -1) {
-+                      rprintf(FERROR,"%s: %s\n",fname,strerror(errno));
++                      rsyserr(FERROR, errno, "stat failed: %s", fname);
 +                      return -1;
 +              }
 +              hashfiles = find_hashfiles(hashname, st.st_size, &last_fnbr);
 +                      return -1;
 +              }
 +              hashfiles = find_hashfiles(hashname, st.st_size, &last_fnbr);
@@ -317,16 +312,16 @@ Patch Summary:
 +                      asprintf(&linkname,"%s/0",hashname);
 +                      rprintf(FINFO, "(2) linkname = %s\n", linkname);
 +              } else {
 +                      asprintf(&linkname,"%s/0",hashname);
 +                      rprintf(FINFO, "(2) linkname = %s\n", linkname);
 +              } else {
-+                      
++                      int fd;
 +                      /* Search for one identical to us. */
 +                      if ((fd = open(fnametmp,O_RDONLY|O_BINARY)) == -1) {
 +                      /* Search for one identical to us. */
 +                      if ((fd = open(fnametmp,O_RDONLY|O_BINARY)) == -1) {
-+                              rprintf(FERROR,"%s: %s\n",fnametmp,
-+                                      strerror(errno));
++                              rsyserr(FERROR, errno, "open failed: %s", fnametmp);
 +                              kill_hashfiles(hashfiles);
 +                              return -1;
 +                      }
 +                      hashfile = compare_hashfiles(fd, hashfiles);
 +                      hashfiles = NULL;
 +                              kill_hashfiles(hashfiles);
 +                              return -1;
 +                      }
 +                      hashfile = compare_hashfiles(fd, hashfiles);
 +                      hashfiles = NULL;
++                      close(fd);
 +
 +                      if (hashfile) {
 +                              first = 0;
 +
 +                      if (hashfile) {
 +                              first = 0;
@@ -345,6 +340,7 @@ Patch Summary:
 +      if (!first) {
 +              rprintf(FINFO, "link-by-hash (existing): \"%s\" -> %s\n",
 +                              linkname, full_fname(fname));
 +      if (!first) {
 +              rprintf(FINFO, "link-by-hash (existing): \"%s\" -> %s\n",
 +                              linkname, full_fname(fname));
++              robust_unlink(fname);
 +              rc = do_link(linkname, fname);
 +              if (rc == -1) {
 +                      if (errno == EMLINK) {
 +              rc = do_link(linkname, fname);
 +              if (rc == -1) {
 +                      if (errno == EMLINK) {
@@ -355,11 +351,9 @@ Patch Summary:
 +                              rprintf(FINFO, "(5) linkname = %s\n", linkname);
 +                              rprintf(FINFO,"link-by-hash: max link count exceeded, starting new file \"%s\".\n", linkname);
 +                      } else {
 +                              rprintf(FINFO, "(5) linkname = %s\n", linkname);
 +                              rprintf(FINFO,"link-by-hash: max link count exceeded, starting new file \"%s\".\n", linkname);
 +                      } else {
-+                              rprintf(FERROR,"link \"%s\" -> %s: %s\n",
-+                                      linkname,full_fname(fname),
-+                                      strerror(errno));
-+                              robust_unlink(fname);
-+                              rc = robust_rename(fnametmp,fname,0644);
++                              rsyserr(FERROR, errno, "link \"%s\" -> \"%s\"",
++                                      linkname, full_fname(fname));
++                              rc = robust_rename(fnametmp, fname, NULL, 0644);
 +                      }
 +              } else {
 +                      do_unlink(fnametmp);
 +                      }
 +              } else {
 +                      do_unlink(fnametmp);
@@ -370,17 +364,15 @@ Patch Summary:
 +              rprintf(FINFO, "link-by-hash (new): %s -> \"%s\"\n",
 +                              full_fname(fname),linkname);
 +
 +              rprintf(FINFO, "link-by-hash (new): %s -> \"%s\"\n",
 +                              full_fname(fname),linkname);
 +
-+              rc = robust_rename(fnametmp,fname,0644);
++              rc = robust_rename(fnametmp, fname, NULL, 0644);
 +              if (rc != 0) {
 +              if (rc != 0) {
-+                      rprintf(FERROR,"rename \"%s\" -> \"%s\": %s\n",
-+                              full_fname(fnametmp),full_fname(fname),
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "rename \"%s\" -> \"%s\"",
++                              full_fname(fnametmp), full_fname(fname));
 +              }
 +              rc = do_link(fname,linkname);
 +              if (rc != 0) {
 +              }
 +              rc = do_link(fname,linkname);
 +              if (rc != 0) {
-+                      rprintf(FERROR,"link \"%s\" -> \"%s\": %s\n",
-+                              full_fname(fname),linkname,
-+                              strerror(errno));
++                      rsyserr(FERROR, errno, "link \"%s\" -> \"%s\"",
++                              full_fname(fname), linkname);
 +              }
 +      }
 +
 +              }
 +      }
 +
@@ -388,62 +380,52 @@ Patch Summary:
 +      free(hashname);
 +      return rc;
 +}
 +      free(hashname);
 +      return rc;
 +}
-+
 +#endif
 +#endif
---- Makefile.in        10 Feb 2004 17:06:11 -0000      1.98
-+++ Makefile.in        15 Apr 2004 19:18:59 -0000
-@@ -35,7 +35,7 @@ OBJS1=rsync.o generator.o receiver.o cle
-       main.o checksum.o match.o syscall.o log.o backup.o
- OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
-       fileio.o batch.o clientname.o
--OBJS3=progress.o pipe.o
-+OBJS3=progress.o pipe.o hashlink.o
- DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
- popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
-       popt/popthelp.o popt/poptparse.o
---- options.c  14 Apr 2004 23:33:34 -0000      1.146
-+++ options.c  15 Apr 2004 19:19:00 -0000
-@@ -121,6 +121,7 @@ char *log_format = NULL;
- char *password_file = NULL;
- char *rsync_path = RSYNC_PATH;
- char *backup_dir = NULL;
+--- old/options.c
++++ new/options.c
+@@ -153,6 +153,7 @@ char *backup_suffix = NULL;
+ char *tmpdir = NULL;
+ char *partial_dir = NULL;
+ char *basis_dir[MAX_BASIS_DIRS+1];
 +char *link_by_hash_dir = NULL;
 +char *link_by_hash_dir = NULL;
- char backup_dir_buf[MAXPATHLEN];
- int rsync_port = RSYNC_PORT;
- int link_dest = 0;
-@@ -266,6 +267,7 @@ void usage(enum logcode F)
-   rprintf(F," -T  --temp-dir=DIR          create temporary files in directory DIR\n");
+ char *config_file = NULL;
+ char *shell_cmd = NULL;
+ char *logfile_name = NULL;
+@@ -385,6 +386,7 @@ void usage(enum logcode F)
    rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
    rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
-   rprintf(F,"     --link-dest=DIR         create hardlinks to DIR for unchanged files\n");
-+  rprintf(F,"     --link-by-hash=DIR      create hardlinks by hash to DIR for regular files\n");
-   rprintf(F," -P                          equivalent to --partial --progress\n");
-   rprintf(F," -z, --compress              compress file data\n");
-   rprintf(F," -C, --cvs-exclude           auto ignore files in the same way CVS does\n");
-@@ -305,7 +307,7 @@ void usage(enum logcode F)
- enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
-       OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
-       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
--      OPT_READ_BATCH, OPT_WRITE_BATCH,
-+      OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_LINK_BY_HASH,
-       OPT_REFUSED_BASE = 9000};
+   rprintf(F,"     --copy-dest=DIR         ... and include copies of unchanged files\n");
+   rprintf(F,"     --link-dest=DIR         hardlink to files in DIR when unchanged\n");
++  rprintf(F,"     --link-by-hash=DIR      create hardlinks by hash into DIR\n");
+   rprintf(F," -z, --compress              compress file data during the transfer\n");
+   rprintf(F,"     --compress-level=NUM    explicitly set compression level\n");
+   rprintf(F,"     --skip-compress=LIST    skip compressing files with a suffix in LIST\n");
+@@ -437,7 +439,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OP
+       OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
+       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
+       OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
+-      OPT_NO_D, OPT_APPEND,
++      OPT_NO_D, OPT_APPEND, OPT_LINK_BY_HASH,
+       OPT_SERVER, OPT_REFUSED_BASE = 9000};
  
  static struct poptOption long_options[] = {
  
  static struct poptOption long_options[] = {
-@@ -362,6 +364,7 @@ static struct poptOption long_options[] 
-   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
-   {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
-   {"link-dest",        0,  POPT_ARG_STRING, &compare_dest,  OPT_LINK_DEST, 0, 0 },
-+  {"link-by-hash",     0,  POPT_ARG_STRING, 0,              OPT_LINK_BY_HASH, 0, 0},
-   /* TODO: Should this take an optional int giving the compression level? */
-   {"compress",        'z', POPT_ARG_NONE,   &do_compression, 0, 0, 0 },
-   {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
-@@ -584,6 +587,19 @@ int parse_arguments(int *argc, const cha
+@@ -561,6 +563,7 @@ static struct poptOption long_options[] 
+   {"compare-dest",     0,  POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
+   {"copy-dest",        0,  POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
+   {"link-dest",        0,  POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
++  {"link-by-hash",     0,  POPT_ARG_STRING, 0, OPT_LINK_BY_HASH, 0, 0},
+   {"fuzzy",           'y', POPT_ARG_NONE,   &fuzzy_basis, 0, 0, 0 },
+   {"compress",        'z', POPT_ARG_NONE,   0, 'z', 0, 0 },
+   {"no-compress",      0,  POPT_ARG_VAL,    &do_compression, 0, 0, 0 },
+@@ -1219,6 +1222,21 @@ int parse_arguments(int *argc_p, const c
                        return 0;
  #endif
  
 +                case OPT_LINK_BY_HASH:
                        return 0;
  #endif
  
 +                case OPT_LINK_BY_HASH:
-+#if HAVE_LINK
-+                      link_by_hash_dir = (char *)poptGetOptArg(pc);
-+                      checksum_seed = FIXED_CHECKSUM_SEED;
++#ifdef HAVE_LINK
++                      arg = poptGetOptArg(pc);
++                      if (sanitize_paths)
++                              arg = sanitize_path(NULL, arg, NULL, 0, NULL);
++                      link_by_hash_dir = (char *)arg;
 +                      break;
 +#else
 +                      snprintf(err_buf, sizeof err_buf,
 +                      break;
 +#else
 +                      snprintf(err_buf, sizeof err_buf,
@@ -455,164 +437,123 @@ Patch Summary:
 +
                default:
                        /* A large opt value means that set_refuse_options()
 +
                default:
                        /* A large opt value means that set_refuse_options()
-                        * turned this option off (opt-BASE is its index). */
-@@ -951,6 +967,11 @@ void server_options(char **args,int *arg
-                */
-               args[ac++] = link_dest ? "--link-dest" : "--compare-dest";
-               args[ac++] = compare_dest;
-+      }
-+
+                        * turned this option off. */
+@@ -1965,6 +1983,11 @@ void server_options(char **args, int *ar
+       } else if (inplace)
+               args[ac++] = "--inplace";
 +      if (link_by_hash_dir && am_sender) {
 +              args[ac++] = "--link-by-hash";
 +              args[ac++] = link_by_hash_dir;
 +      if (link_by_hash_dir && am_sender) {
 +              args[ac++] = "--link-by-hash";
 +              args[ac++] = link_by_hash_dir;
-       }
-       if (files_from && (!am_sender || remote_filesfrom_file)) {
---- proto.h    14 Apr 2004 23:33:30 -0000      1.188
-+++ proto.h    15 Apr 2004 19:19:00 -0000
-@@ -92,6 +92,12 @@ char *f_name(struct file_struct *f);
- void write_sum_head(int f, struct sum_struct *sum);
- void recv_generator(char *fname, struct file_struct *file, int i, int f_out);
- void generate_files(int f, struct file_list *flist, char *local_name);
-+char* make_hash_name(struct file_struct *file);
-+void kill_hashfile(struct hashfile_struct *hashfile);
-+void kill_hashfiles(struct hashfile_struct *hashfiles);
-+struct hashfile_struct *find_hashfiles(char *hashname, int64 size, long *fnbr);
-+struct hashfile_struct *compare_hashfiles(int fd,struct hashfile_struct *files);
-+int link_by_hash(char *fnametmp,char *fname,struct file_struct *file);
- void init_hard_links(struct file_list *flist);
- int hard_link_check(struct file_struct *file, int skip);
- void do_hard_links(void);
---- receiver.c 23 Mar 2004 16:50:40 -0000      1.75
-+++ receiver.c 15 Apr 2004 19:19:00 -0000
-@@ -45,6 +45,7 @@ extern int cleanup_got_literal;
- extern int module_id;
- extern int ignore_errors;
- extern int orig_umask;
-+extern char *link_by_hash_dir;
- static void delete_one(char *fn, int is_dir)
- {
-@@ -190,10 +191,11 @@ static int get_tmpname(char *fnametmp, c
++      }
++
+       if (files_from && (!am_sender || filesfrom_host)) {
+               if (filesfrom_host) {
+                       args[ac++] = "--files-from";
+--- old/receiver.c
++++ new/receiver.c
+@@ -125,12 +125,14 @@ int get_tmpname(char *fnametmp, char *fn
  
  
  
  
- static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
--                      OFF_T total_size)
-+                      OFF_T total_size,char *md4)
+ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+-                      const char *fname, int fd, OFF_T total_size)
++                      const char *fname, int fd, OFF_T total_size,
++                      const char *md4)
  {
  {
-       int i;
+       static char file_sum1[MAX_DIGEST_LEN];
+       static char file_sum2[MAX_DIGEST_LEN];
+       struct map_struct *mapbuf;
        struct sum_struct sum;
        struct sum_struct sum;
-+      struct mdfour mdfour_data;
-       unsigned int len;
++      md_context mdfour_data;
+       int32 len, sum_len;
        OFF_T offset = 0;
        OFF_T offset2;
        OFF_T offset = 0;
        OFF_T offset2;
-@@ -203,7 +205,9 @@ static int receive_data(int f_in,struct 
-       char *map=NULL;
+@@ -150,6 +152,9 @@ static int receive_data(int f_in, char *
+       } else
+               mapbuf = NULL;
  
  
-       read_sum_head(f_in, &sum);
--
 +      if (md4)
 +              mdfour_begin(&mdfour_data);
 +      if (md4)
 +              mdfour_begin(&mdfour_data);
-+      
-       sum_init();
++
+       sum_init(checksum_seed);
  
  
-       while ((i = recv_token(f_in, &data)) != 0) {
-@@ -220,6 +224,8 @@ static int receive_data(int f_in,struct 
+       if (append_mode > 0) {
+@@ -194,6 +199,8 @@ static int receive_data(int f_in, char *
                        cleanup_got_literal = 1;
  
                        cleanup_got_literal = 1;
  
-                       sum_update(data,i);
+                       sum_update(data, i);
 +                      if (md4)
 +                      if (md4)
-+                              mdfour_update(&mdfour_data,data,i);
++                              mdfour_update(&mdfour_data, (uchar*)data, i);
  
  
-                       if (fd != -1 && write_file(fd,data,i) != i) {
-                               rprintf(FERROR, "write failed on %s: %s\n",
-@@ -247,6 +253,8 @@ static int receive_data(int f_in,struct 
+                       if (fd != -1 && write_file(fd,data,i) != i)
+                               goto report_write_error;
+@@ -220,6 +227,8 @@ static int receive_data(int f_in, char *
  
                        see_token(map, len);
  
                        see_token(map, len);
-                       sum_update(map,len);
+                       sum_update(map, len);
 +                      if (md4)
 +                      if (md4)
-+                              mdfour_update(&mdfour_data,map,len);
++                              mdfour_update(&mdfour_data, (uchar*)map, len);
                }
  
                }
  
-               if (fd != -1 && write_file(fd,map,len) != (int) len) {
-@@ -269,6 +277,8 @@ static int receive_data(int f_in,struct 
+               if (updating_basis) {
+@@ -262,6 +271,8 @@ static int receive_data(int f_in, char *
        }
  
        }
  
-       sum_end(file_sum1);
+       sum_len = sum_end(file_sum1);
 +      if (md4)
 +      if (md4)
-+              mdfour_result(&mdfour_data, (unsigned char*)md4);
++              mdfour_result(&mdfour_data, (uchar*)md4);
  
  
-       read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
-       if (verbose > 2) {
-@@ -372,7 +382,7 @@ int recv_files(int f_in,struct file_list
-               if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
-                       rprintf(FERROR, "fstat %s failed: %s\n",
-                               full_fname(fnamecmp), strerror(errno));
--                      receive_data(f_in,NULL,-1,NULL,file->length);
-+                      receive_data(f_in,NULL,-1,NULL,file->length,NULL);
-                       close(fd1);
-                       continue;
-               }
-@@ -385,7 +395,7 @@ int recv_files(int f_in,struct file_list
-                        */
-                       rprintf(FERROR,"recv_files: %s is a directory\n",
-                               full_fname(fnamecmp));
--                      receive_data(f_in, NULL, -1, NULL, file->length);
-+                      receive_data(f_in,NULL,-1,NULL,file->length,NULL);
-                       close(fd1);
-                       continue;
-               }
-@@ -437,7 +447,7 @@ int recv_files(int f_in,struct file_list
-               if (fd2 == -1) {
-                       rprintf(FERROR, "mkstemp %s failed: %s\n",
-                               full_fname(fnametmp), strerror(errno));
--                      receive_data(f_in,mapbuf,-1,NULL,file->length);
-+                      receive_data(f_in,mapbuf,-1,NULL,file->length,NULL);
-                       if (mapbuf) unmap_file(mapbuf);
-                       if (fd1 != -1) close(fd1);
-                       continue;
-@@ -450,7 +460,12 @@ int recv_files(int f_in,struct file_list
-               }
+       if (mapbuf)
+               unmap_file(mapbuf);
+@@ -277,7 +288,7 @@ static int receive_data(int f_in, char *
+ static void discard_receive_data(int f_in, OFF_T length)
+ {
+-      receive_data(f_in, NULL, -1, 0, NULL, -1, length);
++      receive_data(f_in, NULL, -1, 0, NULL, -1, length, NULL);
+ }
+ static void handle_delayed_updates(char *local_name)
+@@ -665,7 +676,7 @@ int recv_files(int f_in, char *local_nam
  
                /* recv file data */
  
                /* recv file data */
--              recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length);
-+#ifdef HAVE_LINK
-+              if (link_by_hash_dir) {
-+                      file->u.sum = (char*)malloc (MD4_SUM_LENGTH);
-+              }
-+#endif
-+              recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length,file->u.sum);
+               recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
+-                                     fname, fd2, F_LENGTH(file));
++                                     fname, fd2, F_LENGTH(file), F_SUM(file));
  
  
-               log_recv(file, &initial_stats);
+               log_item(log_code, file, &initial_stats, iflags, NULL);
  
  
---- rsync.c    23 Mar 2004 16:16:15 -0000      1.135
-+++ rsync.c    15 Apr 2004 19:19:00 -0000
-@@ -33,6 +33,7 @@ extern int preserve_uid;
- extern int preserve_gid;
- extern int preserve_perms;
+--- old/rsync.c
++++ new/rsync.c
+@@ -47,6 +47,7 @@ extern int inplace;
+ extern int flist_eof;
+ extern int keep_dirlinks;
  extern int make_backups;
 +extern char *link_by_hash_dir;
  extern int make_backups;
 +extern char *link_by_hash_dir;
- /*
-@@ -235,8 +236,12 @@ void finish_transfer(char *fname, char *
-       if (make_backups && !make_backup(fname))
-               return;
--      /* move tmp file over real file */
--      ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
+ extern struct file_list *cur_flist, *first_flist, *dir_flist;
+ extern struct chmod_mode_struct *daemon_chmod_modes;
+ #ifdef ICONV_OPTION
+@@ -529,8 +530,15 @@ void finish_transfer(const char *fname, 
+       /* move tmp file over real file */
+       if (verbose > 2)
+               rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
+-      ret = robust_rename(fnametmp, fname, partialptr,
+-                          file->mode & INITACCESSPERMS);
 +#ifdef HAVE_LINK
 +      if (link_by_hash_dir)
 +#ifdef HAVE_LINK
 +      if (link_by_hash_dir)
-+              ret = link_by_hash(fnametmp,fname,file);
++              ret = link_by_hash(fnametmp, fname, file);
 +      else
 +#endif
 +      else
 +#endif
-+              ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
++      {
++              ret = robust_rename(fnametmp, fname, partialptr,
++                                  file->mode & INITACCESSPERMS);
++      }
        if (ret < 0) {
        if (ret < 0) {
-               rprintf(FERROR, "%s %s -> \"%s\": %s\n",
-                   ret == -2 ? "copy" : "rename",
---- rsync.h    14 Apr 2004 23:33:37 -0000      1.196
-+++ rsync.h    15 Apr 2004 19:19:00 -0000
-@@ -519,6 +519,14 @@ struct stats {
+               rsyserr(FERROR, errno, "%s %s -> \"%s\"",
+                       ret == -2 ? "copy" : "rename",
+--- old/rsync.h
++++ new/rsync.h
+@@ -768,6 +768,14 @@ struct stats {
        int current_file_index;
  };
  
        int current_file_index;
  };
  
@@ -624,6 +565,16 @@ Patch Summary:
 +      uint32 nlink;
 +};
 +
 +      uint32 nlink;
 +};
 +
+ struct chmod_mode_struct;
  
  
- /* we need this function because of the silly way in which duplicate
-    entries are handled in the file lists - we can't change this
+ #define EMPTY_ITEM_LIST {NULL, 0, 0}
+--- old/rsync.yo
++++ new/rsync.yo
+@@ -392,6 +392,7 @@ to the detailed description below for a 
+      --compare-dest=DIR      also compare received files relative to DIR
+      --copy-dest=DIR         ... and include copies of unchanged files
+      --link-dest=DIR         hardlink to files in DIR when unchanged
++     --link-by-hash=DIR      create hardlinks by hash into DIR
+  -z, --compress              compress file data during the transfer
+      --compress-level=NUM    explicitly set compression level
+      --skip-compress=LIST    skip compressing files with suffix in LIST