#define MAX_RENAMES 1000
/**
- *
- Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
- rename to <path>/.rsyncNNN instead.
-
- Note that successive rsync runs will shuffle the filenames around a
- bit as long as the file is still busy; this is because this function
- does not know if the unlink call is due to a new file coming in, or
- --delete trying to remove old .rsyncNNN files, hence it renames it
- each time.
-*/
+ * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
+ * rename to <path>/.rsyncNNN instead.
+ *
+ * Note that successive rsync runs will shuffle the filenames around a
+ * bit as long as the file is still busy; this is because this function
+ * does not know if the unlink call is due to a new file coming in, or
+ * --delete trying to remove old .rsyncNNN files, hence it renames it
+ * each time.
+ **/
int robust_unlink(char *fname)
{
#ifndef ETXTBSY
void strlower(char *s)
{
while (*s) {
- if (isupper(*s)) *s = tolower(*s);
+ if (isupper(* (unsigned char *) s))
+ *s = tolower(* (unsigned char *) s);
s++;
}
}
/**
* Make path appear as if a chroot had occurred:
*
- * 1. remove leading "/" (or replace with "." if at end)
- * 2. remove leading ".." components (except those allowed by "reldir")
- * 3. delete any other "<dir>/.." (recursively)
+ * @li 1. remove leading "/" (or replace with "." if at end)
+ *
+ * @li 2. remove leading ".." components (except those allowed by @p reldir)
+ *
+ * @li 3. delete any other "<dir>/.." (recursively)
*
* Can only shrink paths, so sanitizes in place.
*
* While we're at it, remove double slashes and "." components like
- * clean_fname does(), but DON'T remove a trailing slash because that
+ * clean_fname() does, but DON'T remove a trailing slash because that
* is sometimes significant on command line arguments.
*
- * If "reldir" is non-null, it is a sanitized directory that the path will be
+ * If @p reldir is non-null, it is a sanitized directory that the path will be
* relative to, so allow as many ".." at the beginning of the path as
* there are components in reldir. This is used for symbolic link targets.
* If reldir is non-null and the path began with "/", to be completely like
static char curr_dir[MAXPATHLEN];
-/** like chdir() but can be reversed with pop_dir() if save is set. It
- is also much faster as it remembers where we have been */
+/**
+ * Like chdir() but can be reversed with pop_dir() if @p save is set.
+ * It is also much faster as it remembers where we have been.
+ **/
char *push_dir(char *dir, int save)
{
char *ret = curr_dir;
return ret;
}
-/** Reverse a push_dir call */
+/** Reverse a push_dir() call */
int pop_dir(char *dir)
{
int ret;
* else's machine it might allow them to establish a symlink to
* /etc/passwd, and then read it through a web server.
*
+ * Null symlinks and absolute symlinks are always unsafe.
+ *
+ * Basically here we are concerned with symlinks whose target contains
+ * "..", because this might cause us to walk back up out of the
+ * 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
*
* @retval True if unsafe
* @retval False is unsafe
+ *
+ * @sa t_unsafe.c
**/
-int unsafe_symlink(char *dest, char *src)
+int unsafe_symlink(const char *dest, const char *src)
{
- char *tok;
+ const char *name, *slash;
int depth = 0;
/* all absolute and null symlinks are unsafe */
- if (!dest || !(*dest) || (*dest == '/')) return 1;
-
- src = strdup(src);
- if (!src) out_of_memory("unsafe_symlink");
+ if (!dest || !*dest || *dest == '/') return 1;
/* find out what our safety margin is */
- for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
- if (strcmp(tok,"..") == 0) {
+ for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
+ if (strncmp(name, "../", 3) == 0) {
depth=0;
- } else if (strcmp(tok,".") == 0) {
+ } else if (strncmp(name, "./", 2) == 0) {
/* nothing */
} else {
depth++;
}
}
- free(src);
+ if (strcmp(name, "..") == 0)
+ depth = 0;
- /* drop by one to account for the filename portion */
- depth--;
-
- dest = strdup(dest);
- if (!dest) out_of_memory("unsafe_symlink");
-
- for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
- if (strcmp(tok,"..") == 0) {
- depth--;
- } else if (strcmp(tok,".") == 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 {
depth++;
}
- /* if at any point we go outside the current directory then
- stop - it is unsafe */
- if (depth < 0) break;
}
+ if (strcmp(name, "..") == 0)
+ depth--;
- free(dest);
return (depth < 0);
}
/**
- Return the date and time as a string
-*/
+ * Return the date and time as a string
+ **/
char *timestring(time_t t)
{
static char TimeBuf[200];