diff -u -r --new-file --exclude=CVS rsync-1.6.8/Makefile.in rsync-1.6.9/Makefile.in --- rsync-1.6.8/Makefile.in Wed Dec 17 11:10:22 1997 +++ rsync-1.6.9/Makefile.in Tue Jan 13 19:40:56 1998 @@ -7,12 +7,13 @@ INSTALL_MAN=$(prefix)/man LIBS=@LIBS@ -CC=@CC@ +CC=@CC@ CFLAGS=@CFLAGS@ - + INSTALLCMD=@INSTALL@ -SRC=@srcdir@ +VPATH=@srcdir@ +srcdir=@srcdir@ SHELL=/bin/sh @@ -20,19 +21,21 @@ .SUFFIXES: .c .o LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o -OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o -OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o $(LIBOBJ) +OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o +OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o uidlist.o $(LIBOBJ) .c.o: - $(CC) $(CFLAGS) -c $*.c -o $*.o + $(CC) -I$(srcdir) $(CFLAGS) -c $*.c -o $*.o all: rsync install: all + -mkdir -p ${INSTALL_BIN} ${INSTALLCMD} -m 755 rsync ${INSTALL_BIN} - ${INSTALLCMD} -m 644 rsync.1 ${INSTALL_MAN}/man1 + -mkdir -p ${INSTALL_MAN}/man1 + ${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${INSTALL_MAN}/man1 -rsync: $(OBJS) +rsync: $(OBJS) $(CC) $(CFLAGS) -o rsync $(OBJS) $(LIBS) proto: @@ -41,7 +44,7 @@ clean: rm -f *~ $(OBJS) rsync config.cache config.log config.status -dist: +dist: tar --exclude-from .ignore -czf dist.tar.gz . -mkdir rsync-$(VERSION) (cd rsync-$(VERSION) ; tar xzf ../dist.tar.gz) diff -u -r --new-file --exclude=CVS rsync-1.6.8/cvs.log rsync-1.6.9/cvs.log --- rsync-1.6.8/cvs.log Sun Dec 28 22:28:29 1997 +++ rsync-1.6.9/cvs.log Tue Jan 13 19:44:08 1998 @@ -540,3 +540,278 @@ Log Message: preparing for release of 1.6.8 + +**************************************** +Date: Tuesday December 30, 1997 @ 10:54 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv24821 + +Modified Files: + main.c +Log Message: +fixed the --suffix option. It wasn't being propogated to the remote +end in the server_options() function. + + + + +**************************************** +Date: Tuesday December 30, 1997 @ 17:37 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv17613 + +Modified Files: + flist.c rsync.c +Log Message: +buffer overflow patches from mhpower@mit.edu (Matt Power) + + + +**************************************** +Date: Wednesday December 31, 1997 @ 16:39 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv184 + +Modified Files: + rsync.c +Log Message: +simplified the logic of whether to skip a file or not. The -c +(always_checksum) option is probably now more useful. + + + + +**************************************** +Date: Wednesday December 31, 1997 @ 16:48 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv8654 + +Modified Files: + io.c proto.h +Log Message: +removed the read_write() call, it's not used anywhere + + + +**************************************** +Date: Thursday January 1, 1998 @ 15:53 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv18811 + +Modified Files: + hlink.c +Log Message: + +yet *another* hard link bug. How many bugs can I have packed into those +few lines of code?? + +The fix is simple, as usual. Here is the patch in case anyone doesn't +want to wait for the next release: + +--- hlink.c 1997/12/28 22:13:41 1.6 ++++ hlink.c 1998/01/01 04:52:24 +@@ -80,7 +80,10 @@ + while (low != high) { + int mid = (low+high)/2; + ret = hlink_compare(&hlink_list[mid],file); +- if (ret == 0) break; ++ if (ret == 0) { ++ low = mid; ++ break; ++ } + if (ret > 0) + high=mid; + else + + + +**************************************** +Date: Monday January 5, 1998 @ 23:30 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv12304 + +Modified Files: + Makefile.in flist.c rsync.1 +Log Message: +cosmetic changes only + +- minor correction to --update docs + +- don't print "building file list" stuff when building a local file +list for use in the --delete code. + +- remove some spaces at the end of lines in Makefile.in + + + + +**************************************** +Date: Tuesday January 6, 1998 @ 16:53 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv25095 + +Modified Files: + flist.c rsync.c rsync.h +Log Message: + +fixed another --delete bug + +This one affected directory structures where one directory name is a +prefix for another directory name, for example if you have 2 top-level +directories called "drivers" and "drivers.new". In this case rsync +would delete files that should not have been deleted. + + + + +**************************************** +Date: Tuesday January 13, 1998 @ 15:57 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv26963 + +Modified Files: + Makefile.in flist.c main.c proto.h rsync.1 rsync.h version.h +Added Files: + uidlist.c +Log Message: + +This implements uid/gid mapping. A map of uids/gids and the +corresponding user/group names is sent after the file list and is used +by the destination system to map to the same names. This allows +transfers between systems that have different uid/gid maps. + +The old behaviour can be selected using the --numeric-ids option. + +The special uid 0 and the special group id 0 are never mapped, they +are always sent as numeric ids. + + + + +**************************************** +Date: Tuesday January 13, 1998 @ 17:16 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv4646 + +Modified Files: + Makefile.in +Log Message: + +patch from pinard@iro.umontreal.ca to fix building the binaries in a +different directory. + +As he points out (in PR#353) the lack of a Makefile in lib/ makes +things a little tricky. We should probably move to automake sometime, +if only I could work out exactly how to use it :-) + + + + +**************************************** +Date: Tuesday January 13, 1998 @ 18:35 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv24039 + +Modified Files: + main.c proto.h rsync.1 rsync.c util.c +Log Message: + +patch from Alberto Accomazzi to implement +a --temp-dir option. This allows the user to specify that temporary +files are to be created in a different directory, which is useful when +the target filesystem doesn't have enough room for 2 copies of a file. + +Alberto, I made some changes to the logic of your patch. Please let me +know if you don't like the way I did it. + + + +**************************************** +Date: Tuesday January 13, 1998 @ 18:43 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv5396 + +Modified Files: + rsync.1 +Log Message: + +modified the man page to make it clear how things differ when you add +a / to the end of a source directory name. + + + +**************************************** +Date: Tuesday January 13, 1998 @ 19:19 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv26821 + +Modified Files: + rsync.c +Log Message: + +only set the file permissions and date on a file if the rename was +successful. Otherwise a 2nd rsync after the error has been fixes might +not update the file! Thanks to Brian Whittaker for pointing this out. + +Brian also sent some other useful patches in that I haven't integrated +yet. + + + +**************************************** +Date: Tuesday January 13, 1998 @ 19:26 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv5557 + +Modified Files: + rsync.1 rsync.c +Log Message: + +change --update to skip files if they have a date later than (as +opposed to later than or equal to) the source file. This means that +using -u will still allow permissions to be updated when the files +have the same date. (problem pointed out by pinard@iro.umontreal.ca) + + + +**************************************** +Date: Tuesday January 13, 1998 @ 19:30 +Author: tridge + +Update of /data/cvs/rsync +In directory samba:/tmp/cvs-serv6142 + +Modified Files: + Makefile.in +Log Message: + +create the install directories if necessary. Requested by +harald.meland@usit.uio.no + + diff -u -r --new-file --exclude=CVS rsync-1.6.8/flist.c rsync-1.6.9/flist.c --- rsync-1.6.8/flist.c Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/flist.c Tue Jan 13 19:40:56 1998 @@ -43,6 +43,7 @@ extern int preserve_times; extern int relative_paths; extern int copy_links; +extern int remote_version; static char **local_exclude_list = NULL; @@ -142,10 +143,14 @@ write_int(f,(int)file->modtime); if (!(flags & SAME_MODE)) write_int(f,(int)file->mode); - if (preserve_uid && !(flags & SAME_UID)) - write_int(f,(int)file->uid); - if (preserve_gid && !(flags & SAME_GID)) - write_int(f,(int)file->gid); + if (preserve_uid && !(flags & SAME_UID)) { + add_uid(file->uid); + write_int(f,(int)file->uid); + } + if (preserve_gid && !(flags & SAME_GID)) { + add_gid(file->gid); + write_int(f,(int)file->gid); + } if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV)) write_int(f,(int)file->rdev); @@ -373,14 +378,23 @@ fname[MAXPATHLEN-1]=0; l = strlen(fname); if (fname[l-1] != '/') { + if (l == MAXPATHLEN-1) { + fprintf(FERROR,"skipping long-named directory %s\n",fname); + closedir(d); + return; + } strcat(fname,"/"); l++; } p = fname + strlen(fname); if (cvs_exclude) { - strcpy(p,".cvsignore"); - local_exclude_list = make_exclude_list(fname,NULL,0); + if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) { + strcpy(p,".cvsignore"); + local_exclude_list = make_exclude_list(fname,NULL,0); + } else { + fprintf(FERROR,"cannot cvs-exclude in long-named directory %s\n",fname); + } } for (di=readdir(d); di; di=readdir(d)) { @@ -404,7 +418,7 @@ char dbuf[MAXPATHLEN]; struct file_list *flist; - if (verbose && recurse && !am_server) { + if (verbose && recurse && !am_server && f != -1) { fprintf(FINFO,"building file list ... "); fflush(FINFO); } @@ -488,11 +502,16 @@ write_flush(f); } - if (verbose && recurse && !am_server) + if (verbose && recurse && !am_server && f != -1) fprintf(FINFO,"done\n"); clean_flist(flist); + /* now send the uid/gid list. This was introduced in protocol version 15 */ + if (f != -1 && remote_version >= 15) { + send_uid_list(f); + } + return flist; } @@ -555,6 +574,11 @@ fprintf(FINFO,"done\n"); } + /* now recv the uid/gid list. This was introduced in protocol version 15 */ + if (f != -1 && remote_version >= 15) { + recv_uid_list(f, flist); + } + return flist; oom: @@ -569,16 +593,6 @@ if (!f1->name) return -1; if (!f2->name) return 1; return strcmp(f1->name,f2->name); -} - - -/* we need this function because of the silly way in which duplicate - entries are handled in the file lists - we can't change this - without breaking existing versions */ -static int flist_up(struct file_list *flist, int i) -{ - while (!flist->files[i].name) i++; - return i; } diff -u -r --new-file --exclude=CVS rsync-1.6.8/hlink.c rsync-1.6.9/hlink.c --- rsync-1.6.8/hlink.c Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/hlink.c Tue Jan 13 19:40:56 1998 @@ -80,7 +80,10 @@ while (low != high) { int mid = (low+high)/2; ret = hlink_compare(&hlink_list[mid],file); - if (ret == 0) break; + if (ret == 0) { + low = mid; + break; + } if (ret > 0) high=mid; else diff -u -r --new-file --exclude=CVS rsync-1.6.8/io.c rsync-1.6.9/io.c --- rsync-1.6.8/io.c Tue Dec 16 09:25:34 1997 +++ rsync-1.6.9/io.c Tue Jan 13 19:40:56 1998 @@ -211,27 +211,6 @@ return len; } -int read_write(int fd_in,int fd_out,int size) -{ - static char *buf=NULL; - int bufsize = sparse_files?SPARSE_WRITE_SIZE:WRITE_SIZE; - int total=0; - - if (!buf) { - buf = (char *)malloc(bufsize); - if (!buf) out_of_memory("read_write"); - } - - while (total < size) { - int n = MIN(size-total,bufsize); - read_buf(fd_in,buf,n); - if (write_sparse(fd_out,buf,n) != n) - return total; - total += n; - } - return total; -} - static int writefd(int fd,char *buf,int len) { diff -u -r --new-file --exclude=CVS rsync-1.6.8/main.c rsync-1.6.9/main.c --- rsync-1.6.8/main.c Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/main.c Tue Jan 13 19:40:56 1998 @@ -26,6 +26,7 @@ int block_size=BLOCK_SIZE; char *backup_suffix = BACKUP_SUFFIX; +char *tmpdir = NULL; static char *rsync_path = RSYNC_NAME; @@ -52,6 +53,7 @@ int am_root=0; int orig_umask=0; int relative_paths=0; +int numeric_ids = 0; extern int csum_length; @@ -158,9 +160,22 @@ args[ac++] = bsize; } + if (strcmp(backup_suffix, BACKUP_SUFFIX)) { + args[ac++] = "--suffix"; + args[ac++] = backup_suffix; + } + if (delete_mode) args[ac++] = "--delete"; + if (numeric_ids) + args[ac++] = "--numeric-ids"; + + if (tmpdir) { + args[ac++] = "--temp-dir"; + args[ac++] = tmpdir; + } + *argc = ac; } @@ -429,7 +444,9 @@ fprintf(f," --rsync-path PATH specify path to rsync on the remote machine\n"); fprintf(f,"-C, --cvs-exclude auto ignore files in the same way CVS does\n"); fprintf(f," --delete delete files that don't exist on the sending side\n"); + fprintf(f," --numeric-ids don't map uid/gid values by user/group name\n"); fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n"); + fprintf(f,"-T --temp-dir DIR create temporary files in directory DIR\n"); fprintf(f,"-z, --compress compress file data\n"); fprintf(f," --exclude FILE exclude file FILE\n"); fprintf(f," --exclude-from FILE exclude files listed in FILE\n"); @@ -442,15 +459,16 @@ } enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE, - OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH}; + OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH}; -static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:z"; +static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z"; static struct option long_options[] = { {"version", 0, 0, OPT_VERSION}, {"server", 0, 0, OPT_SERVER}, {"sender", 0, 0, OPT_SENDER}, {"delete", 0, 0, OPT_DELETE}, + {"numeric-ids", 0, 0, OPT_NUMERIC_IDS}, {"exclude", 1, 0, OPT_EXCLUDE}, {"exclude-from",1, 0, OPT_EXCLUDE_FROM}, {"rsync-path", 1, 0, OPT_RSYNC_PATH}, @@ -479,6 +497,7 @@ {"rsh", 1, 0, 'e'}, {"suffix", 1, 0, OPT_SUFFIX}, {"block-size", 1, 0, 'B'}, + {"temp-dir", 1, 0, 'T'}, {"compress", 0, 0, 'z'}, {0,0,0,0}}; @@ -544,6 +563,10 @@ delete_mode = 1; break; + case OPT_NUMERIC_IDS: + numeric_ids = 1; + break; + case OPT_EXCLUDE: add_exclude(optarg); break; @@ -666,6 +689,10 @@ case 'B': block_size = atoi(optarg); break; + + case 'T': + tmpdir = optarg; + break; case 'z': do_compression = 1; diff -u -r --new-file --exclude=CVS rsync-1.6.8/proto.h rsync-1.6.9/proto.h --- rsync-1.6.8/proto.h Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/proto.h Tue Jan 13 19:40:56 1998 @@ -39,7 +39,6 @@ unsigned char read_byte(int f); int sparse_end(int f); int write_sparse(int f,char *buf,int len); -int read_write(int fd_in,int fd_out,int size); void write_int(int f,int x); void write_buf(int f,char *buf,int len); void write_byte(int f,unsigned char c); @@ -59,6 +58,10 @@ int n,int toklen); int recv_token(int f,char **data); void see_token(char *data, int toklen); +void add_uid(uid_t uid); +void add_gid(gid_t gid); +void send_uid_list(int f); +void recv_uid_list(int f, struct file_list *flist); int num_waiting(int fd); struct map_struct *map_file(int fd,off_t len); char *map_ptr(struct map_struct *map,off_t offset,int len); @@ -68,3 +71,6 @@ int set_modtime(char *fname,time_t modtime); int set_blocking(int fd, int set); int create_directory_path(char *fname); +int full_write(int desc, char *ptr, int len); +int safe_read(int desc, char *ptr, int len); +int copy_file(char *source, char *dest, mode_t mode); diff -u -r --new-file --exclude=CVS rsync-1.6.8/rsync.1 rsync-1.6.9/rsync.1 --- rsync-1.6.8/rsync.1 Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/rsync.1 Tue Jan 13 19:40:56 1998 @@ -76,6 +76,15 @@ in the transfer. Additionally compression will be used to reduce the size of data portions of the transfer. + rsync -avz foo:src/bar/ /data/tmp + +With a trailing slash on the source this behaviour changes to transfer +all files from the directory src/bar on the machine foo into the +/data/tmp/. With a traling / on a source name it means "copy the +contents of this directory". Without a trailing slash it means "copy +the directory". This difference becomes particularly important when +using the --delete option. + You can also use rsync in local-only mode, where both the source and destination don't have a ':' in the name. In this case it behaves like an improved copy command. @@ -195,7 +204,7 @@ .B -u, --update .RS 3 This forces rsync to skip any files for which the destination file -already exists and is newer than the source file. +already exists and has a date later than the source file. .RE .B -l, --links @@ -393,6 +402,14 @@ before it fails) but with smaller values the risk is higher. .RE +.B -T, --temp-dir DIR +.RS 3 +This options instructs rsync to use DIR as a scratch directory when +creating a temporary copies of the files transferred on the +receiving side. The default behaviour is to create the temporary +files in the receiving directory. +.RE + .B -z, --compress .RS 3 With this option, rsync compresses any data from the source file(s) @@ -406,9 +423,22 @@ information sent for matching data blocks. .RE -.SH BUGS +.B --numeric-ids +.RS 3 +With this option rsync will transfer numeric group and user ids rather +than using user and group names and mapping them at both ends. -user ids and group ids are transferred using their numerical value +By default rsync will use the user name and group name to determine +what ownership to give files. The special uid 0 and the special group +0 and never mapped via user/group names even if the --numeric-ids +option is not specified. + +If a user or group name does not exist on the destination system then +the numeric id from the source system is used instead. + +.RE + +.SH BUGS times are transferred as unix time_t values diff -u -r --new-file --exclude=CVS rsync-1.6.8/rsync.c rsync-1.6.9/rsync.c --- rsync-1.6.8/rsync.c Sun Dec 28 22:28:17 1997 +++ rsync-1.6.9/rsync.c Tue Jan 13 19:40:56 1998 @@ -29,6 +29,7 @@ extern int remote_version; extern char *backup_suffix; +extern char *tmpdir; extern int whole_file; extern int block_size; @@ -252,13 +253,36 @@ } +/* choose whether to skip a particular file */ +static int skip_file(char *fname, + struct file_struct *file, struct stat *st) +{ + if (st->st_size != file->length) { + return 0; + } + + /* if always checksum is set then we use the checksum instead + of the file time to determine whether to sync */ + if (always_checksum && S_ISREG(st->st_mode)) { + char sum[MD4_SUM_LENGTH]; + file_checksum(fname,sum,st->st_size); + return (memcmp(sum,file->sum,csum_length) == 0); + } + + if (ignore_times) { + return 0; + } + + return (st->st_mtime == file->modtime); +} + + void recv_generator(char *fname,struct file_list *flist,int i,int f_out) { int fd; struct stat st; struct map_struct *buf; struct sum_struct *s; - char sum[MD4_SUM_LENGTH]; int statret; struct file_struct *file = &flist->files[i]; @@ -382,20 +406,13 @@ return; } - if (update_only && st.st_mtime >= file->modtime) { + if (update_only && st.st_mtime > file->modtime) { if (verbose > 1) fprintf(FERROR,"%s is newer\n",fname); return; } - if (always_checksum && S_ISREG(st.st_mode)) { - file_checksum(fname,sum,st.st_size); - } - - if (st.st_size == file->length && - ((!ignore_times && st.st_mtime == file->modtime) || - (always_checksum && S_ISREG(st.st_mode) && - memcmp(sum,file->sum,csum_length) == 0))) { + if (skip_file(fname, file, &st)) { set_perms(fname,file,&st,1); return; } @@ -535,6 +552,61 @@ } +/* yuck! This function wouldn't have been necessary if I had the sorting + algorithm right. Unfortunately fixing the sorting algorithm would introduce + a backward incompatibility as file list indexes are sent over the link. + + The aim is to see if a directory has already had the deletion algorithm applied + to it (due to recursion), and if so to skip it. The bisection is to + prevent this being an n^2 algorithm */ +static int delete_already_done(struct file_list *flist,int j) +{ + int low=0,high=j-1; + char *name; + char *p; + + if (j == 0) return 0; + + name = strdup(flist->files[j].name); + + if (!name) { + fprintf(FERROR,"out of memory in delete_already_done"); + exit_cleanup(1); + } + + p = strrchr(name,'/'); + if (!p) { + free(name); + return 0; + } + *p = 0; + + while (low != high) { + int mid = (low+high)/2; + int ret = strcmp(flist->files[flist_up(flist, mid)].name,name); + if (ret == 0) { + free(name); + return 1; + } + if (ret > 0) { + high=mid; + } else { + low=mid+1; + } + } + + low = flist_up(flist, low); + + if (strcmp(flist->files[low].name,name) == 0) { + free(name); + return 1; + } + + free(name); + return 0; +} + + /* this deletes any files on the receiving side that are not present on the sending side. For version 1.6.4 I have changed the behaviour to match more closely what most people seem to expect of this option */ @@ -542,23 +614,22 @@ { struct file_list *local_file_list; int i, j; - char *last_name=NULL; if (cvs_exclude) add_cvs_excludes(); for (j=0;jcount;j++) { + char *name = flist->files[j].name; + if (!S_ISDIR(flist->files[j].mode)) continue; - if (strcmp(flist->files[j].name,".")==0) continue; - if (last_name && - flist->files[j].name[strlen(last_name)] == '/' && - strncmp(flist->files[j].name,last_name, strlen(last_name))==0) - continue; - last_name = flist->files[j].name; - if (!(local_file_list = send_file_list(-1,1,&last_name))) + + if (delete_already_done(flist, j)) continue; + + if (!(local_file_list = send_file_list(-1,1,&name))) continue; + if (verbose > 1) - fprintf(FINFO,"deleting in %s\n", last_name); + fprintf(FINFO,"deleting in %s\n", name); for (i=local_file_list->count-1;i>=0;i--) { if (!local_file_list->files[i].name) continue; @@ -674,7 +745,17 @@ close(fd1); continue; } - sprintf(fnametmp,"%s.XXXXXX",fname); + if (tmpdir) { + char *f; + f = strrchr(fname,'/'); + if (f == NULL) + f = fname; + else + f++; + sprintf(fnametmp,"%s/%s.XXXXXX",tmpdir,f); + } else { + sprintf(fnametmp,"%s.XXXXXX",fname); + } if (NULL == mktemp(fnametmp)) { fprintf(FERROR,"mktemp %s failed\n",fnametmp); receive_data(f_in,buf,-1,NULL); @@ -682,10 +763,10 @@ close(fd1); continue; } - fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode); + fd2 = open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); if (fd2 == -1 && relative_paths && errno == ENOENT && create_directory_path(fnametmp) == 0) { - fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode); + fd2 = open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); } if (fd2 == -1) { fprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno)); @@ -727,14 +808,27 @@ /* move tmp file over real file */ if (rename(fnametmp,fname) != 0) { - fprintf(FERROR,"rename %s -> %s : %s\n", - fnametmp,fname,strerror(errno)); - unlink(fnametmp); + if (errno == EXDEV) { + /* rename failed on cross-filesystem link. + Copy the file instead. */ + if (copy_file(fnametmp,fname, file->mode)) { + fprintf(FERROR,"copy %s -> %s : %s\n", + fnametmp,fname,strerror(errno)); + } else { + set_perms(fname,file,NULL,0); + } + unlink(fnametmp); + } else { + fprintf(FERROR,"rename %s -> %s : %s\n", + fnametmp,fname,strerror(errno)); + unlink(fnametmp); + } + } else { + set_perms(fname,file,NULL,0); } cleanup_fname = NULL; - set_perms(fname,file,NULL,0); if (!recv_ok) { if (verbose > 1) @@ -803,6 +897,11 @@ if (file->dir) { strncpy(fname,file->dir,MAXPATHLEN-1); fname[MAXPATHLEN-1] = 0; + if (strlen(fname) == MAXPATHLEN-1) { + fprintf(FERROR, "send_files failed on long-named directory %s\n", + fname); + return -1; + } strcat(fname,"/"); } strncat(fname,file->name,MAXPATHLEN-strlen(fname)); diff -u -r --new-file --exclude=CVS rsync-1.6.8/rsync.h rsync-1.6.9/rsync.h --- rsync-1.6.8/rsync.h Wed Dec 17 11:10:22 1997 +++ rsync-1.6.9/rsync.h Tue Jan 13 19:40:56 1998 @@ -39,7 +39,7 @@ #define SAME_TIME (1<<7) /* update this if you make incompatible changes */ -#define PROTOCOL_VERSION 14 +#define PROTOCOL_VERSION 15 #define MIN_PROTOCOL_VERSION 10 #define MAX_PROTOCOL_VERSION 20 @@ -163,6 +163,10 @@ #include "lib/getopt.h" #endif +/* these are needed for the uid/gid mapping code */ +#include +#include + #ifndef S_IFLNK #define S_IFLNK 0120000 #endif @@ -247,6 +251,16 @@ char *map,*p; int fd,size,p_size,p_offset,p_len; }; + +/* we need this function because of the silly way in which duplicate + entries are handled in the file lists - we can't change this + without breaking existing versions */ +static int flist_up(struct file_list *flist, int i) +{ + while (!flist->files[i].name) i++; + return i; +} + #include "byteorder.h" #include "version.h" diff -u -r --new-file --exclude=CVS rsync-1.6.8/uidlist.c rsync-1.6.9/uidlist.c --- rsync-1.6.8/uidlist.c Thu Jan 1 10:00:00 1970 +++ rsync-1.6.9/uidlist.c Wed Jan 14 02:57:33 1998 @@ -0,0 +1,310 @@ +/* + 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. +*/ + +/* handle the mapping of uid/gid and user/group names between systems. + If the source username/group does not exist on the target then use + the numeric ids. Never do any mapping for uid=0 or gid=0 as these + are special. +*/ + +#include "rsync.h" + +extern int preserve_uid; +extern int preserve_gid; +extern int numeric_ids; + +struct idlist { + struct idlist *next; + int id, id2; + char *name; +}; + +static struct idlist *uidlist; +static struct idlist *gidlist; + +static struct idlist *add_list(int id, char *name) +{ + struct idlist *list = (struct idlist *)malloc(sizeof(list[0])); + if (!list) out_of_memory("add_list"); + list->next = NULL; + list->name = strdup(name); + if (!list->name) out_of_memory("add_list"); + list->id = (int)id; + return list; +} + + + +/* turn a uid into a user name */ +static char *uid_to_name(uid_t uid) +{ + struct passwd *pass = getpwuid(uid); + if (pass) return(pass->pw_name); + return NULL; +} + +/* turn a gid into a group name */ +static char *gid_to_name(gid_t gid) +{ + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + return NULL; +} + + +/* turn a user name into a uid */ +static uid_t name_to_uid(char *name) +{ + struct passwd *pass; + if (!name || !*name) return 0; + pass = getpwnam(name); + if (pass) return(pass->pw_uid); + return 0; +} + +/* turn a group name into a gid */ +static gid_t name_to_gid(char *name) +{ + struct group *grp; + if (!name || !*name) return 0; + grp = getgrnam(name); + if (grp) return(grp->gr_gid); + return 0; +} + +static int map_uid(int id, char *name) +{ + uid_t uid = name_to_uid(name); + if (uid != 0) return uid; + return id; +} + +static int map_gid(int id, char *name) +{ + gid_t gid = name_to_gid(name); + if (gid != 0) return gid; + return id; +} + +/* this function is a definate candidate for a faster algorithm */ +static uid_t match_uid(uid_t uid) +{ + static uid_t last_in, last_out; + struct idlist *list = uidlist; + + if (uid == last_in) return last_out; + + last_in = uid; + + while (list) { + if (list->id == (int)uid) { + last_out = (uid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = uid; + return last_out; +} + +static gid_t match_gid(gid_t gid) +{ + static gid_t last_in, last_out; + struct idlist *list = gidlist; + + if (gid == last_in) return last_out; + + last_in = gid; + + while (list) { + if (list->id == (int)gid) { + last_out = (gid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = gid; + return last_out; +} + +/* add a uid to the list of uids */ +void add_uid(uid_t uid) +{ + struct idlist *list = uidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (uid==0) return; + + if (!list) { + if (!(name = uid_to_name(uid))) return; + uidlist = add_list((int)uid, name); + return; + } + + while (list->next) { + if (list->id == (int)uid) return; + list = list->next; + } + + if (list->id == (int)uid) return; + + if (!(name = uid_to_name(uid))) return; + + list->next = add_list((int)uid, name); +} + +/* add a gid to the list of gids */ +void add_gid(gid_t gid) +{ + struct idlist *list = gidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (gid==0) return; + + if (!list) { + if (!(name = gid_to_name(gid))) return; + gidlist = add_list((int)gid, name); + return; + } + + while (list->next) { + if (list->id == (int)gid) return; + list = list->next; + } + + if (list->id == (int)gid) return; + + if (!(name = gid_to_name(gid))) return; + + list->next = add_list((int)gid, name); +} + + +/* send a complete uid/gid mapping to the peer */ +void send_uid_list(int f) +{ + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* we send sequences of uid/byte-length/name */ + list = uidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + + /* terminate the uid list with a 0 uid. We explicitly exclude + 0 from the list */ + write_int(f, 0); + } + + if (preserve_gid) { + list = gidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + write_int(f, 0); + } +} + +/* recv a complete uid/gid mapping from the peer and map the uid/gid + in the file list to local names */ +void recv_uid_list(int f, struct file_list *flist) +{ + int id, i; + char *name; + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* read the uid list */ + list = uidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + uidlist = add_list(id, name); + list = uidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_uid(id, name); + free(name); + id = read_int(f); + } + } + + + if (preserve_gid) { + /* and the gid list */ + list = gidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + gidlist = add_list(id, name); + list = gidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_gid(id, name); + free(name); + id = read_int(f); + } + } + + if (!uidlist && !gidlist) return; + + /* now convert the uid/gid of all files in the list to the mapped + uid/gid */ + for (i=0;icount;i++) { + if (preserve_uid && flist->files[i].uid != 0) { + flist->files[i].uid = match_uid(flist->files[i].uid); + } + if (preserve_gid && flist->files[i].gid != 0) { + flist->files[i].gid = match_gid(flist->files[i].gid); + } + } +} diff -u -r --new-file --exclude=CVS rsync-1.6.8/util.c rsync-1.6.9/util.c --- rsync-1.6.8/util.c Tue Dec 16 01:43:34 1997 +++ rsync-1.6.9/util.c Tue Jan 13 19:40:56 1998 @@ -251,3 +251,105 @@ } return 0; } + + +/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted. + Return LEN upon success, write's (negative) error code otherwise. + + derived from GNU C's cccp.c. +*/ +int full_write(int desc, char *ptr, int len) +{ + int total_written; + + total_written = 0; + while (len > 0) { + int written = write (desc, ptr, len); + if (written < 0) { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + return written; + } + total_written += written; + ptr += written; + len -= written; + } + return total_written; +} + +/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted. + Return the actual number of bytes read, zero for EOF, or negative + for an error. + + derived from GNU C's cccp.c. */ +int safe_read(int desc, char *ptr, int len) +{ + int n_chars; + + if (len <= 0) + return len; + +#ifdef EINTR + do { + n_chars = read(desc, ptr, len); + } while (n_chars < 0 && errno == EINTR); +#else + n_chars = read(desc, ptr, len); +#endif + + return n_chars; +} + + +/* copy a file - this is used in conjunction with the --temp-dir option */ +int copy_file(char *source, char *dest, mode_t mode) +{ + int ifd; + int ofd; + char buf[1024 * 8]; + int len; /* Number of bytes read into `buf'. */ + + ifd = open(source, O_RDONLY); + if (ifd == -1) { + fprintf(FERROR,"open %s: %s\n", + source,strerror(errno)); + return -1; + } + + if (unlink(dest) && errno != ENOENT) { + fprintf(FERROR,"unlink %s: %s\n", + dest,strerror(errno)); + return -1; + } + + ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); + if (ofd < 0) { + fprintf(FERROR,"open %s: %s\n", + dest,strerror(errno)); + close(ifd); + return -1; + } + + while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) { + if (full_write(ofd, buf, len) < 0) { + fprintf(FERROR,"write %s: %s\n", + dest,strerror(errno)); + close(ifd); + close(ofd); + return -1; + } + } + + close(ifd); + close(ofd); + + if (len < 0) { + fprintf(FERROR,"read %s: %s\n", + source,strerror(errno)); + return -1; + } + + return 0; +} diff -u -r --new-file --exclude=CVS rsync-1.6.8/version.h rsync-1.6.9/version.h --- rsync-1.6.8/version.h Sun Dec 28 22:28:19 1997 +++ rsync-1.6.9/version.h Tue Jan 13 19:44:01 1998 @@ -1 +1 @@ -#define VERSION "1.6.8" +#define VERSION "1.6.9"