X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/7a16e12207b65010dc2f0c05dc87a9690c9ed87b..bec617b934dc2ef90b7acd1c7ef4b5db74821e91:/flist.c diff --git a/flist.c b/flist.c index 29d75cab..30e88ab4 100644 --- a/flist.c +++ b/flist.c @@ -546,7 +546,7 @@ static struct file_struct *receive_file_entry(struct file_list *flist, rprintf(FERROR, "overflow: flags=0x%x l1=%d l2=%d lastname=%s\n", flags, l1, l2, safe_fname(lastname)); - overflow("receive_file_entry"); + overflow_exit("receive_file_entry"); } strlcpy(thisname, lastname, l1 + 1); @@ -611,7 +611,7 @@ static struct file_struct *receive_file_entry(struct file_list *flist, if (linkname_len <= 0 || linkname_len > MAXPATHLEN) { rprintf(FERROR, "overflow: linkname_len=%d\n", linkname_len - 1); - overflow("receive_file_entry"); + overflow_exit("receive_file_entry"); } } else @@ -1120,11 +1120,21 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (l == 2 && fname[0] == '.') { /* Turn "./" into just "." rather than "./." */ fname[1] = '\0'; - } else if (l < MAXPATHLEN) { + } else { + if (l + 1 >= MAXPATHLEN) + overflow_exit("send_file_list"); fname[l++] = '.'; fname[l] = '\0'; } is_dot_dir = 1; + } else if (l > 1 && fname[l-1] == '.' && fname[l-2] == '.' + && (l == 2 || fname[l-3] == '/')) { + if (l + 2 >= MAXPATHLEN) + overflow_exit("send_file_list"); + fname[l++] = '/'; + fname[l++] = '.'; + fname[l] = '\0'; + is_dot_dir = 1; } else { is_dot_dir = fname[l-1] == '.' && (l == 1 || fname[l-2] == '/'); @@ -1149,7 +1159,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (!relative_paths) { p = strrchr(fname, '/'); if (p) { - *p = 0; + *p = '\0'; if (p == fname) dir = "/"; else @@ -1157,10 +1167,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) fname = p + 1; } } else if (implied_dirs && (p=strrchr(fname,'/')) && p != fname) { - /* this ensures we send the intermediate directories, - thus getting their permissions right */ + /* Send the implied directories at the start of the + * source spec, so we get their permissions right. */ char *lp = lastpath, *fn = fname, *slash = fname; - *p = 0; + *p = '\0'; /* Skip any initial directories in our path that we * have in common with lastpath. */ while (*fn && *lp == *fn) { @@ -1175,13 +1185,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) copy_links = copy_unsafe_links; xfer_dirs = 1; while ((slash = strchr(slash+1, '/')) != 0) { - *slash = 0; + *slash = '\0'; send_file_name(f, flist, fname, 0); *slash = '/'; } copy_links = save_copy_links; xfer_dirs = save_xfer_dirs; - *p = 0; + *p = '\0'; strlcpy(lastpath, fname, sizeof lastpath); *p = '/'; } @@ -1461,8 +1471,12 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) { int i, prev_i = 0; - if (!flist || flist->count == 0) + if (!flist) return; + if (flist->count == 0) { + flist->high = -1; + return; + } sorting_flist = flist; qsort(flist->files, flist->count, @@ -1514,8 +1528,8 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) } /* Make sure that if we unduplicate '.', that we don't * lose track of a user-specified top directory. */ - if (flist->files[drop]->flags & FLAG_TOP_DIR) - flist->files[keep]->flags |= FLAG_TOP_DIR; + flist->files[keep]->flags |= flist->files[drop]->flags + & (FLAG_TOP_DIR|FLAG_DEL_HERE); clear_file(drop, flist); @@ -1670,8 +1684,13 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) break; case s_SLASH: type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; - state1 = s_BASE; c1 = (uchar*)f1->basename; + if (type1 == t_PATH && *c1 == '.' && !c1[1]) { + type1 = t_ITEM; + state1 = s_TRAILING; + c1 = (uchar*)""; + } else + state1 = s_BASE; break; case s_BASE: state1 = s_TRAILING; @@ -1695,8 +1714,13 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) break; case s_SLASH: type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; - state2 = s_BASE; c2 = (uchar*)f2->basename; + if (type2 == t_PATH && *c2 == '.' && !c2[1]) { + type2 = t_ITEM; + state2 = s_TRAILING; + c2 = (uchar*)""; + } else + state2 = s_BASE; break; case s_BASE: state2 = s_TRAILING;