+ }
+ flist->low = prev_i;
+ } else {
+ i = prev_i = flist->count - 1;
+ flist->low = 0;
+ }
+
+ while (++i < flist->count) {
+ int j;
+ struct file_struct *file = flist->sorted[i];
+
+ if (!F_IS_ACTIVE(file))
+ continue;
+ if (f_name_cmp(file, flist->sorted[prev_i]) == 0)
+ j = prev_i;
+ else if (protocol_version >= 29 && S_ISDIR(file->mode)) {
+ int save_mode = file->mode;
+ /* Make sure that this directory doesn't duplicate a
+ * non-directory earlier in the list. */
+ flist->high = prev_i;
+ file->mode = S_IFREG;
+ j = flist_find(flist, file);
+ file->mode = save_mode;
+ } else
+ j = -1;
+ if (j >= 0) {
+ struct file_struct *fp = flist->sorted[j];
+ int keep, drop;
+ /* If one is a dir and the other is not, we want to
+ * keep the dir because it might have contents in the
+ * list. */
+ if (S_ISDIR(file->mode) != S_ISDIR(fp->mode)) {
+ if (S_ISDIR(file->mode))
+ keep = i, drop = j;
+ else
+ keep = j, drop = i;
+ } else if (protocol_version < 27)
+ keep = j, drop = i;
+ else
+ keep = i, drop = j;
+
+ if (am_sender)
+ flist->sorted[drop]->flags |= FLAG_DUPLICATE;
+ else {
+ if (verbose > 1) {
+ rprintf(FINFO,
+ "removing duplicate name %s from file list (%d)\n",
+ f_name(file, fbuf), drop);
+ }
+ /* Make sure we don't lose track of a user-specified
+ * top directory. */
+ flist->sorted[keep]->flags |= flist->sorted[drop]->flags
+ & (FLAG_TOP_DIR|FLAG_XFER_DIR);
+
+ clear_file(flist->sorted[drop]);
+ }
+
+ if (keep == i) {
+ if (flist->low == drop) {
+ for (j = drop + 1;
+ j < i && !F_IS_ACTIVE(flist->sorted[j]);
+ j++) {}
+ flist->low = j;
+ }
+ prev_i = i;
+ }
+ } else
+ prev_i = i;
+ }
+ flist->high = prev_i;
+
+ if (strip_root) {
+ /* We need to strip off the leading slashes for relative
+ * paths, but this must be done _after_ the sorting phase. */
+ for (i = flist->low; i <= flist->high; i++) {
+ struct file_struct *file = flist->sorted[i];
+
+ if (!file->dirname)
+ continue;
+ while (*file->dirname == '/')
+ file->dirname++;
+ if (!*file->dirname)
+ file->dirname = NULL;
+ }
+ }
+
+ if (prune_empty_dirs && !am_sender) {
+ int j, prev_depth = 0;
+
+ prev_i = 0; /* It's OK that this isn't really true. */
+
+ for (i = flist->low; i <= flist->high; i++) {
+ struct file_struct *fp, *file = flist->sorted[i];
+
+ /* This temporarily abuses the F_DEPTH() value for a
+ * directory that is in a chain that might get pruned.
+ * We restore the old value if it gets a reprieve. */
+ if (S_ISDIR(file->mode) && F_DEPTH(file)) {
+ /* Dump empty dirs when coming back down. */
+ for (j = prev_depth; j >= F_DEPTH(file); j--) {
+ fp = flist->sorted[prev_i];
+ if (F_DEPTH(fp) >= 0)
+ break;
+ prev_i = -F_DEPTH(fp)-1;
+ clear_file(fp);
+ }
+ prev_depth = F_DEPTH(file);
+ if (is_excluded(f_name(file, fbuf), 1,
+ ALL_FILTERS)) {
+ /* Keep dirs through this dir. */
+ for (j = prev_depth-1; ; j--) {
+ fp = flist->sorted[prev_i];
+ if (F_DEPTH(fp) >= 0)
+ break;
+ prev_i = -F_DEPTH(fp)-1;
+ F_DEPTH(fp) = j;
+ }
+ } else
+ F_DEPTH(file) = -prev_i-1;
+ prev_i = i;
+ } else {
+ /* Keep dirs through this non-dir. */
+ for (j = prev_depth; ; j--) {
+ fp = flist->sorted[prev_i];
+ if (F_DEPTH(fp) >= 0)
+ break;
+ prev_i = -F_DEPTH(fp)-1;
+ F_DEPTH(fp) = j;
+ }