return cnt;
}
-/* Turns multiple adjacent slashes into a single slash; gets rid of "./"
- * elements; collapses ".." elements except for those at the start of the
- * string; removes a trailing slash. If the resulting name would be empty,
- * change it into a ".". */
-unsigned int clean_fname(char *name)
+/* Turns multiple adjacent slashes into a single slash, gets rid of "./"
+ * elements (but not a trailing dot dir), removes a trailing slash, and
+ * optionally collapses ".." elements (except for those at the start of the
+ * string). If the resulting name would be empty, change it into a ".". */
+unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
{
char *limit = name - 1, *t = name, *f = name;
int anchored;
continue;
}
/* collapse ".." dirs */
- if (f[1] == '.' && (f[2] == '/' || !f[2])) {
+ if (collapse_dot_dot
+ && f[1] == '.' && (f[2] == '/' || !f[2])) {
char *s = t - 1;
if (s == name && anchored) {
f += 2;
* If depth is > 0, it is a count of how many '..'s to allow at the start
* of the path.
*
- * We call clean_fname() to clean up the path, but we preserve a trailing
- * slash because that is sometimes significant on command-line arguments.
- */
+ * We also clean the path in a manner similar to clean_fname() but with a
+ * few differences:
+ *
+ * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
+ * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
+ * ALWAYS collapses ".." elements (except for those at the start of the
+ * string up to "depth" deep). If the resulting name would be empty,
+ * change it into a ".". */
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
{
char *start, *sanp;
}
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
/* ".." component followed by slash or end */
- if (depth > 0 && sanp == start) {
- /* allow depth levels of .. at the beginning */
- --depth;
- *sanp++ = *p++;
- *sanp++ = *p++;
- /* move virtual beginning to leave .. alone */
- start = sanp;
- continue;
- }
- p += 2;
- if (sanp != start) {
- /* back up sanp one level */
- --sanp; /* now pointing at slash */
- while (sanp > start && sanp[-1] != '/') {
- /* skip back up to slash */
- sanp--;
+ if (depth <= 0 || sanp != start) {
+ p += 2;
+ if (sanp != start) {
+ /* back up sanp one level */
+ --sanp; /* now pointing at slash */
+ while (sanp > start && sanp[-1] != '/') {
+ /* skip back up to slash */
+ sanp--;
+ }
}
+ continue;
}
- continue;
+ /* allow depth levels of .. at the beginning */
+ depth--;
+ /* move the virtual beginning to leave the .. alone */
+ start = sanp + 3;
}
/* copy one component through next slash */
while (*p && (*sanp++ = *p++) != '/') {}
curr_dir_len += len;
}
- curr_dir_len = clean_fname(curr_dir);
+ curr_dir_len = clean_fname(curr_dir, 1);
return 1;
}