X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/5e58e3f9cf3db5c3958fe6505eb59a2f814887fb..c0b134a445a12a98c70313ce18b94858ef9a4b77:/flist.c diff --git a/flist.c b/flist.c index 277750c0..dc283a1f 100644 --- a/flist.c +++ b/flist.c @@ -48,10 +48,12 @@ extern int preserve_links; extern int preserve_hard_links; extern int preserve_perms; extern int preserve_devices; +extern int preserve_specials; extern int preserve_uid; extern int preserve_gid; extern int relative_paths; extern int implied_dirs; +extern int skip_empty_dirs; extern int copy_links; extern int copy_unsafe_links; extern int protocol_version; @@ -74,6 +76,7 @@ unsigned int file_struct_len; static char empty_sum[MD4_SUM_LENGTH]; static int flist_count_offset; +static int max_dir_depth = 0; static void clean_flist(struct file_list *flist, int strip_root, int no_dups); static void output_flist(struct file_list *flist); @@ -343,16 +346,14 @@ static void send_file_entry(struct file_struct *file, int f) flags |= XMIT_SAME_MODE; else mode = file->mode; - if (preserve_devices) { + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) { if (protocol_version < 28) { - if (IS_DEVICE(mode)) { - if (file->u.rdev == rdev) - flags |= XMIT_SAME_RDEV_pre28; - else - rdev = file->u.rdev; - } else - rdev = makedev(0, 0); - } else if (IS_DEVICE(mode)) { + if (file->u.rdev == rdev) + flags |= XMIT_SAME_RDEV_pre28; + else + rdev = file->u.rdev; + } else { rdev = file->u.rdev; if ((uint32)major(rdev) == rdev_major) flags |= XMIT_SAME_RDEV_MAJOR; @@ -361,15 +362,16 @@ static void send_file_entry(struct file_struct *file, int f) if ((uint32)minor(rdev) <= 0xFFu) flags |= XMIT_RDEV_MINOR_IS_SMALL; } - } - if (file->ids->uid == uid) + } else if (protocol_version < 28) + rdev = makedev(0, 0); + if (file->uid == uid) flags |= XMIT_SAME_UID; else - uid = file->ids->uid; - if (file->ids->gid == gid) + uid = file->uid; + if (file->gid == gid) flags |= XMIT_SAME_GID; else - gid = file->ids->gid; + gid = file->gid; if (file->modtime == modtime) flags |= XMIT_SAME_TIME; else @@ -437,7 +439,8 @@ static void send_file_entry(struct file_struct *file, int f) add_gid(gid); write_int(f, gid); } - if (preserve_devices && IS_DEVICE(mode)) { + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) { if (protocol_version < 28) { if (!(flags & XMIT_SAME_RDEV_pre28)) write_int(f, (int)rdev); @@ -577,14 +580,12 @@ static struct file_struct *receive_file_entry(struct file_list *flist, if (preserve_gid && !(flags & XMIT_SAME_GID)) gid = (gid_t)read_int(f); - if (preserve_devices) { + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) { if (protocol_version < 28) { - if (IS_DEVICE(mode)) { - if (!(flags & XMIT_SAME_RDEV_pre28)) - rdev = (dev_t)read_int(f); - } else - rdev = makedev(0, 0); - } else if (IS_DEVICE(mode)) { + if (!(flags & XMIT_SAME_RDEV_pre28)) + rdev = (dev_t)read_int(f); + } else { uint32 rdev_minor; if (!(flags & XMIT_SAME_RDEV_MAJOR)) rdev_major = read_int(f); @@ -594,7 +595,8 @@ static struct file_struct *receive_file_entry(struct file_list *flist, rdev_minor = read_int(f); rdev = makedev(rdev_major, rdev_minor); } - } + } else if (protocol_version < 28) + rdev = makedev(0, 0); #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(mode)) { @@ -622,7 +624,8 @@ static struct file_struct *receive_file_entry(struct file_list *flist, file->modtime = modtime; file->length = file_length; file->mode = mode; - file->ids = id_pair(uid, gid); + file->uid = uid; + file->gid = gid; if (dirname_len) { file->dirname = lastdir = bp; @@ -632,6 +635,8 @@ static struct file_struct *receive_file_entry(struct file_list *flist, bp[-1] = '\0'; lastdir_depth = count_dir_elements(lastdir); file->dir.depth = lastdir_depth + 1; + if (lastdir_depth >= max_dir_depth) + max_dir_depth = lastdir_depth + 1; } else if (dirname) { file->dirname = dirname; /* we're reusing lastname */ file->dir.depth = lastdir_depth + 1; @@ -663,7 +668,8 @@ static struct file_struct *receive_file_entry(struct file_list *flist, memcpy(bp, basename, basename_len); bp += basename_len; - if (preserve_devices && IS_DEVICE(mode)) + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) file->u.rdev = rdev; #ifdef SUPPORT_LINKS @@ -878,7 +884,8 @@ struct file_struct *make_file(char *fname, struct file_list *flist, file->modtime = st.st_mtime; file->length = st.st_size; file->mode = st.st_mode; - file->ids = id_pair(st.st_uid, st.st_gid); + file->uid = st.st_uid; + file->gid = st.st_gid; #ifdef SUPPORT_HARD_LINKS if (flist && flist->hlink_pool) { @@ -914,7 +921,8 @@ struct file_struct *make_file(char *fname, struct file_list *flist, bp += basename_len; #ifdef HAVE_STRUCT_STAT_ST_RDEV - if (preserve_devices && IS_DEVICE(st.st_mode)) + if ((preserve_devices && IS_DEVICE(st.st_mode)) + || (preserve_specials && IS_SPECIAL(st.st_mode))) file->u.rdev = st.st_rdev; #endif @@ -945,7 +953,8 @@ struct file_struct *make_file(char *fname, struct file_list *flist, file->modtime = st2.st_mtime; file->length = st2.st_size; file->mode = st2.st_mode; - file->ids = id_pair(st2.st_uid, st2.st_gid); + file->uid = st2.st_uid; + file->gid = st2.st_gid; file->u.link = NULL; } else file->mode = save_mode; @@ -1389,7 +1398,7 @@ struct file_list *recv_file_list(int f) clean_flist(flist, relative_paths, 1); if (f >= 0) { - recv_uid_list(f); + recv_uid_list(f, flist); /* Recv the io_error flag */ if (lp_ignore_errors(module_id) || ignore_errors) @@ -1434,11 +1443,30 @@ int flist_find(struct file_list *flist, struct file_struct *f) while (low <= high) { mid = (low + high) / 2; - for (mid_up = mid; !flist->files[mid_up]->basename; mid_up++) {} - if (mid_up <= high) - ret = f_name_cmp(flist->files[mid_up], f); - else - ret = 1; + if (flist->files[mid]->basename) + mid_up = mid; + else if (flist->files[mid]->dir.depth) { + mid_up = mid + flist->files[mid]->dir.depth; + if (mid_up < mid) { + high = mid_up; + continue; + } + } else { + /* Scan for the next non-empty entry and cache + * the distance so we never do this again. */ + mid_up = mid; + while (++mid_up <= high + && !flist->files[mid_up]->basename) {} + if (mid_up > high) { + high = mid; + while (--high >= low + && !flist->files[high]->basename) {} + flist->files[mid]->dir.depth = high - mid; + continue; + } + flist->files[mid]->dir.depth = mid_up - mid; + } + ret = f_name_cmp(flist->files[mid_up], f); if (ret == 0) { if (protocol_version < 29 && S_ISDIR(flist->files[mid_up]->mode) @@ -1565,8 +1593,8 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) "removing duplicate name %s from file list (%d)\n", f_name(file, NULL), drop); } - /* Make sure that if we unduplicate '.', that we don't - * lose track of a user-specified top directory. */ + /* Make sure we don't lose track of a user-specified + * top directory. */ flist->files[keep]->flags |= flist->files[drop]->flags & (FLAG_TOP_DIR|FLAG_DEL_HERE); @@ -1594,16 +1622,53 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) if (!file->dirname) continue; - if (*file->dirname == '/') { - char *s = file->dirname + 1; - while (*s == '/') s++; - memmove(file->dirname, s, strlen(s) + 1); - } - + while (*file->dirname == '/') + file->dirname++; if (!*file->dirname) file->dirname = NULL; } } + + if (skip_empty_dirs && no_dups && max_dir_depth) { + int j, cur_depth = 0; + int *maybe_dirs = new_array(int, max_dir_depth); + + maybe_dirs[0] = -1; + + for (i = flist->low; i <= flist->high; i++) { + struct file_struct *file = flist->files[i]; + + if (S_ISDIR(file->mode) && file->dir.depth) { + j = cur_depth; + cur_depth = file->dir.depth - 1; + for ( ; j >= cur_depth; j--) { + if (maybe_dirs[j] < 0) + continue; + clear_file(maybe_dirs[j], flist); + } + maybe_dirs[cur_depth] = i; + } else if (maybe_dirs[cur_depth] >= 0) { + for (j = 0; j <= cur_depth; j++) + maybe_dirs[j] = -1; + } + } + for (j = cur_depth; j >= 0; j--) { + if (maybe_dirs[j] < 0) + continue; + clear_file(maybe_dirs[j], flist); + } + + for (i = flist->low; i <= flist->high; i++) { + if (flist->files[i]->basename) + break; + } + flist->low = i; + for (i = flist->high; i >= flist->low; i--) { + if (flist->files[i]->basename) + break; + } + flist->high = i; + } } static void output_flist(struct file_list *flist) @@ -1616,11 +1681,11 @@ static void output_flist(struct file_list *flist) for (i = 0; i < flist->count; i++) { file = flist->files[i]; if ((am_root || am_sender) && preserve_uid) - sprintf(uidbuf, " uid=%ld", (long)file->ids->uid); + sprintf(uidbuf, " uid=%ld", (long)file->uid); else *uidbuf = '\0'; - if (preserve_gid && file->ids->gid != GID_NONE) - sprintf(gidbuf, " gid=%ld", (long)file->ids->gid); + if (preserve_gid && file->gid != GID_NONE) + sprintf(gidbuf, " gid=%ld", (long)file->gid); else *gidbuf = '\0'; if (!am_sender)