From dc5ddbccace1f4f37d57ce5d961117effc28a356 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 30 Jun 1996 03:57:22 +0000 Subject: [PATCH] - hard links - better sparse handling - FERROR and FINFO --- Makefile.in | 2 +- README | 4 +- compat.c | 16 ++--- configure.in | 3 +- exclude.c | 6 +- flist.c | 93 +++++++++++++++---------- hlink.c | 138 +++++++++++++++++++++++++++++++++++++ io.c | 45 ++++++++----- main.c | 128 +++++++++++++++++++++-------------- match.c | 20 +++--- rsync.c | 187 ++++++++++++++++++++++++++++----------------------- rsync.h | 11 ++- util.c | 14 ++-- 13 files changed, 444 insertions(+), 223 deletions(-) create mode 100644 hlink.c diff --git a/Makefile.in b/Makefile.in index 36e4180c..b0a1f8f2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -21,7 +21,7 @@ SHELL=/bin/sh LIBOBJ=lib/getopt.o lib/fnmatch.o OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o -OBJS=$(OBJS1) flist.o io.o compat.o $(LIBOBJ) +OBJS=$(OBJS1) flist.o io.o compat.o hlink.o $(LIBOBJ) .c.o: $(CC) $(CFLAGS) -c $*.c -o $*.o diff --git a/README b/README index 1440c343..b1651cee 100644 --- a/README +++ b/README @@ -29,11 +29,13 @@ Here is a brief description of available options: -b, --backup make backups (default ~ extension) -u, --update update only (don't overwrite newer files) -l, --links preserve soft links +-H, --hard-links preserve hard links -p, --perms preserve permissions -o, --owner preserve owner (root only) -g, --group preserve group -D, --devices preserve devices (root only) -t, --times preserve times +-S, --sparse handle sparse files efficiently -n, --dry-run show what would have been transferred -x, --one-file-system don't cross filesystem boundaries -B, --block-size SIZE checksum blocking size @@ -45,10 +47,10 @@ Here is a brief description of available options: --exclude FILE exclude file FILE --exclude-from FILE exclude files listed in FILE --suffix SUFFIX override backup suffix + --csum-length LENGTH set the checksum length --version print version number - SETUP ----- diff --git a/compat.c b/compat.c index 64808a04..04913c2e 100644 --- a/compat.c +++ b/compat.c @@ -43,7 +43,7 @@ void send_file_entry_v10(struct file_struct *file,int f) { unsigned char flags; static mode_t last_mode=0; - static dev_t last_dev=0; + static dev_t last_rdev=0; static uid_t last_uid=0; static gid_t last_gid=0; static char lastdir[MAXPATHLEN]=""; @@ -59,7 +59,7 @@ void send_file_entry_v10(struct file_struct *file,int f) flags = FILE_VALID; if (file->mode == last_mode) flags |= SAME_MODE; - if (file->dev == last_dev) flags |= SAME_DEV; + if (file->rdev == last_rdev) flags |= SAME_RDEV; if (file->uid == last_uid) flags |= SAME_UID; if (file->gid == last_gid) flags |= SAME_GID; @@ -84,8 +84,8 @@ void send_file_entry_v10(struct file_struct *file,int f) write_int(f,(int)file->uid); if (preserve_gid && !(flags & SAME_GID)) write_int(f,(int)file->gid); - if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_DEV)) - write_int(f,(int)file->dev); + if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV)) + write_int(f,(int)file->rdev); #if SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { @@ -99,7 +99,7 @@ void send_file_entry_v10(struct file_struct *file,int f) } last_mode = file->mode; - last_dev = file->dev; + last_rdev = file->rdev; last_uid = file->uid; last_gid = file->gid; p = strrchr(file->name,'/'); @@ -118,7 +118,7 @@ void receive_file_entry_v10(struct file_struct *file, unsigned char flags,int f) { static mode_t last_mode=0; - static dev_t last_dev=0; + static dev_t last_rdev=0; static uid_t last_uid=0; static gid_t last_gid=0; static char lastdir[MAXPATHLEN]=""; @@ -148,7 +148,7 @@ void receive_file_entry_v10(struct file_struct *file, if (preserve_gid) file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f); if (preserve_devices && IS_DEVICE(file->mode)) - file->dev = (flags & SAME_DEV) ? last_dev : (dev_t)read_int(f); + file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f); #if SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { @@ -164,7 +164,7 @@ void receive_file_entry_v10(struct file_struct *file, read_buf(f,file->sum,csum_length); last_mode = file->mode; - last_dev = file->dev; + last_rdev = file->rdev; last_uid = file->uid; last_gid = file->gid; p = strrchr(file->name,'/'); diff --git a/configure.in b/configure.in index 0d34b4a6..46ab1683 100644 --- a/configure.in +++ b/configure.in @@ -28,6 +28,7 @@ AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_PID_T AC_STRUCT_ST_RDEV +AC_CHECK_TYPE(ino_t,unsigned) echo $ac_n "checking for errno in errno.h... $ac_c" AC_TRY_COMPILE([#include ],[int i = errno], @@ -38,7 +39,7 @@ AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_UTIME_NULL AC_CHECK_FUNCS(waitpid strtok pipe getcwd mkdir strdup strerror chown chmod mknod) -AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink utime utimes) +AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink link utime utimes) AC_CHECK_FUNCS(memmove getopt_long) echo $ac_n "checking for working fnmatch... $ac_c" diff --git a/exclude.c b/exclude.c index 9a837411..e82bafa5 100644 --- a/exclude.c +++ b/exclude.c @@ -86,7 +86,7 @@ void add_exclude_list(char *pattern,char ***list) if (strcmp(pattern,"!") == 0) { if (verbose > 2) - fprintf(stderr,"clearing exclude list\n"); + fprintf(FERROR,"clearing exclude list\n"); while ((len)--) free((*list)[len]); free((*list)); @@ -104,7 +104,7 @@ void add_exclude_list(char *pattern,char ***list) out_of_memory("add_exclude"); if (verbose > 2) - fprintf(stderr,"add_exclude(%s)\n",pattern); + fprintf(FERROR,"add_exclude(%s)\n",pattern); (*list)[len+1] = NULL; } @@ -121,7 +121,7 @@ char **make_exclude_list(char *fname,char **list1,int fatal) char line[MAXPATHLEN]; if (!f) { if (fatal) { - fprintf(stderr,"%s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"%s : %s\n",fname,strerror(errno)); exit_cleanup(1); } return list; diff --git a/flist.c b/flist.c index fad433a0..38569aa1 100644 --- a/flist.c +++ b/flist.c @@ -33,6 +33,7 @@ extern int cvs_exclude; extern int one_file_system; extern int make_backups; extern int preserve_links; +extern int preserve_hard_links; extern int preserve_perms; extern int preserve_devices; extern int preserve_uid; @@ -52,7 +53,7 @@ static int match_file_name(char *fname,struct stat *st) { if (check_exclude(fname,local_exclude_list)) { if (verbose > 2) - fprintf(stderr,"excluding file %s\n",fname); + fprintf(FERROR,"excluding file %s\n",fname); return 0; } return 1; @@ -83,7 +84,7 @@ void send_file_entry_v11(struct file_struct *file,int f) unsigned char flags; static time_t last_time=0; static mode_t last_mode=0; - static dev_t last_dev=0; + static dev_t last_rdev=0; static uid_t last_uid=0; static gid_t last_gid=0; static char lastname[MAXPATHLEN]=""; @@ -99,7 +100,7 @@ void send_file_entry_v11(struct file_struct *file,int f) flags = FILE_VALID; if (file->mode == last_mode) flags |= SAME_MODE; - if (file->dev == last_dev) flags |= SAME_DEV; + if (file->rdev == last_rdev) flags |= SAME_RDEV; if (file->uid == last_uid) flags |= SAME_UID; if (file->gid == last_gid) flags |= SAME_GID; if (file->modtime == last_time) flags |= SAME_TIME; @@ -128,8 +129,8 @@ void send_file_entry_v11(struct file_struct *file,int f) write_int(f,(int)file->uid); if (preserve_gid && !(flags & SAME_GID)) write_int(f,(int)file->gid); - if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_DEV)) - write_int(f,(int)file->dev); + if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV)) + write_int(f,(int)file->rdev); #if SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { @@ -138,12 +139,19 @@ void send_file_entry_v11(struct file_struct *file,int f) } #endif +#if SUPPORT_HARD_LINKS + if (preserve_hard_links && S_ISREG(file->mode)) { + write_int(f,file->dev); + write_int(f,file->inode); + } +#endif + if (always_checksum) { write_buf(f,file->sum,csum_length); } last_mode = file->mode; - last_dev = file->dev; + last_rdev = file->rdev; last_uid = file->uid; last_gid = file->gid; last_time = file->modtime; @@ -159,7 +167,7 @@ void receive_file_entry_v11(struct file_struct *file, { static mode_t last_time=0; static mode_t last_mode=0; - static dev_t last_dev=0; + static dev_t last_rdev=0; static uid_t last_uid=0; static gid_t last_gid=0; static char lastname[MAXPATHLEN]=""; @@ -173,6 +181,8 @@ void receive_file_entry_v11(struct file_struct *file, else l2 = read_byte(f); + bzero((char *)file,sizeof(*file)); + file->name = (char *)malloc(l1+l2+1); if (!file->name) out_of_memory("receive_file_entry"); @@ -188,7 +198,7 @@ void receive_file_entry_v11(struct file_struct *file, if (preserve_gid) file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f); if (preserve_devices && IS_DEVICE(file->mode)) - file->dev = (flags & SAME_DEV) ? last_dev : (dev_t)read_int(f); + file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f); #if SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { @@ -199,12 +209,19 @@ void receive_file_entry_v11(struct file_struct *file, file->link[l] = 0; } #endif + +#if SUPPORT_HARD_LINKS + if (preserve_hard_links && S_ISREG(file->mode)) { + file->dev = read_int(f); + file->inode = read_int(f); + } +#endif if (always_checksum) read_buf(f,file->sum,csum_length); last_mode = file->mode; - last_dev = file->dev; + last_rdev = file->rdev; last_uid = file->uid; last_gid = file->gid; last_time = file->modtime; @@ -224,13 +241,13 @@ static struct file_struct *make_file(int recurse,char *fname) bzero(sum,SUM_LENGTH); if (lstat(fname,&st) != 0) { - fprintf(stderr,"%s: %s\n", + fprintf(FERROR,"%s: %s\n", fname,strerror(errno)); return NULL; } if (S_ISDIR(st.st_mode) && !recurse) { - fprintf(stderr,"skipping directory %s\n",fname); + fprintf(FERROR,"skipping directory %s\n",fname); return NULL; } @@ -241,7 +258,9 @@ static struct file_struct *make_file(int recurse,char *fname) return NULL; if (verbose > 2) - fprintf(stderr,"make_file(%s)\n",fname); + fprintf(FERROR,"make_file(%s)\n",fname); + + bzero((char *)&file,sizeof(file)); file.name = strdup(fname); file.modtime = st.st_mtime; @@ -249,8 +268,10 @@ static struct file_struct *make_file(int recurse,char *fname) file.mode = st.st_mode; file.uid = st.st_uid; file.gid = st.st_gid; + file.dev = st.st_dev; + file.inode = st.st_ino; #ifdef HAVE_ST_RDEV - file.dev = st.st_rdev; + file.rdev = st.st_rdev; #endif #if SUPPORT_LINKS @@ -258,7 +279,7 @@ static struct file_struct *make_file(int recurse,char *fname) int l; char lnk[MAXPATHLEN]; if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) { - fprintf(stderr,"readlink %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"readlink %s : %s\n",fname,strerror(errno)); return NULL; } lnk[l] = 0; @@ -326,7 +347,7 @@ static void send_directory(int f,struct file_list *flist,char *dir) d = opendir(dir); if (!d) { - fprintf(stderr,"%s: %s\n", + fprintf(FERROR,"%s: %s\n", dir,strerror(errno)); return; } @@ -364,8 +385,8 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[]) struct file_list *flist; if (verbose && recurse) { - fprintf(am_server?stderr:stdout,"building file list ... "); - fflush(am_server?stderr:stdout); + fprintf(FINFO,"building file list ... "); + fflush(FINFO); } flist = (struct file_list *)malloc(sizeof(flist[0])); @@ -389,12 +410,12 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[]) } if (lstat(fname,&st) != 0) { - fprintf(stderr,"%s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"%s : %s\n",fname,strerror(errno)); continue; } if (S_ISDIR(st.st_mode) && !recurse) { - fprintf(stderr,"skipping directory %s\n",fname); + fprintf(FERROR,"skipping directory %s\n",fname); continue; } @@ -410,11 +431,11 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[]) if (dir && *dir) { if (getcwd(dbuf,MAXPATHLEN-1) == NULL) { - fprintf(stderr,"getwd : %s\n",strerror(errno)); + fprintf(FERROR,"getwd : %s\n",strerror(errno)); exit_cleanup(1); } if (chdir(dir) != 0) { - fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno)); + fprintf(FERROR,"chdir %s : %s\n",dir,strerror(errno)); continue; } flist_dir = dir; @@ -423,7 +444,7 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[]) send_file_name(f,flist,recurse,fname); flist_dir = NULL; if (chdir(dbuf) != 0) { - fprintf(stderr,"chdir %s : %s\n",dbuf,strerror(errno)); + fprintf(FERROR,"chdir %s : %s\n",dbuf,strerror(errno)); exit_cleanup(1); } continue; @@ -439,10 +460,10 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[]) write_flush(f); } - clean_flist(flist); - if (verbose && recurse) - fprintf(am_server?stderr:stdout,"done\n"); + fprintf(FINFO,"done\n"); + + clean_flist(flist); return flist; } @@ -454,7 +475,7 @@ struct file_list *recv_file_list(int f) unsigned char flags; if (verbose > 2) - fprintf(stderr,"recv_file_list starting\n"); + fprintf(FERROR,"recv_file_list starting\n"); flist = (struct file_list *)malloc(sizeof(flist[0])); if (!flist) @@ -488,12 +509,12 @@ struct file_list *recv_file_list(int f) flist->count++; if (verbose > 2) - fprintf(stderr,"recv_file_name(%s)\n",flist->files[i].name); + fprintf(FERROR,"recv_file_name(%s)\n",flist->files[i].name); } if (verbose > 2) - fprintf(stderr,"received %d names\n",flist->count); + fprintf(FERROR,"received %d names\n",flist->count); clean_flist(flist); @@ -505,7 +526,7 @@ oom: } -static int flist_compare(struct file_struct *f1,struct file_struct *f2) +int file_compare(struct file_struct *f1,struct file_struct *f2) { if (!f1->name && !f2->name) return 0; if (!f1->name) return -1; @@ -520,14 +541,14 @@ int flist_find(struct file_list *flist,struct file_struct *f) while (low != high) { int mid = (low+high)/2; - int ret = flist_compare(&flist->files[mid],f); + int ret = file_compare(&flist->files[mid],f); if (ret == 0) return mid; if (ret > 0) high=mid; else low=mid+1; } - if (flist_compare(&flist->files[low],f) == 0) + if (file_compare(&flist->files[low],f) == 0) return low; return -1; } @@ -594,17 +615,17 @@ void clean_flist(struct file_list *flist) qsort(flist->files,flist->count, sizeof(flist->files[0]), - (int (*)())flist_compare); + (int (*)())file_compare); for (i=1;icount;i++) { if (flist->files[i].name && strcmp(flist->files[i].name,flist->files[i-1].name) == 0) { if (verbose > 1 && !am_server) - fprintf(stderr,"removing duplicate name %s from file list\n", - flist->files[i].name); + fprintf(FERROR,"removing duplicate name %s from file list %d\n", + flist->files[i-1].name,i-1); free(flist->files[i-1].name); - flist->files[i-1].name = NULL; - } + bzero((char *)&flist->files[i-1],sizeof(flist->files[i-1])); + } } } diff --git a/hlink.c b/hlink.c new file mode 100644 index 00000000..3213b2ea --- /dev/null +++ b/hlink.c @@ -0,0 +1,138 @@ +/* + Copyright (C) Andrew Tridgell 1996 + Copyright (C) Paul Mackerras 1996 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "rsync.h" + +extern int am_server; +extern int dry_run; + +#if SUPPORT_HARD_LINKS +static int hlink_compare(struct file_struct *f1,struct file_struct *f2) +{ + if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode)) return 0; + if (!S_ISREG(f1->mode)) return -1; + if (!S_ISREG(f2->mode)) return 1; + + if (f1->dev != f2->dev) + return (f1->dev - f2->dev); + + if (f1->inode != f2->inode) + return (f1->inode - f2->inode); + + return file_compare(f1,f2); +} + + +static struct file_struct *hlink_list = NULL; +static int hlink_count=0; +#endif + +void init_hard_links(struct file_list *flist) +{ +#if SUPPORT_HARD_LINKS + if (flist->count < 2) return; + + if (hlink_list) free(hlink_list); + + if (!(hlink_list = + (struct file_struct *)malloc(sizeof(hlink_list[0])*flist->count))) + out_of_memory("init_hard_links"); + + bcopy((char *)flist->files,hlink_list,sizeof(hlink_list[0])*flist->count); + + qsort(hlink_list,flist->count, + sizeof(hlink_list[0]), + (int (*)())hlink_compare); + + hlink_count=flist->count; +#endif +} + +/* check if a file should be skipped because it is the same as an + earlier hard link */ +int check_hard_link(struct file_struct *file) +{ +#if SUPPORT_HARD_LINKS + int low=0,high=hlink_count; + int mid=0,ret=0; + + if (!hlink_list || !S_ISREG(file->mode)) return 0; + + while (low != high) { + mid = (low+high)/2; + ret = hlink_compare(&hlink_list[mid],file); + if (ret == 0) break; + if (ret > 0) + high=mid; + else + low=mid+1; + } + + if (hlink_compare(&hlink_list[mid],file) != 0) return 0; + + if (mid > 0 && + S_ISREG(hlink_list[mid-1].mode) && + file->dev == hlink_list[mid-1].dev && + file->inode == hlink_list[mid-1].inode) + return 1; +#endif + + return 0; +} + + +/* create any hard links in the flist */ +void do_hard_links(struct file_list *flist) +{ +#if SUPPORT_HARD_LINKS + int i; + + if (!hlink_list) return; + + for (i=1;i %s : %s\n", + hlink_list[i].name,hlink_list[i-1].name,strerror(errno)); + continue; + } + } else { + if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) continue; + + if (!dry_run && (unlink(hlink_list[i].name) != 0 || + link(hlink_list[i-1].name,hlink_list[i].name) != 0)) { + fprintf(FINFO,"link %s => %s : %s\n", + hlink_list[i].name,hlink_list[i-1].name,strerror(errno)); + continue; + } + } + fprintf(FINFO,"%s => %s\n", + hlink_list[i].name,hlink_list[i-1].name); + } + } +#endif +} diff --git a/io.c b/io.c index 9b6bdc82..3c55dbee 100644 --- a/io.c +++ b/io.c @@ -28,6 +28,7 @@ static int total_written = 0; static int total_read = 0; extern int verbose; +extern int sparse_files; int write_total(void) { @@ -128,7 +129,7 @@ int read_int(int f) char b[4]; if ((ret=readfd(f,b,4)) != 4) { if (verbose > 1) - fprintf(stderr,"Error reading %d bytes : %s\n", + fprintf(FERROR,"Error reading %d bytes : %s\n", 4,ret==-1?strerror(errno):"EOF"); exit_cleanup(1); } @@ -141,7 +142,7 @@ void read_buf(int f,char *buf,int len) int ret; if ((ret=readfd(f,buf,len)) != len) { if (verbose > 1) - fprintf(stderr,"Error reading %d bytes : %s\n", + fprintf(FERROR,"Error reading %d bytes : %s\n", len,ret==-1?strerror(errno):"EOF"); exit_cleanup(1); } @@ -161,43 +162,51 @@ static int last_sparse = 0; int sparse_end(int f) { -#if SPARSE_FILES if (last_sparse) { lseek(f,-1,SEEK_CUR); return (write(f,&last_byte,1) == 1 ? 0 : -1); } -#endif last_sparse = 0; return 0; } int write_sparse(int f,char *buf,int len) { - int l=0; + int l1=0,l2=0; + int ret; -#if SPARSE_FILES - for (l=0;l 0) - lseek(f,l,SEEK_CUR); + for (l1=0;l1 0) + last_sparse=1; + + if (l1 > 0) + lseek(f,l1,SEEK_CUR); + + if (l1 == len) return len; - } - last_sparse = 0; + if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) { + if (ret == -1 || ret == 0) return ret; + return (l1+ret); + } + + if (l2 > 0) + lseek(f,l2,SEEK_CUR); - return (l + write(f,buf+l,len-l)); + return len; } int read_write(int fd_in,int fd_out,int size) { static char *buf=NULL; - static int bufsize = CHUNK_SIZE; + int bufsize = sparse_files?SPARSE_WRITE_SIZE:WRITE_SIZE; int total=0; if (!buf) { @@ -257,7 +266,7 @@ void write_int(int f,int x) char b[4]; SIVAL(b,0,x); if ((ret=writefd(f,b,4)) != 4) { - fprintf(stderr,"write_int failed : %s\n", + fprintf(FERROR,"write_int failed : %s\n", ret==-1?strerror(errno):"EOF"); exit_cleanup(1); } @@ -268,7 +277,7 @@ void write_buf(int f,char *buf,int len) { int ret; if ((ret=writefd(f,buf,len)) != len) { - fprintf(stderr,"write_buf failed : %s\n", + fprintf(FERROR,"write_buf failed : %s\n", ret==-1?strerror(errno):"EOF"); exit_cleanup(1); } diff --git a/main.c b/main.c index ceed01da..a0887202 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,7 @@ static char *rsync_path = RSYNC_NAME; int make_backups = 0; int preserve_links = 0; +int preserve_hard_links = 0; int preserve_perms = 0; int preserve_devices = 0; int preserve_uid = 0; @@ -44,6 +45,7 @@ int ignore_times=0; int delete_mode=0; int one_file_system=0; int remote_version=0; +int sparse_files=0; extern int csum_length; int am_server = 0; @@ -109,6 +111,8 @@ static void server_options(char **args,int *argc) argstr[x++] = 'n'; if (preserve_links) argstr[x++] = 'l'; + if (preserve_hard_links) + argstr[x++] = 'H'; if (preserve_uid) argstr[x++] = 'o'; if (preserve_gid) @@ -129,6 +133,8 @@ static void server_options(char **args,int *argc) argstr[x++] = 'I'; if (one_file_system) argstr[x++] = 'x'; + if (sparse_files) + argstr[x++] = 'S'; argstr[x] = 0; if (x != 1) args[ac++] = argstr; @@ -199,10 +205,10 @@ int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out) args[argc] = NULL; if (verbose > 3) { - fprintf(stderr,"cmd="); + fprintf(FERROR,"cmd="); for (i=0;icount > 1) { - fprintf(stderr,"ERROR: destination must be a directory when copying more than 1 file\n"); + fprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n"); exit_cleanup(1); } return name; @@ -241,14 +247,14 @@ static char *get_local_name(struct file_list *flist,char *name) return NULL; if (mkdir(name,0777) != 0) { - fprintf(stderr,"mkdir %s : %s\n",name,strerror(errno)); + fprintf(FERROR,"mkdir %s : %s\n",name,strerror(errno)); exit_cleanup(1); } else { - fprintf(am_server?stderr:stdout,"created directory %s\n",name); + fprintf(FINFO,"created directory %s\n",name); } if (chdir(name) != 0) { - fprintf(stderr,"chdir %s : %s\n",name,strerror(errno)); + fprintf(FERROR,"chdir %s : %s\n",name,strerror(errno)); exit_cleanup(1); } @@ -265,10 +271,10 @@ void do_server_sender(int argc,char *argv[]) struct file_list *flist; if (verbose > 2) - fprintf(stderr,"server_sender starting pid=%d\n",(int)getpid()); + fprintf(FERROR,"server_sender starting pid=%d\n",(int)getpid()); if (chdir(dir) != 0) { - fprintf(stderr,"chdir %s: %s\n",dir,strerror(errno)); + fprintf(FERROR,"chdir %s: %s\n",dir,strerror(errno)); exit_cleanup(1); } argc--; @@ -294,23 +300,47 @@ void do_server_sender(int argc,char *argv[]) } +static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) +{ + int pid; + int status=0; + + if (preserve_hard_links) + init_hard_links(flist); + + if ((pid=fork()) == 0) { + recv_files(f_in,flist,local_name); + if (preserve_hard_links) + do_hard_links(flist); + if (verbose > 2) + fprintf(FERROR,"receiver read %d\n",read_total()); + exit_cleanup(0); + } + + generate_files(f_out,flist,local_name); + + waitpid(pid, &status, 0); + + return status; +} + void do_server_recv(int argc,char *argv[]) { - int pid,status; + int status; char *dir = NULL; struct file_list *flist; char *local_name=NULL; if (verbose > 2) - fprintf(stderr,"server_recv(%d) starting pid=%d\n",argc,(int)getpid()); + fprintf(FERROR,"server_recv(%d) starting pid=%d\n",argc,(int)getpid()); if (argc > 0) { dir = argv[0]; argc--; argv++; if (chdir(dir) != 0) { - fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno)); + fprintf(FERROR,"chdir %s : %s\n",dir,strerror(errno)); exit_cleanup(1); } } @@ -320,7 +350,7 @@ void do_server_recv(int argc,char *argv[]) flist = recv_file_list(STDIN_FILENO); if (!flist || flist->count == 0) { - fprintf(stderr,"nothing to do\n"); + fprintf(FERROR,"nothing to do\n"); exit_cleanup(1); } @@ -332,16 +362,7 @@ void do_server_recv(int argc,char *argv[]) local_name = get_local_name(flist,argv[0]); } - if ((pid=fork()) == 0) { - recv_files(STDIN_FILENO,flist,local_name); - if (verbose > 2) - fprintf(stderr,"receiver read %d\n",read_total()); - exit_cleanup(0); - } - - generate_files(STDOUT_FILENO,flist,local_name); - - waitpid(pid, &status, 0); + status = do_recv(STDIN_FILENO,STDOUT_FILENO,flist,local_name); exit_cleanup(status); } @@ -360,11 +381,13 @@ static void usage(FILE *f) fprintf(f,"-b, --backup make backups (default ~ extension)\n"); fprintf(f,"-u, --update update only (don't overwrite newer files)\n"); fprintf(f,"-l, --links preserve soft links\n"); + fprintf(f,"-H, --hard-links preserve hard links\n"); fprintf(f,"-p, --perms preserve permissions\n"); fprintf(f,"-o, --owner preserve owner (root only)\n"); fprintf(f,"-g, --group preserve group\n"); fprintf(f,"-D, --devices preserve devices (root only)\n"); fprintf(f,"-t, --times preserve times\n"); + fprintf(f,"-S, --sparse handle sparse files efficiently\n"); fprintf(f,"-n, --dry-run show what would have been transferred\n"); fprintf(f,"-x, --one-file-system don't cross filesystem boundaries\n"); fprintf(f,"-B, --block-size SIZE checksum blocking size\n"); @@ -387,7 +410,7 @@ static void usage(FILE *f) enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE, OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH,OPT_CSUM_LENGTH}; -static char *short_options = "oblpguDCtcahvrIxne:B:"; +static char *short_options = "oblHpguDCtcahvrIxnSe:B:"; static struct option long_options[] = { {"version", 0, 0, OPT_VERSION}, @@ -402,6 +425,7 @@ static struct option long_options[] = { {"ignore-times",0, 0, 'I'}, {"help", 0, 0, 'h'}, {"dry-run", 0, 0, 'n'}, + {"sparse", 0, 0, 'S'}, {"cvs-exclude", 0, 0, 'C'}, {"archive", 0, 0, 'a'}, {"checksum", 0, 0, 'c'}, @@ -412,6 +436,7 @@ static struct option long_options[] = { {"devices", 0, 0, 'D'}, {"perms", 0, 0, 'p'}, {"links", 0, 0, 'l'}, + {"hard-links", 0, 0, 'H'}, {"owner", 0, 0, 'o'}, {"group", 0, 0, 'g'}, {"times", 0, 0, 't'}, @@ -422,7 +447,7 @@ static struct option long_options[] = { int main(int argc,char *argv[]) { - int pid, status, pid2, status2; + int pid, status, status2; int opt; int option_index; char *shell_cmd = NULL; @@ -482,7 +507,7 @@ int main(int argc,char *argv[]) break; case 'h': - usage(stdout); + usage(FINFO); exit_cleanup(0); case 'b': @@ -493,6 +518,10 @@ int main(int argc,char *argv[]) dry_run=1; break; + case 'S': + sparse_files=1; + break; + case 'C': cvs_exclude=1; break; @@ -501,11 +530,17 @@ int main(int argc,char *argv[]) update_only=1; break; -#if SUPPORT_LINKS case 'l': +#if SUPPORT_LINKS preserve_links=1; +#endif break; + + case 'H': +#if SUPPORT_HARD_LINKS + preserve_hard_links=1; #endif + break; case 'p': preserve_perms=1; @@ -515,7 +550,7 @@ int main(int argc,char *argv[]) if (getuid() == 0) { preserve_uid=1; } else { - fprintf(stderr,"-o only allowed for root\n"); + fprintf(FERROR,"-o only allowed for root\n"); exit_cleanup(1); } break; @@ -528,7 +563,7 @@ int main(int argc,char *argv[]) if (getuid() == 0) { preserve_devices=1; } else { - fprintf(stderr,"-D only allowed for root\n"); + fprintf(FERROR,"-D only allowed for root\n"); exit_cleanup(1); } break; @@ -565,7 +600,7 @@ int main(int argc,char *argv[]) case OPT_SENDER: if (!am_server) { - usage(stderr); + usage(FERROR); exit_cleanup(1); } sender = 1; @@ -584,7 +619,7 @@ int main(int argc,char *argv[]) break; default: - fprintf(stderr,"bad option -%c\n",opt); + fprintf(FERROR,"bad option -%c\n",opt); exit_cleanup(1); } } @@ -606,7 +641,7 @@ int main(int argc,char *argv[]) remote_version = read_int(STDIN_FILENO); if (remote_version < MIN_PROTOCOL_VERSION || remote_version > MAX_PROTOCOL_VERSION) { - fprintf(stderr,"protocol version mismatch - is your shell clean?\n"); + fprintf(FERROR,"protocol version mismatch - is your shell clean?\n"); exit_cleanup(1); } write_int(STDOUT_FILENO,PROTOCOL_VERSION); @@ -626,7 +661,7 @@ int main(int argc,char *argv[]) } if (argc < 2) { - usage(stderr); + usage(FERROR); exit_cleanup(1); } @@ -668,7 +703,7 @@ int main(int argc,char *argv[]) } if (verbose > 3) { - fprintf(stderr,"cmd=%s machine=%s user=%s path=%s\n", + fprintf(FERROR,"cmd=%s machine=%s user=%s path=%s\n", shell_cmd?shell_cmd:"", shell_machine?shell_machine:"", shell_user?shell_user:"", @@ -676,7 +711,7 @@ int main(int argc,char *argv[]) } if (!sender && argc != 1) { - usage(stderr); + usage(FERROR); exit_cleanup(1); } @@ -688,7 +723,7 @@ int main(int argc,char *argv[]) remote_version = read_int(f_in); if (remote_version < MIN_PROTOCOL_VERSION || remote_version > MAX_PROTOCOL_VERSION) { - fprintf(stderr,"protocol version mismatch - is your shell clean?\n"); + fprintf(FERROR,"protocol version mismatch - is your shell clean?\n"); exit_cleanup(1); } } @@ -696,7 +731,7 @@ int main(int argc,char *argv[]) setup_protocol(); if (verbose > 3) - fprintf(stderr,"parent=%d child=%d sender=%d recurse=%d\n", + fprintf(FERROR,"parent=%d child=%d sender=%d recurse=%d\n", (int)getpid(),pid,sender,recurse); if (sender) { @@ -706,10 +741,10 @@ int main(int argc,char *argv[]) send_exclude_list(f_out); flist = send_file_list(f_out,recurse,argc,argv); if (verbose > 3) - fprintf(stderr,"file list sent\n"); + fprintf(FERROR,"file list sent\n"); send_files(flist,f_out,f_in); if (verbose > 3) - fprintf(stderr,"waiting on %d\n",pid); + fprintf(FERROR,"waiting on %d\n",pid); waitpid(pid, &status, 0); report(-1); exit_cleanup(status); @@ -719,22 +754,13 @@ int main(int argc,char *argv[]) flist = recv_file_list(f_in); if (!flist || flist->count == 0) { - fprintf(stderr,"nothing to do\n"); + fprintf(FERROR,"nothing to do\n"); exit_cleanup(0); } local_name = get_local_name(flist,argv[0]); - if ((pid2=fork()) == 0) { - recv_files(f_in,flist,local_name); - if (verbose > 1) - fprintf(stderr,"receiver read %d\n",read_total()); - exit_cleanup(0); - } - - generate_files(f_out,flist,local_name); - - waitpid(pid2, &status2, 0); + status2 = do_recv(f_in,f_out,flist,local_name); report(f_in); diff --git a/match.c b/match.c index 2c807279..971fa109 100644 --- a/match.c +++ b/match.c @@ -95,7 +95,7 @@ static void matched(int f,struct sum_struct *s,char *buf,off_t len, if (verbose > 2) if (i != -1) - fprintf(stderr,"match at %d last_match=%d j=%d len=%d n=%d\n", + fprintf(FERROR,"match at %d last_match=%d j=%d len=%d n=%d\n", (int)offset,(int)last_match,i,(int)s->sums[i].len,n); if (n > 0) { @@ -125,7 +125,7 @@ static void hash_search(int f,struct sum_struct *s,char *buf,off_t len) char *map; if (verbose > 2) - fprintf(stderr,"hash search b=%d len=%d\n",s->n,(int)len); + fprintf(FERROR,"hash search b=%d len=%d\n",s->n,(int)len); k = MIN(len, s->n); @@ -135,21 +135,21 @@ static void hash_search(int f,struct sum_struct *s,char *buf,off_t len) s1 = sum & 0xFFFF; s2 = sum >> 16; if (verbose > 3) - fprintf(stderr, "sum=%.8x k=%d\n", sum, k); + fprintf(FERROR, "sum=%.8x k=%d\n", sum, k); offset = 0; end = len + 1 - s->sums[s->count-1].len; if (verbose > 3) - fprintf(stderr,"hash search s->n=%d len=%d count=%d\n", + fprintf(FERROR,"hash search s->n=%d len=%d count=%d\n", s->n,(int)len,s->count); do { tag t = gettag2(s1,s2); j = tag_table[t]; if (verbose > 4) - fprintf(stderr,"offset=%d sum=%08x\n", + fprintf(FERROR,"offset=%d sum=%08x\n", offset,sum); if (j != NULL_TAG) { @@ -162,7 +162,7 @@ static void hash_search(int f,struct sum_struct *s,char *buf,off_t len) if (sum == s->sums[i].sum1) { if (verbose > 3) - fprintf(stderr,"potential match at %d target=%d %d sum=%08x\n", + fprintf(FERROR,"potential match at %d target=%d %d sum=%08x\n", offset,j,i,sum); if (!done_csum2) { @@ -220,12 +220,12 @@ void match_sums(int f,struct sum_struct *s,char *buf,off_t len) build_hash_table(s); if (verbose > 2) - fprintf(stderr,"built hash table\n"); + fprintf(FERROR,"built hash table\n"); hash_search(f,s,buf,len); if (verbose > 2) - fprintf(stderr,"done hash search\n"); + fprintf(FERROR,"done hash search\n"); } else { matched(f,s,buf,len,len,-1); } @@ -236,7 +236,7 @@ void match_sums(int f,struct sum_struct *s,char *buf,off_t len) } if (verbose > 2) - fprintf(stderr, "false_alarms=%d tag_hits=%d matches=%d\n", + fprintf(FERROR, "false_alarms=%d tag_hits=%d matches=%d\n", false_alarms, tag_hits, matches); total_tag_hits += tag_hits; @@ -250,7 +250,7 @@ void match_report(void) if (verbose <= 1) return; - fprintf(am_server?stderr:stdout, + fprintf(FINFO, "total: matches=%d tag_hits=%d false_alarms=%d data=%d\n", total_matches,total_tag_hits, total_false_alarms,total_data_transfer); diff --git a/rsync.c b/rsync.c index bb249800..5ae36950 100644 --- a/rsync.c +++ b/rsync.c @@ -32,6 +32,7 @@ extern int block_size; extern int update_only; extern int make_backups; extern int preserve_links; +extern int preserve_hard_links; extern int preserve_perms; extern int preserve_devices; extern int preserve_uid; @@ -105,7 +106,7 @@ static struct sum_struct *generate_sums(char *buf,off_t len,int n) } if (verbose > 3) - fprintf(stderr,"count=%d rem=%d n=%d flength=%d\n", + fprintf(FERROR,"count=%d rem=%d n=%d flength=%d\n", s->count,s->remainder,s->n,(int)s->flength); s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count); @@ -123,7 +124,7 @@ static struct sum_struct *generate_sums(char *buf,off_t len,int n) s->sums[i].i = i; if (verbose > 3) - fprintf(stderr,"chunk[%d] offset=%d len=%d sum1=%08x\n", + fprintf(FERROR,"chunk[%d] offset=%d len=%d sum1=%08x\n", i,(int)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1); len -= n1; @@ -153,7 +154,7 @@ static struct sum_struct *receive_sums(int f) s->sums = NULL; if (verbose > 3) - fprintf(stderr,"count=%d n=%d rem=%d\n", + fprintf(FERROR,"count=%d n=%d rem=%d\n", s->count,s->n,s->remainder); block_len = s->n; @@ -179,7 +180,7 @@ static struct sum_struct *receive_sums(int f) offset += s->sums[i].len; if (verbose > 3) - fprintf(stderr,"chunk[%d] len=%d offset=%d sum1=%08x\n", + fprintf(FERROR,"chunk[%d] len=%d offset=%d sum1=%08x\n", i,s->sums[i].len,(int)s->sums[i].offset,s->sums[i].sum1); } @@ -199,7 +200,7 @@ static void set_perms(char *fname,struct file_struct *file,struct stat *st, if (!st) { if (stat(fname,&st2) != 0) { - fprintf(stderr,"stat %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"stat %s : %s\n",fname,strerror(errno)); return; } st = &st2; @@ -209,7 +210,7 @@ static void set_perms(char *fname,struct file_struct *file,struct stat *st, st->st_mtime != file->modtime) { updated = 1; if (set_modtime(fname,file->modtime) != 0) { - fprintf(stderr,"failed to set times on %s : %s\n", + fprintf(FERROR,"failed to set times on %s : %s\n", fname,strerror(errno)); return; } @@ -220,7 +221,7 @@ static void set_perms(char *fname,struct file_struct *file,struct stat *st, st->st_mode != file->mode) { updated = 1; if (chmod(fname,file->mode) != 0) { - fprintf(stderr,"failed to set permissions on %s : %s\n", + fprintf(FERROR,"failed to set permissions on %s : %s\n", fname,strerror(errno)); return; } @@ -234,16 +235,16 @@ static void set_perms(char *fname,struct file_struct *file,struct stat *st, preserve_uid?file->uid:-1, preserve_gid?file->gid:-1) != 0) { if (verbose>1 || preserve_uid) - fprintf(stderr,"chown %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"chown %s : %s\n",fname,strerror(errno)); return; } } if (verbose > 1 && report) { if (updated) - fprintf(am_server?stderr:stdout,"%s\n",fname); + fprintf(FINFO,"%s\n",fname); else - fprintf(am_server?stderr:stdout,"%s is uptodate\n",fname); + fprintf(FINFO,"%s is uptodate\n",fname); } } @@ -256,66 +257,73 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) struct sum_struct *s; char sum[SUM_LENGTH]; int statret; + struct file_struct *file = &flist->files[i]; if (verbose > 2) - fprintf(stderr,"recv_generator(%s)\n",fname); + fprintf(FERROR,"recv_generator(%s)\n",fname); statret = lstat(fname,&st); #if SUPPORT_LINKS - if (preserve_links && S_ISLNK(flist->files[i].mode)) { + if (preserve_links && S_ISLNK(file->mode)) { char lnk[MAXPATHLEN]; int l; if (statret == 0) { l = readlink(fname,lnk,MAXPATHLEN-1); if (l > 0) { lnk[l] = 0; - if (strcmp(lnk,flist->files[i].link) == 0) { - set_perms(fname,&flist->files[i],&st,1); + if (strcmp(lnk,file->link) == 0) { + set_perms(fname,file,&st,1); return; } } } if (!dry_run) unlink(fname); - if (!dry_run && symlink(flist->files[i].link,fname) != 0) { - fprintf(stderr,"link %s -> %s : %s\n", - fname,flist->files[i].link,strerror(errno)); + if (!dry_run && symlink(file->link,fname) != 0) { + fprintf(FERROR,"link %s -> %s : %s\n", + fname,file->link,strerror(errno)); } else { - set_perms(fname,&flist->files[i],NULL,0); + set_perms(fname,file,NULL,0); if (verbose) - fprintf(am_server?stderr:stdout,"%s -> %s\n", - fname,flist->files[i].link); + fprintf(FINFO,"%s -> %s\n", + fname,file->link); } return; } #endif #ifdef HAVE_MKNOD - if (preserve_devices && IS_DEVICE(flist->files[i].mode)) { + if (preserve_devices && IS_DEVICE(file->mode)) { if (statret != 0 || - st.st_mode != flist->files[i].mode || - st.st_rdev != flist->files[i].dev) { + st.st_mode != file->mode || + st.st_rdev != file->rdev) { if (!dry_run) unlink(fname); if (verbose > 2) - fprintf(stderr,"mknod(%s,0%o,0x%x)\n", - fname,(int)flist->files[i].mode,(int)flist->files[i].dev); + fprintf(FERROR,"mknod(%s,0%o,0x%x)\n", + fname,(int)file->mode,(int)file->rdev); if (!dry_run && - mknod(fname,flist->files[i].mode,flist->files[i].dev) != 0) { - fprintf(stderr,"mknod %s : %s\n",fname,strerror(errno)); + mknod(fname,file->mode,file->rdev) != 0) { + fprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno)); } else { - set_perms(fname,&flist->files[i],NULL,0); + set_perms(fname,file,NULL,0); if (verbose) - fprintf(am_server?stderr:stdout,"%s\n",fname); + fprintf(FINFO,"%s\n",fname); } } else { - set_perms(fname,&flist->files[i],&st,1); + set_perms(fname,file,&st,1); } return; } #endif - if (!S_ISREG(flist->files[i].mode)) { - fprintf(stderr,"skipping non-regular file %s\n",fname); + if (preserve_hard_links && check_hard_link(file)) { + if (verbose > 1) + fprintf(FINFO,"%s is a hard link\n",file->name); + return; + } + + if (!S_ISREG(file->mode)) { + fprintf(FERROR,"skipping non-regular file %s\n",fname); return; } @@ -325,19 +333,19 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) if (!dry_run) send_sums(NULL,f_out); } else { if (verbose > 1) - fprintf(stderr,"recv_generator failed to open %s\n",fname); + fprintf(FERROR,"recv_generator failed to open %s\n",fname); } return; } if (!S_ISREG(st.st_mode)) { - fprintf(stderr,"%s : not a regular file\n",fname); + fprintf(FERROR,"%s : not a regular file\n",fname); return; } - if (update_only && st.st_mtime >= flist->files[i].modtime) { + if (update_only && st.st_mtime >= file->modtime) { if (verbose > 1) - fprintf(stderr,"%s is newer\n",fname); + fprintf(FERROR,"%s is newer\n",fname); return; } @@ -345,11 +353,11 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) file_checksum(fname,sum,st.st_size); } - if (st.st_size == flist->files[i].length && - ((!ignore_times && st.st_mtime == flist->files[i].modtime) || + if (st.st_size == file->length && + ((!ignore_times && st.st_mtime == file->modtime) || (always_checksum && S_ISREG(st.st_mode) && - memcmp(sum,flist->files[i].sum,csum_length) == 0))) { - set_perms(fname,&flist->files[i],&st,1); + memcmp(sum,file->sum,csum_length) == 0))) { + set_perms(fname,file,&st,1); return; } @@ -362,7 +370,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) fd = open(fname,O_RDONLY); if (fd == -1) { - fprintf(stderr,"failed to open %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"failed to open %s : %s\n",fname,strerror(errno)); return; } @@ -373,7 +381,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) } if (verbose > 3) - fprintf(stderr,"mapped %s of size %d\n",fname,(int)st.st_size); + fprintf(FERROR,"mapped %s of size %d\n",fname,(int)st.st_size); s = generate_sums(buf,st.st_size,block_size); @@ -402,10 +410,10 @@ static void receive_data(int f_in,char *buf,int fd,char *fname) for (i=read_int(f_in); i != 0; i=read_int(f_in)) { if (i > 0) { if (verbose > 3) - fprintf(stderr,"data recv %d at %d\n",i,(int)offset); + fprintf(FERROR,"data recv %d at %d\n",i,(int)offset); if (read_write(f_in,fd,i) != i) { - fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); exit_cleanup(1); } offset += i; @@ -417,11 +425,11 @@ static void receive_data(int f_in,char *buf,int fd,char *fname) len = remainder; if (verbose > 3) - fprintf(stderr,"chunk[%d] of size %d at %d offset=%d\n", + fprintf(FERROR,"chunk[%d] of size %d at %d offset=%d\n", i,len,(int)offset2,(int)offset); if (write_sparse(fd,map_ptr(buf,offset2,len),len) != len) { - fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); exit_cleanup(1); } offset += len; @@ -429,7 +437,7 @@ static void receive_data(int f_in,char *buf,int fd,char *fname) } if (offset > 0 && sparse_end(fd) != 0) { - fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); exit_cleanup(1); } } @@ -439,16 +447,16 @@ static void delete_one(struct file_struct *f) { if (!S_ISDIR(f->mode)) { if (!dry_run && unlink(f->name) != 0) { - fprintf(stderr,"unlink %s : %s\n",f->name,strerror(errno)); + fprintf(FERROR,"unlink %s : %s\n",f->name,strerror(errno)); } else if (verbose) { - fprintf(stderr,"deleting %s\n",f->name); + fprintf(FERROR,"deleting %s\n",f->name); } } else { if (!dry_run && rmdir(f->name) != 0) { if (errno != ENOTEMPTY) - fprintf(stderr,"rmdir %s : %s\n",f->name,strerror(errno)); + fprintf(FERROR,"rmdir %s : %s\n",f->name,strerror(errno)); } else if (verbose) { - fprintf(stderr,"deleting directory %s\n",f->name); + fprintf(FERROR,"deleting directory %s\n",f->name); } } } @@ -497,9 +505,10 @@ int recv_files(int f_in,struct file_list *flist,char *local_name) char fnametmp[MAXPATHLEN]; char *buf; int i; + struct file_struct *file; if (verbose > 2) { - fprintf(stderr,"recv_files(%d) starting\n",flist->count); + fprintf(FERROR,"recv_files(%d) starting\n",flist->count); } if (recurse && delete_mode && !local_name && flist->count>0) { @@ -511,7 +520,8 @@ int recv_files(int f_in,struct file_list *flist,char *local_name) i = read_int(f_in); if (i == -1) break; - fname = flist->files[i].name; + file = &flist->files[i]; + fname = file->name; if (local_name) fname = local_name; @@ -523,19 +533,19 @@ int recv_files(int f_in,struct file_list *flist,char *local_name) } if (verbose > 2) - fprintf(stderr,"recv_files(%s)\n",fname); + fprintf(FERROR,"recv_files(%s)\n",fname); /* open the file */ fd1 = open(fname,O_RDONLY); if (fd1 != -1 && fstat(fd1,&st) != 0) { - fprintf(stderr,"fstat %s : %s\n",fname,strerror(errno)); + fprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno)); close(fd1); return -1; } if (fd1 != -1 && !S_ISREG(st.st_mode)) { - fprintf(stderr,"%s : not a regular file\n",fname); + fprintf(FERROR,"%s : not a regular file\n",fname); close(fd1); return -1; } @@ -547,17 +557,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name) } if (verbose > 2) - fprintf(stderr,"mapped %s of size %d\n",fname,(int)st.st_size); + fprintf(FERROR,"mapped %s of size %d\n",fname,(int)st.st_size); /* open tmp file */ sprintf(fnametmp,"%s.XXXXXX",fname); if (NULL == mktemp(fnametmp)) { - fprintf(stderr,"mktemp %s failed\n",fnametmp); + fprintf(FERROR,"mktemp %s failed\n",fnametmp); return -1; } - fd2 = open(fnametmp,O_WRONLY|O_CREAT,flist->files[i].mode); + fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode); if (fd2 == -1) { - fprintf(stderr,"open %s : %s\n",fnametmp,strerror(errno)); + fprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno)); return -1; } @@ -576,30 +586,30 @@ int recv_files(int f_in,struct file_list *flist,char *local_name) close(fd2); if (verbose > 2) - fprintf(stderr,"renaming %s to %s\n",fnametmp,fname); + fprintf(FERROR,"renaming %s to %s\n",fnametmp,fname); if (make_backups) { char fnamebak[MAXPATHLEN]; sprintf(fnamebak,"%s%s",fname,backup_suffix); if (rename(fname,fnamebak) != 0 && errno != ENOENT) { - fprintf(stderr,"rename %s %s : %s\n",fname,fnamebak,strerror(errno)); + fprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno)); exit_cleanup(1); } } /* move tmp file over real file */ if (rename(fnametmp,fname) != 0) { - fprintf(stderr,"rename %s -> %s : %s\n", + fprintf(FERROR,"rename %s -> %s : %s\n", fnametmp,fname,strerror(errno)); } cleanup_fname = NULL; - set_perms(fname,&flist->files[i],NULL,0); + set_perms(fname,file,NULL,0); } if (verbose > 2) - fprintf(stderr,"recv_files finished\n"); + fprintf(FERROR,"recv_files finished\n"); return 0; } @@ -615,9 +625,10 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) char fname[MAXPATHLEN]; off_t total=0; int i; + struct file_struct *file; if (verbose > 2) - fprintf(stderr,"send_files starting\n"); + fprintf(FERROR,"send_files starting\n"); setup_nonblocking(f_in,f_out); @@ -626,15 +637,17 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) i = read_int(f_in); if (i == -1) break; + file = &flist->files[i]; + fname[0] = 0; - if (flist->files[i].dir) { - strcpy(fname,flist->files[i].dir); + if (file->dir) { + strcpy(fname,file->dir); strcat(fname,"/"); } - strcat(fname,flist->files[i].name); + strcat(fname,file->name); if (verbose > 2) - fprintf(stderr,"send_files(%d,%s)\n",i,fname); + fprintf(FERROR,"send_files(%d,%s)\n",i,fname); if (dry_run) { if (!am_server && verbose) @@ -645,20 +658,20 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) s = receive_sums(f_in); if (!s) { - fprintf(stderr,"receive_sums failed\n"); + fprintf(FERROR,"receive_sums failed\n"); return -1; } fd = open(fname,O_RDONLY); if (fd == -1) { - fprintf(stderr,"send_files failed to open %s: %s\n", + fprintf(FERROR,"send_files failed to open %s: %s\n", fname,strerror(errno)); continue; } /* map the local file */ if (fstat(fd,&st) != 0) { - fprintf(stderr,"fstat failed : %s\n",strerror(errno)); + fprintf(FERROR,"fstat failed : %s\n",strerror(errno)); return -1; } @@ -669,7 +682,7 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) } if (verbose > 2) - fprintf(stderr,"send_files mapped %s of size %d\n", + fprintf(FERROR,"send_files mapped %s of size %d\n", fname,(int)st.st_size); write_int(f_out,i); @@ -679,7 +692,7 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) write_int(f_out,s->remainder); if (verbose > 2) - fprintf(stderr,"calling match_sums %s\n",fname); + fprintf(FERROR,"calling match_sums %s\n",fname); if (!am_server && verbose) printf("%s\n",fname); @@ -693,11 +706,14 @@ off_t send_files(struct file_list *flist,int f_out,int f_in) free_sums(s); if (verbose > 2) - fprintf(stderr,"sender finished %s\n",fname); + fprintf(FERROR,"sender finished %s\n",fname); total += st.st_size; } + if (verbose > 2) + fprintf(FERROR,"send files finished\n"); + match_report(); write_int(f_out,-1); @@ -713,25 +729,28 @@ void generate_files(int f,struct file_list *flist,char *local_name) int i; if (verbose > 2) - fprintf(stderr,"generator starting pid=%d count=%d\n", + fprintf(FERROR,"generator starting pid=%d count=%d\n", (int)getpid(),flist->count); for (i = 0; i < flist->count; i++) { - if (!flist->files[i].name) continue; - if (S_ISDIR(flist->files[i].mode)) { + struct file_struct *file = &flist->files[i]; + if (!file->name) continue; + if (S_ISDIR(file->mode)) { if (dry_run) continue; - if (mkdir(flist->files[i].name,flist->files[i].mode) != 0 && + if (mkdir(file->name,file->mode) != 0 && errno != EEXIST) { - fprintf(stderr,"mkdir %s : %s\n", - flist->files[i].name,strerror(errno)); + fprintf(FERROR,"mkdir %s : %s\n", + file->name,strerror(errno)); } continue; } - recv_generator(local_name?local_name:flist->files[i].name, + recv_generator(local_name?local_name:file->name, flist,i,f); } write_int(f,-1); write_flush(f); if (verbose > 2) - fprintf(stderr,"generator wrote %d\n",write_total()); + fprintf(FERROR,"generator wrote %d\n",write_total()); } + + diff --git a/rsync.h b/rsync.h index 3220e462..45e1e7f3 100644 --- a/rsync.h +++ b/rsync.h @@ -25,7 +25,7 @@ #define FILE_VALID 1 #define SAME_MODE (1<<1) -#define SAME_DEV (1<<2) +#define SAME_RDEV (1<<2) #define SAME_UID (1<<3) #define SAME_GID (1<<4) #define SAME_DIR (1<<5) @@ -38,13 +38,15 @@ #define MIN_PROTOCOL_VERSION 10 #define MAX_PROTOCOL_VERSION 20 +#define SPARSE_WRITE_SIZE (4*1024) +#define WRITE_SIZE (32*1024) #define CHUNK_SIZE (32*1024) #define MAX_MAP_SIZE (4*1024*1024) #define BLOCKING_TIMEOUT 10 -/* do we try to create sparse files */ -#define SPARSE_FILES 1 +#define FERROR stderr +#define FINFO (am_server?stderr:stdout) #include "config.h" @@ -175,7 +177,9 @@ struct file_struct { time_t modtime; off_t length; mode_t mode; + ino_t inode; dev_t dev; + dev_t rdev; uid_t uid; gid_t gid; char *name; @@ -250,6 +254,7 @@ extern int errno; #endif #define SUPPORT_LINKS (HAVE_READLINK && defined(S_ISLNK)) +#define SUPPORT_HARD_LINKS HAVE_LINK #ifndef S_ISLNK #define S_ISLNK(x) 0 diff --git a/util.c b/util.c index ff40b884..f9985ef2 100644 --- a/util.c +++ b/util.c @@ -78,7 +78,7 @@ char *map_ptr(char *buf,off_t offset,int len) if (lseek(map_fd,offset,SEEK_SET) != offset || read(map_fd,p,len) != len) { - fprintf(stderr,"EOF in map_ptr!\n"); + fprintf(FERROR,"EOF in map_ptr!\n"); exit_cleanup(1); } @@ -110,14 +110,14 @@ int piped_child(char **command,int *f_in,int *f_out) if (pipe(to_child_pipe) < 0 || pipe(from_child_pipe) < 0) { - fprintf(stderr,"pipe: %s\n",strerror(errno)); + fprintf(FERROR,"pipe: %s\n",strerror(errno)); exit_cleanup(1); } pid = fork(); if (pid < 0) { - fprintf(stderr,"fork: %s\n",strerror(errno)); + fprintf(FERROR,"fork: %s\n",strerror(errno)); exit_cleanup(1); } @@ -127,18 +127,18 @@ int piped_child(char **command,int *f_in,int *f_out) close(to_child_pipe[1]) < 0 || close(from_child_pipe[0]) < 0 || dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { - fprintf(stderr,"Failed to dup/close : %s\n",strerror(errno)); + fprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); exit_cleanup(1); } execvp(command[0], command); - fprintf(stderr,"Failed to exec %s : %s\n", + fprintf(FERROR,"Failed to exec %s : %s\n", command[0],strerror(errno)); exit_cleanup(1); } if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { - fprintf(stderr,"Failed to close : %s\n",strerror(errno)); + fprintf(FERROR,"Failed to close : %s\n",strerror(errno)); exit_cleanup(1); } @@ -151,7 +151,7 @@ int piped_child(char **command,int *f_in,int *f_out) void out_of_memory(char *str) { - fprintf(stderr,"out of memory in %s\n",str); + fprintf(FERROR,"out of memory in %s\n",str); exit_cleanup(1); } -- 2.34.1