Don't try to backup a file being removed from the backup area.
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index ea24775..0cafed6 100644 (file)
--- a/util.c
+++ b/util.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2008 Wayne Davison
+ * Copyright (C) 2003-2009 Wayne Davison
  *
  * 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
@@ -806,7 +806,8 @@ int count_dir_elements(const char *p)
        return cnt;
 }
 
-/* Turns multiple adjacent slashes into a single slash, drops all leading or
+/* Turns multiple adjacent slashes into a single slash (possible exception:
+ * the preserving of two leading slashes at the start), drops all leading or
  * interior "." elements unless CFN_KEEP_DOT_DIRS is flagged.  Will also drop
  * a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes
  * a trailing slash (perhaps after removing the aforementioned dot) unless
@@ -821,9 +822,16 @@ unsigned int clean_fname(char *name, int flags)
        if (!name)
                return 0;
 
-       if ((anchored = *f == '/') != 0)
+       if ((anchored = *f == '/') != 0) {
                *t++ = *f++;
-       else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
+#ifdef __CYGWIN__
+               /* If there are exactly 2 slashes at the start, preserve
+                * them.  Would break daemon excludes unless the paths are
+                * really treated differently, so used this sparingly. */
+               if (*f == '/' && f[1] != '/')
+                       *t++ = *f++;
+#endif
+       } else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
                *t++ = *f++;
                *t++ = *f++;
        }
@@ -979,7 +987,10 @@ int change_dir(const char *dir, int set_path_only)
 
        if (!initialised) {
                initialised = 1;
-               getcwd(curr_dir, sizeof curr_dir - 1);
+               if (getcwd(curr_dir, sizeof curr_dir - 1) == NULL) {
+                       rsyserr(FERROR, errno, "getcwd()");
+                       exit_cleanup(RERR_FILESELECT);
+               }
                curr_dir_len = strlen(curr_dir);
        }
 
@@ -1157,12 +1168,13 @@ int handle_partial_dir(const char *fname, int create)
        return 1;
 }
 
-/**
- * Determine if a symlink points outside the current directory tree.
+/* Determine if a symlink points outside the current directory tree.
  * This is considered "unsafe" because e.g. when mirroring somebody
  * else's machine it might allow them to establish a symlink to
  * /etc/passwd, and then read it through a web server.
  *
+ * Returns 1 if unsafe, 0 if safe.
+ *
  * Null symlinks and absolute symlinks are always unsafe.
  *
  * Basically here we are concerned with symlinks whose target contains
@@ -1170,17 +1182,11 @@ int handle_partial_dir(const char *fname, int create)
  * transferred directory.  We are not allowed to go back up and
  * reenter.
  *
- * @param dest Target of the symlink in question.
- *
- * @param src Top source directory currently applicable.  Basically this
- * is the first parameter to rsync in a simple invocation, but it's
- * modified by flist.c in slightly complex ways.
- *
- * @retval True if unsafe
- * @retval False is unsafe
+ * "dest" is the target of the symlink in question.
  *
- * @sa t_unsafe.c
- **/
+ * "src" is the top source directory currently applicable at the level
+ * of the referenced symlink.  This is usually the symlink's full path
+ * (including its name), as referenced from the root of the transfer. */
 int unsafe_symlink(const char *dest, const char *src)
 {
        const char *name, *slash;
@@ -1192,33 +1198,33 @@ int unsafe_symlink(const char *dest, const char *src)
 
        /* find out what our safety margin is */
        for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
-               if (strncmp(name, "../", 3) == 0) {
-                       depth = 0;
-               } else if (strncmp(name, "./", 2) == 0) {
-                       /* nothing */
-               } else {
+               /* ".." segment starts the count over.  "." segment is ignored. */
+               if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
+                       if (name[1] == '.')
+                               depth = 0;
+               } else
                        depth++;
-               }
+               while (slash[1] == '/') slash++; /* just in case src isn't clean */
        }
-       if (strcmp(name, "..") == 0)
+       if (*name == '.' && name[1] == '.' && name[2] == '\0')
                depth = 0;
 
        for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
-               if (strncmp(name, "../", 3) == 0) {
-                       /* if at any point we go outside the current directory
-                          then stop - it is unsafe */
-                       if (--depth < 0)
-                               return 1;
-               } else if (strncmp(name, "./", 2) == 0) {
-                       /* nothing */
-               } else {
+               if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
+                       if (name[1] == '.') {
+                               /* if at any point we go outside the current directory
+                                  then stop - it is unsafe */
+                               if (--depth < 0)
+                                       return 1;
+                       }
+               } else
                        depth++;
-               }
+               while (slash[1] == '/') slash++;
        }
-       if (strcmp(name, "..") == 0)
+       if (*name == '.' && name[1] == '.' && name[2] == '\0')
                depth--;
 
-       return (depth < 0);
+       return depth < 0;
 }
 
 /* Return the date and time as a string.  Some callers tweak returned buf. */
@@ -1540,6 +1546,39 @@ int bitbag_next_bit(struct bitbag *bb, int after)
        return -1;
 }
 
+void flist_ndx_push(flist_ndx_list *lp, int ndx)
+{
+       struct flist_ndx_item *item;
+
+       if (!(item = new(struct flist_ndx_item)))
+               out_of_memory("flist_ndx_push");
+       item->next = NULL;
+       item->ndx = ndx;
+       if (lp->tail)
+               lp->tail->next = item;
+       else
+               lp->head = item;
+       lp->tail = item;
+}
+
+int flist_ndx_pop(flist_ndx_list *lp)
+{
+       struct flist_ndx_item *next;
+       int ndx;
+
+       if (!lp->head)
+               return -1;
+
+       ndx = lp->head->ndx;
+       next = lp->head->next;
+       free(lp->head);
+       lp->head = next;
+       if (!next)
+               lp->tail = NULL;
+
+       return ndx;
+}
+
 void *expand_item_list(item_list *lp, size_t item_size,
                       const char *desc, int incr)
 {