X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/7d6879328a26775fd680fc8291246c69e1c1c43c..6a7cc46cb279b9dbf12977177330aeebb912aa34:/flist.c diff --git a/flist.c b/flist.c index f6ae2240..8bc3ab37 100644 --- a/flist.c +++ b/flist.c @@ -57,7 +57,7 @@ extern int relative_paths; extern int implied_dirs; extern int copy_links; extern int copy_unsafe_links; -extern int remote_version; +extern int protocol_version; extern int io_error; extern int sanitize_paths; @@ -262,19 +262,26 @@ static int check_exclude_file(char *fname, int is_dir, int exclude_level) if (exclude_level == NO_EXCLUDES) return 0; #endif - if (fname && fname[0] == '.' && !fname[1]) { + if (fname) { /* never exclude '.', even if somebody does --exclude '*' */ - return 0; + if (fname[0] == '.' && !fname[1]) + return 0; + /* Handle the -R version of the '.' dir. */ + if (fname[0] == '/') { + int len = strlen(fname); + if (fname[len-1] == '.' && fname[len-2] == '/') + return 0; + } } - if (server_exclude_list && - check_exclude(server_exclude_list, fname, is_dir)) + if (server_exclude_list + && check_exclude(server_exclude_list, fname, is_dir)) return 1; if (exclude_level != ALL_EXCLUDES) return 0; if (exclude_list && check_exclude(exclude_list, fname, is_dir)) return 1; - if (local_exclude_list && - check_exclude(local_exclude_list, fname, is_dir)) + if (local_exclude_list + && check_exclude(local_exclude_list, fname, is_dir)) return 1; return 0; } @@ -439,7 +446,7 @@ static void send_file_entry(struct file_struct *file, int f, #if SUPPORT_HARD_LINKS if (preserve_hard_links && S_ISREG(file->mode)) { - if (remote_version < 26) { + if (protocol_version < 26) { /* 32-bit dev_t and ino_t */ write_int(f, (int) file->dev); write_int(f, (int) file->inode); @@ -452,7 +459,7 @@ static void send_file_entry(struct file_struct *file, int f, #endif if (always_checksum) { - if (remote_version < 21) { + if (protocol_version < 21) { write_buf(f, file->sum, 2); } else { write_buf(f, file->sum, MD4_SUM_LENGTH); @@ -572,7 +579,7 @@ static void receive_file_entry(struct file_struct **fptr, } #if SUPPORT_HARD_LINKS if (preserve_hard_links && S_ISREG(file->mode)) { - if (remote_version < 26) { + if (protocol_version < 26) { file->dev = read_int(f); file->inode = read_int(f); } else { @@ -586,7 +593,7 @@ static void receive_file_entry(struct file_struct **fptr, file->sum = (char *) malloc(MD4_SUM_LENGTH); if (!file->sum) out_of_memory("md4 sum"); - if (remote_version < 21) { + if (protocol_version < 21) { read_buf(f, file->sum, 2); } else { read_buf(f, file->sum, MD4_SUM_LENGTH); @@ -686,8 +693,8 @@ struct file_struct *make_file(char *fname, struct string_area **ap, } } io_error = 1; - rprintf(FERROR, "readlink %s: %s\n", - fname, strerror(save_errno)); + rprintf(FERROR, "readlink %s failed: %s\n", + full_fname(fname), strerror(save_errno)); return NULL; } @@ -836,7 +843,8 @@ static void send_directory(int f, struct file_list *flist, char *dir) d = opendir(dir); if (!d) { io_error = 1; - rprintf(FERROR, "opendir(%s): %s\n", dir, strerror(errno)); + rprintf(FERROR, "opendir %s failed: %s\n", + full_fname(dir), strerror(errno)); return; } @@ -845,9 +853,8 @@ static void send_directory(int f, struct file_list *flist, char *dir) if (fname[l - 1] != '/') { if (l == MAXPATHLEN - 1) { io_error = 1; - rprintf(FERROR, - "skipping long-named directory %s\n", - fname); + rprintf(FERROR, "skipping long-named directory: %s\n", + full_fname(fname)); closedir(d); return; } @@ -866,18 +873,23 @@ static void send_directory(int f, struct file_list *flist, char *dir) io_error = 1; rprintf(FINFO, "cannot cvs-exclude in long-named directory %s\n", - fname); + full_fname(fname)); } } - for (di = readdir(d); di; di = readdir(d)) { + for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { char *dname = d_name(di); - if (dname[0] == '.' && (dname[1] == '\0' || - (dname[1] == '.' && dname[2] == '\0'))) + if (dname[0] == '.' && (dname[1] == '\0' + || (dname[1] == '.' && dname[2] == '\0'))) continue; strlcpy(p, dname, MAXPATHLEN - l); send_file_name(f, flist, fname, recurse, 0); } + if (errno) { + io_error = 1; + rprintf(FERROR, "readdir(%s): (%d) %s\n", + dir, errno, strerror(errno)); + } if (local_exclude_list) free_exclude_list(&local_exclude_list); /* Zeros pointer too */ @@ -913,8 +925,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) io_start_buffering(f); if (filesfrom_fd >= 0) { if (argv[0] && !push_dir(argv[0], 0)) { - rprintf(FERROR, "push_dir %s : %s\n", - argv[0], strerror(errno)); + rprintf(FERROR, "push_dir %s failed: %s\n", + full_fname(argv[0]), strerror(errno)); exit_cleanup(RERR_FILESELECT); } use_ff_fd = 1; @@ -938,14 +950,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } l = strlen(fname); - if (l != 1 && fname[l - 1] == '/') { - if ((l == 2) && (fname[0] == '.')) { - /* Turn ./ into just . rather than ./. - This was put in to avoid a problem with - rsync -aR --delete from ./ - The send_file_name() below of ./ was - mysteriously preventing deletes */ - fname[1] = 0; + if (fname[l - 1] == '/') { + if (l == 2 && fname[0] == '.') { + /* Turn "./" into just "." rather than "./." */ + fname[1] = '\0'; } else { strlcat(fname, ".", MAXPATHLEN); } @@ -954,8 +962,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (link_stat(fname, &st) != 0) { if (f != -1) { io_error = 1; - rprintf(FERROR, "link_stat %s : %s\n", - fname, strerror(errno)); + rprintf(FERROR, "link_stat %s failed: %s\n", + full_fname(fname), strerror(errno)); } continue; } @@ -1021,8 +1029,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (!olddir) { io_error = 1; - rprintf(FERROR, "push_dir %s : %s\n", - dir, strerror(errno)); + rprintf(FERROR, "push_dir %s failed: %s\n", + full_fname(dir), strerror(errno)); continue; } @@ -1037,8 +1045,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (olddir != NULL) { flist_dir = NULL; if (pop_dir(olddir) != 0) { - rprintf(FERROR, "pop_dir %s : %s\n", - dir, strerror(errno)); + rprintf(FERROR, "pop_dir %s failed: %s\n", + full_fname(dir), strerror(errno)); exit_cleanup(RERR_FILESELECT); } } @@ -1290,7 +1298,7 @@ void flist_free(struct file_list *flist) */ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) { - int i; + int i, prev_i = 0; char *name, *prev_name = NULL; if (!flist || flist->count == 0) @@ -1301,6 +1309,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) for (i = no_dups? 0 : flist->count; i < flist->count; i++) { if (flist->files[i]->basename) { + prev_i = i; prev_name = f_name(flist->files[i]); break; } @@ -1315,6 +1324,11 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) "removing duplicate name %s from file list %d\n", name, i); } + /* Make sure that if we unduplicate '.', that we don't + * lose track of a user-specified starting point (or + * else deletions will mysteriously fail with -R). */ + if (flist->files[i]->flags & FLAG_DELETE) + flist->files[prev_i]->flags |= FLAG_DELETE; /* it's not great that the flist knows the semantics of * the file memory usage, but i'd rather not add a flag * byte to that struct. @@ -1324,6 +1338,10 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) else free_file(flist->files[i]); } + else + prev_i = i; + /* We set prev_name every iteration to avoid it becoming + * invalid when names[][] in f_name() wraps around. */ prev_name = name; }