#endif
}
-/* Returns 0 on success, -1 on most errors, and -2 if we got an error
- * trying to copy the file across file systems. */
+/* Returns 0 on successful rename, 1 if we successfully copied the file
+ * across filesystems, -2 if copy_file() failed, and -1 on other errors. */
int robust_rename(char *from, char *to, int mode)
{
int tries = 4;
if (copy_file(from, to, mode) != 0)
return -2;
do_unlink(from);
- return 0;
+ return 1;
default:
return -1;
}
return ret;
}
-void clean_fname(char *name)
+unsigned int clean_fname(char *name)
{
- char *limit = name, *t = name, *f = name;
+ char *limit = name - 1, *t = name, *f = name;
int anchored;
if (!name)
- return;
+ return 0;
if ((anchored = *f == '/') != 0)
*t++ = *f++;
if (*f == '.') {
/* discard "." dirs (but NOT a trailing '.'!) */
if (f[1] == '/') {
- f++; /* not += 2! */
+ f += 2;
continue;
}
/* collapse ".." dirs */
continue;
}
while (s > limit && *--s != '/') {}
- if (s != t - 1 && *s == '/') {
+ if (s != t - 1 && (s < name || *s == '/')) {
t = s + 1;
f += 2;
continue;
if (t == name)
*t++ = '.';
*t = '\0';
+
+ return t - name;
}
/* Make path appear as if a chroot had occurred. This handles a leading
curr_dir_len += len;
}
- clean_fname(curr_dir);
+ curr_dir_len = clean_fname(curr_dir);
return 1;
}