-/*
+/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
static struct file_struct null_file;
-static void clean_flist(struct file_list *flist, int strip_root);
+static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static int show_filelist_p(void)
if (S_ISLNK(buffer->st_mode)) {
int l;
l = readlink((char *) path, linkbuf, MAXPATHLEN - 1);
- if (l == -1)
+ if (l == -1)
return -1;
linkbuf[l] = 0;
if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
if (verbose > 1) {
- rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
+ rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
path, linkbuf);
}
return do_stat(path, buffer);
if (flist->count >= flist->malloced) {
size_t new_bytes;
void *new_ptr;
-
+
if (flist->malloced < 1000)
flist->malloced += 1000;
else
flist->malloced *= 2;
new_bytes = sizeof(flist->files[0]) * flist->malloced;
-
+
if (flist->files)
new_ptr = realloc(flist->files, new_bytes);
else
(double) new_bytes,
(new_ptr == flist->files) ? " not" : "");
}
-
+
flist->files = (struct file_struct **) new_ptr;
if (!flist->files)
for (l1 = 0;
lastname[l1] && (fname[l1] == lastname[l1]) && (l1 < 255);
- l1++);
+ l1++) {}
l2 = strlen(fname) - l1;
if (l1 > 0)
if (readlink_stat(fname, &st, linkbuf) != 0) {
int save_errno = errno;
if ((errno == ENOENT) && !noexcludes) {
- /* either symlink pointing nowhere or file that
+ /* either symlink pointing nowhere or file that
* was removed during rsync run; see if excluded
* before reporting an error */
memset((char *) &st, 0, sizeof(st));
dir = fname;
fname = p + 1;
}
- } else if (f != -1 && (p = strrchr(fname, '/'))) {
+ } else if (f != -1 && (p=strrchr(fname,'/')) && p != fname) {
/* this ensures we send the intermediate directories,
thus getting their permissions right */
+ char *lp = lastpath, *fn = fname, *slash = fname;
*p = 0;
- if (strcmp(lastpath, fname)) {
- strlcpy(lastpath, fname, sizeof(lastpath));
- *p = '/';
- for (p = fname + 1; (p = strchr(p, '/'));
- p++) {
- int copy_links_saved = copy_links;
- int recurse_saved = recurse;
- *p = 0;
- copy_links = copy_unsafe_links;
- /* set recurse to 1 to prevent make_file
- from ignoring directory, but still
- turn off the recursive parameter to
- send_file_name */
- recurse = 1;
- send_file_name(f, flist, fname, 0,
- 0);
- copy_links = copy_links_saved;
- recurse = recurse_saved;
- *p = '/';
+ /* Skip any initial directories in our path that we
+ * have in common with lastpath. */
+ while (*fn && *lp == *fn) {
+ if (*fn == '/')
+ slash = fn;
+ lp++, fn++;
+ }
+ *p = '/';
+ if (fn != p || (*lp && *lp != '/')) {
+ int copy_links_saved = copy_links;
+ int recurse_saved = recurse;
+ copy_links = copy_unsafe_links;
+ /* set recurse to 1 to prevent make_file
+ * from ignoring directory, but still
+ * turn off the recursive parameter to
+ * send_file_name */
+ recurse = 1;
+ while ((slash = strchr(slash+1, '/')) != 0) {
+ *slash = 0;
+ send_file_name(f, flist, fname, 0, 0);
+ *slash = '/';
}
- } else {
+ copy_links = copy_links_saved;
+ recurse = recurse_saved;
+ *p = 0;
+ strlcpy(lastpath, fname, sizeof lastpath);
*p = '/';
}
}
finish_filelist_progress(flist);
}
- clean_flist(flist, 0);
+ clean_flist(flist, 0, 0);
/* now send the uid/gid list. This was introduced in protocol
version 15 */
for (flags = read_byte(f); flags; flags = read_byte(f)) {
int i = flist->count;
-
+
flist_expand(flist);
receive_file_entry(&flist->files[i], flags, f);
if (verbose > 2)
rprintf(FINFO, "received %d names\n", flist->count);
- clean_flist(flist, relative_paths);
+ clean_flist(flist, relative_paths, 1);
if (show_filelist_p()) {
finish_filelist_progress(flist);
/*
* This routine ensures we don't have any duplicate names in our file list.
- * duplicate names can cause corruption because of the pipelining
+ * duplicate names can cause corruption because of the pipelining
*/
-static void clean_flist(struct file_list *flist, int strip_root)
+static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
{
int i;
char *name, *prev_name = NULL;
qsort(flist->files, flist->count,
sizeof(flist->files[0]), (int (*)()) file_compare);
- for (i = 0; i < flist->count; i++) {
+ for (i = no_dups? 0 : flist->count; i < flist->count; i++) {
if (flist->files[i]->basename) {
prev_name = f_name(flist->files[i]);
break;