X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/72914a606ec66f61678c6d077e515f08908e76a3..66203a982b3d249bafda9b9272c4c103c19e4a9b:/flist.c diff --git a/flist.c b/flist.c index c33323ed..14fa5a3f 100644 --- a/flist.c +++ b/flist.c @@ -23,8 +23,6 @@ extern struct stats stats; -extern int csum_length; - extern int verbose; extern int am_server; extern int always_checksum; @@ -44,11 +42,77 @@ extern int preserve_gid; extern int preserve_times; extern int relative_paths; extern int copy_links; +extern int copy_unsafe_links; extern int remote_version; extern int io_error; +extern int sanitize_paths; + +static char topsrcname[MAXPATHLEN]; static struct exclude_struct **local_exclude_list; +static void clean_flist(struct file_list *flist, int strip_root); + + +static void list_file_entry(struct file_struct *f) +{ + char perms[11] = "----------"; + char *perm_map = "rwxrwxrwx"; + int i; + + if (!f->basename) + /* this can happen if duplicate names were removed */ + return; + + for (i=0;i<9;i++) { + if (f->mode & (1<mode)) perms[0] = 'l'; + if (S_ISDIR(f->mode)) perms[0] = 'd'; + if (S_ISBLK(f->mode)) perms[0] = 'b'; + if (S_ISCHR(f->mode)) perms[0] = 'c'; + if (S_ISSOCK(f->mode)) perms[0] = 's'; + if (S_ISFIFO(f->mode)) perms[0] = 'p'; + + if (preserve_links && S_ISLNK(f->mode)) { + rprintf(FINFO,"%s %11.0f %s %s -> %s\n", + perms, + (double)f->length, timestring(f->modtime), + f_name(f), f->link); + } else { + rprintf(FINFO,"%s %11.0f %s %s\n", + perms, + (double)f->length, timestring(f->modtime), f_name(f)); + } +} + + +int readlink_stat(const char *Path, STRUCT_STAT *Buffer, char *Linkbuf) +{ +#if SUPPORT_LINKS + if (copy_links) { + return do_stat(Path, Buffer); + } + if (do_lstat(Path, Buffer) == -1) { + return -1; + } + if (S_ISLNK(Buffer->st_mode)) { + int l; + if ((l = readlink(Path,Linkbuf,MAXPATHLEN-1)) == -1) { + return -1; + } + Linkbuf[l] = 0; + if (copy_unsafe_links && (topsrcname[0] != '\0') && + unsafe_symlink(Linkbuf, topsrcname)) { + return do_stat(Path, Buffer); + } + } + return 0; +#else + return do_stat(Path, Buffer); +#endif +} + int link_stat(const char *Path, STRUCT_STAT *Buffer) { #if SUPPORT_LINKS @@ -87,12 +151,29 @@ static void set_filesystem(char *fname) } +static int to_wire_mode(mode_t mode) +{ + if (S_ISLNK(mode) && (S_IFLNK != 0120000)) { + return (mode & ~(_S_IFMT)) | 0120000; + } + return (int)mode; +} + +static mode_t from_wire_mode(int mode) +{ + if ((mode & (_S_IFMT)) == 0120000 && (S_IFLNK != 0120000)) { + return (mode & ~(_S_IFMT)) | S_IFLNK; + } + return (mode_t)mode; +} + + static void send_directory(int f,struct file_list *flist,char *dir); static char *flist_dir; -void send_file_entry(struct file_struct *file,int f,unsigned base_flags) +static void send_file_entry(struct file_struct *file,int f,unsigned base_flags) { unsigned char flags; static time_t last_time; @@ -145,7 +226,7 @@ void send_file_entry(struct file_struct *file,int f,unsigned base_flags) if (!(flags & SAME_TIME)) write_int(f,(int)file->modtime); if (!(flags & SAME_MODE)) - write_int(f,(int)file->mode); + write_int(f,to_wire_mode(file->mode)); if (preserve_uid && !(flags & SAME_UID)) { add_uid(file->uid); write_int(f,(int)file->uid); @@ -172,7 +253,11 @@ void send_file_entry(struct file_struct *file,int f,unsigned base_flags) #endif if (always_checksum) { - write_buf(f,file->sum,csum_length); + if (remote_version < 21) { + write_buf(f,file->sum,2); + } else { + write_buf(f,file->sum,MD4_SUM_LENGTH); + } } last_mode = file->mode; @@ -181,7 +266,7 @@ void send_file_entry(struct file_struct *file,int f,unsigned base_flags) last_gid = file->gid; last_time = file->modtime; - strlcpy(lastname,fname,MAXPATHLEN-1); + strlcpy(lastname,fname,MAXPATHLEN); lastname[MAXPATHLEN-1] = 0; } @@ -216,19 +301,17 @@ static void receive_file_entry(struct file_struct **fptr, if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry"); - strlcpy(thisname,lastname,l1); + strlcpy(thisname,lastname,l1+1); read_sbuf(f,&thisname[l1],l2); thisname[l1+l2] = 0; - strlcpy(lastname,thisname,MAXPATHLEN-1); + strlcpy(lastname,thisname,MAXPATHLEN); lastname[MAXPATHLEN-1] = 0; clean_fname(thisname); - if (relative_paths && thisname[0] == '/') { - /* strip / off absolute paths in destination */ - memmove(thisname, thisname+1, strlen(thisname)); - if (!thisname[0]) strcpy(thisname,"."); + if (sanitize_paths) { + sanitize_path(thisname, NULL); } if ((p = strrchr(thisname,'/'))) { @@ -252,7 +335,7 @@ static void receive_file_entry(struct file_struct **fptr, file->flags = flags; file->length = read_longint(f); file->modtime = (flags & SAME_TIME) ? last_time : (time_t)read_int(f); - file->mode = (flags & SAME_MODE) ? last_mode : (mode_t)read_int(f); + file->mode = (flags & SAME_MODE) ? last_mode : from_wire_mode(read_int(f)); if (preserve_uid) file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f); if (preserve_gid) @@ -265,6 +348,9 @@ static void receive_file_entry(struct file_struct **fptr, file->link = (char *)malloc(l+1); if (!file->link) out_of_memory("receive_file_entry 2"); read_sbuf(f,file->link,l); + if (sanitize_paths) { + sanitize_path(file->link, file->dirname); + } } #if SUPPORT_HARD_LINKS @@ -277,7 +363,11 @@ static void receive_file_entry(struct file_struct **fptr, if (always_checksum) { file->sum = (char *)malloc(MD4_SUM_LENGTH); if (!file->sum) out_of_memory("md4 sum"); - read_buf(f,file->sum,csum_length); + if (remote_version < 21) { + read_buf(f,file->sum,2); + } else { + read_buf(f,file->sum,MD4_SUM_LENGTH); + } } last_mode = file->mode; @@ -319,22 +409,28 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st) return (st2.st_dev != filesystem_dev); } -static struct file_struct *make_file(char *fname) +/* create a file_struct for a named file */ +struct file_struct *make_file(int f, char *fname) { struct file_struct *file; STRUCT_STAT st; char sum[SUM_LENGTH]; char *p; char cleaned_name[MAXPATHLEN]; + char linkbuf[MAXPATHLEN]; + extern int delete_excluded; - strlcpy(cleaned_name, fname, MAXPATHLEN-1); + strlcpy(cleaned_name, fname, MAXPATHLEN); cleaned_name[MAXPATHLEN-1] = 0; clean_fname(cleaned_name); + if (sanitize_paths) { + sanitize_path(cleaned_name, NULL); + } fname = cleaned_name; memset(sum,0,SUM_LENGTH); - if (link_stat(fname,&st) != 0) { + if (readlink_stat(fname,&st,linkbuf) != 0) { io_error = 1; rprintf(FERROR,"%s: %s\n", fname,strerror(errno)); @@ -351,11 +447,12 @@ static struct file_struct *make_file(char *fname) return NULL; } - if (!match_file_name(fname,&st)) + /* f is set to -1 when calculating deletion file list */ + if (((f != -1) || !delete_excluded) && !match_file_name(fname,&st)) return NULL; if (verbose > 2) - rprintf(FINFO,"make_file(%s)\n",fname); + rprintf(FINFO,"make_file(%d,%s)\n",f,fname); file = (struct file_struct *)malloc(sizeof(*file)); if (!file) out_of_memory("make_file"); @@ -390,16 +487,7 @@ static struct file_struct *make_file(char *fname) #if SUPPORT_LINKS if (S_ISLNK(st.st_mode)) { - int l; - char lnk[MAXPATHLEN]; - if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) { - io_error=1; - rprintf(FERROR,"readlink %s : %s\n", - fname,strerror(errno)); - return NULL; - } - lnk[l] = 0; - file->link = strdup(lnk); + file->link = strdup(linkbuf); } #endif @@ -436,12 +524,12 @@ static struct file_struct *make_file(char *fname) -static void send_file_name(int f,struct file_list *flist,char *fname, +void send_file_name(int f,struct file_list *flist,char *fname, int recursive, unsigned base_flags) { struct file_struct *file; - file = make_file(fname); + file = make_file(f,fname); if (!file) return; @@ -488,7 +576,7 @@ static void send_directory(int f,struct file_list *flist,char *dir) return; } - strlcpy(fname,dir,MAXPATHLEN-1); + strlcpy(fname,dir,MAXPATHLEN); l = strlen(fname); if (fname[l-1] != '/') { if (l == MAXPATHLEN-1) { @@ -497,11 +585,13 @@ static void send_directory(int f,struct file_list *flist,char *dir) closedir(d); return; } - strlcat(fname,"/", MAXPATHLEN-1); + strlcat(fname,"/", MAXPATHLEN); l++; } p = fname + strlen(fname); + local_exclude_list = NULL; + if (cvs_exclude) { if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) { strcpy(p,".cvsignore"); @@ -517,10 +607,14 @@ static void send_directory(int f,struct file_list *flist,char *dir) if (strcmp(dname,".")==0 || strcmp(dname,"..")==0) continue; - strlcpy(p,dname,MAXPATHLEN-(l+1)); + strlcpy(p,dname,MAXPATHLEN-l); send_file_name(f,flist,fname,recurse,0); } + if (local_exclude_list) { + add_exclude_list("!", &local_exclude_list, 0); + } + closedir(d); } @@ -530,7 +624,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) { int i,l; STRUCT_STAT st; - char *p,*dir; + char *p,*dir,*olddir; char lastpath[MAXPATHLEN]=""; struct file_list *flist; int64 start_write; @@ -556,14 +650,22 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) } for (i=0;i= 17 then send the io_error flag */ if (f != -1 && remote_version >= 17) { - write_int(f, io_error); + extern int module_id; + write_int(f, lp_ignore_errors(module_id)? 0 : io_error); } if (f != -1) { @@ -678,6 +791,7 @@ struct file_list *recv_file_list(int f) struct file_list *flist; unsigned char flags; int64 start_read; + extern int list_only; if (verbose && recurse && !am_server) { rprintf(FINFO,"receiving file list ... "); @@ -728,7 +842,7 @@ struct file_list *recv_file_list(int f) if (verbose > 2) rprintf(FINFO,"received %d names\n",flist->count); - clean_flist(flist); + clean_flist(flist, relative_paths); if (verbose && recurse && !am_server) { rprintf(FINFO,"done\n"); @@ -741,9 +855,22 @@ struct file_list *recv_file_list(int f) /* if protocol version is >= 17 then recv the io_error flag */ if (f != -1 && remote_version >= 17) { - io_error |= read_int(f); + extern int module_id; + if (lp_ignore_errors(module_id)) { + read_int(f); + } else { + io_error |= read_int(f); + } } + if (list_only) { + int i; + for (i=0;icount;i++) { + list_file_entry(flist->files[i]); + } + } + + if (verbose > 2) rprintf(FINFO,"recv_file_list done\n"); @@ -795,7 +922,7 @@ int flist_find(struct file_list *flist,struct file_struct *f) /* * free up one file */ -static void free_file(struct file_struct *file) +void free_file(struct file_struct *file) { if (!file) return; if (file->basename) free(file->basename); @@ -826,7 +953,7 @@ void flist_free(struct file_list *flist) * This routine ensures we don't have any duplicate names in our file list. * duplicate names can cause corruption because of the pipelining */ -void clean_flist(struct file_list *flist) +static void clean_flist(struct file_list *flist, int strip_root) { int i; @@ -848,6 +975,37 @@ void clean_flist(struct file_list *flist) free_file(flist->files[i]); } } + + if (strip_root) { + /* we need to strip off the root directory in the case + of relative paths, but this must be done _after_ + the sorting phase */ + for (i=0;icount;i++) { + if (flist->files[i]->dirname && + flist->files[i]->dirname[0] == '/') { + memmove(&flist->files[i]->dirname[0], + &flist->files[i]->dirname[1], + strlen(flist->files[i]->dirname)); + } + + if (flist->files[i]->dirname && + !flist->files[i]->dirname[0]) { + flist->files[i]->dirname = NULL; + } + } + } + + + if (verbose <= 3) return; + + for (i=0;icount;i++) { + rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%.0f\n", + getpid(), i, + NS(flist->files[i]->dirname), + NS(flist->files[i]->basename), + flist->files[i]->mode, + (double)flist->files[i]->length); + } } @@ -865,9 +1023,11 @@ char *f_name(struct file_struct *f) n = (n+1)%10; if (f->dirname) { - slprintf(p, MAXPATHLEN-1, "%s/%s", f->dirname, f->basename); + strlcpy(p, f->dirname, MAXPATHLEN); + strlcat(p, "/", MAXPATHLEN); + strlcat(p, f->basename, MAXPATHLEN); } else { - strlcpy(p, f->basename, MAXPATHLEN-1); + strlcpy(p, f->basename, MAXPATHLEN); } return p;