summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
819bfe4)
- Removed the CFN_KEEP_LEADING_DOT_DIR flag for clean_fname().
- Explicitly add an implied dot-dir to the transfer rather than keeping
a leading a "./" prefix as a part of a relative pathname.
- Added the CFN_KEEP_DOT_DIRS flag for clean_fname().
- Added the SP_KEEP_DOT_DIRS flag for sanitize_path().
- Call clean_fname() a couple more times.
strlcpy(to, merge_file, *len_ptr + 1);
merge_file = to;
}
strlcpy(to, merge_file, *len_ptr + 1);
merge_file = to;
}
- if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
+ if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) {
rprintf(FERROR, "merge-file name overflows: %s\n",
merge_file);
return NULL;
rprintf(FERROR, "merge-file name overflows: %s\n",
merge_file);
return NULL;
clean_fname(thisname, 0);
if (sanitize_paths)
clean_fname(thisname, 0);
if (sanitize_paths)
- sanitize_path(thisname, thisname, "", 0);
+ sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if ((basename = strrchr(thisname, '/')) != NULL) {
int len = basename++ - thisname;
if ((basename = strrchr(thisname, '/')) != NULL) {
int len = basename++ - thisname;
} else {
read_sbuf(f, bp, linkname_len - 1);
if (sanitize_paths)
} else {
read_sbuf(f, bp, linkname_len - 1);
if (sanitize_paths)
- sanitize_path(bp, bp, "", lastdir_depth);
+ sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT);
}
clean_fname(thisname, 0);
if (sanitize_paths)
}
clean_fname(thisname, 0);
if (sanitize_paths)
- sanitize_path(thisname, thisname, "", 0);
+ sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if (stp && S_ISDIR(stp->st_mode)) {
st = *stp; /* Needed for "symlink/." with --relative. */
if (stp && S_ISDIR(stp->st_mode)) {
st = *stp; /* Needed for "symlink/." with --relative. */
| (filesfrom_convert ? RL_CONVERT : 0)
#endif
| (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0);
| (filesfrom_convert ? RL_CONVERT : 0)
#endif
| (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0);
+ int implied_dot_dir = 0;
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
if (use_ff_fd) {
if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0)
break;
if (use_ff_fd) {
if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0)
break;
- sanitize_path(fbuf, fbuf, "", 0);
+ sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
} else {
if (argc-- == 0)
break;
strlcpy(fbuf, *argv++, MAXPATHLEN);
if (sanitize_paths)
} else {
if (argc-- == 0)
break;
strlcpy(fbuf, *argv++, MAXPATHLEN);
if (sanitize_paths)
- sanitize_path(fbuf, fbuf, "", 0);
+ sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
*p = '\0';
if (p == fbuf)
dir = "/";
*p = '\0';
if (p == fbuf)
dir = "/";
+ clean_fname(dir, 0);
+ }
fn = p + 3;
while (*fn == '/')
fn++;
fn = p + 3;
while (*fn == '/')
fn++;
*--fn = '\0'; /* ensure room for '.' */
} else
fn = fbuf;
*--fn = '\0'; /* ensure room for '.' */
} else
fn = fbuf;
- len = clean_fname(fn, CFN_KEEP_LEADING_DOT_DIR
- | CFN_KEEP_TRAILING_SLASH
+ /* A leading ./ can be used in relative mode to affect
+ * the dest dir without its name being in the path. */
+ if (*fn == '.' && fn[1] == '/' && !implied_dot_dir) {
+ send_file_name(f, flist, ".", NULL,
+ (flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR,
+ ALL_FILTERS);
+ implied_dot_dir = 1;
+ }
+ len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH
| CFN_DROP_TRAILING_DOT_DIR);
if (len == 1) {
if (fn[0] == '/') {
| CFN_DROP_TRAILING_DOT_DIR);
if (len == 1) {
if (fn[0] == '/') {
int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags;
file = send_file_name(f, flist, fbuf, &st,
top_flags, ALL_FILTERS);
int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags;
file = send_file_name(f, flist, fbuf, &st,
top_flags, ALL_FILTERS);
- if (name_type == DOT_NAME && file) {
+ if (name_type == DOT_NAME) {
if (send_dir_depth < 0) {
send_dir_depth = 0;
change_local_filter_dir(fbuf, len, send_dir_depth);
}
send_directory(f, flist, fbuf, len, flags);
}
if (send_dir_depth < 0) {
send_dir_depth = 0;
change_local_filter_dir(fbuf, len, send_dir_depth);
}
send_directory(f, flist, fbuf, len, flags);
}
send_if_directory(f, flist, file, fbuf, len, flags);
} else
send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS);
send_if_directory(f, flist, file, fbuf, len, flags);
} else
send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS);
if (sanitize_paths) {
char **dir_p;
for (dir_p = basis_dir; *dir_p; dir_p++)
if (sanitize_paths) {
char **dir_p;
for (dir_p = basis_dir; *dir_p; dir_p++)
- *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth);
+ *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
- partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth);
+ partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
}
check_alt_basis_dirs();
}
check_alt_basis_dirs();
case OPT_INCLUDE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
case OPT_INCLUDE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
- arg = sanitize_path(NULL, arg, NULL, 0);
+ arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT);
if (daemon_filter_list.head) {
int rej;
char *dir, *cp = strdup(arg);
if (daemon_filter_list.head) {
int rej;
char *dir, *cp = strdup(arg);
if (sanitize_paths) {
int i;
for (i = argc; i-- > 0; )
if (sanitize_paths) {
int i;
for (i = argc; i-- > 0; )
- argv[i] = sanitize_path(NULL, argv[i], "", 0);
+ argv[i] = sanitize_path(NULL, argv[i], "", 0, SP_KEEP_DOT_DIRS);
- tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
+ tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
- backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
+ backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
}
if (daemon_filter_list.head && !am_sender) {
struct filter_list_struct *elp = &daemon_filter_list;
}
if (daemon_filter_list.head && !am_sender) {
struct filter_list_struct *elp = &daemon_filter_list;
}
} else {
if (sanitize_paths)
}
} else {
if (sanitize_paths)
- files_from = sanitize_path(NULL, files_from, NULL, 0);
+ files_from = sanitize_path(NULL, files_from, NULL, 0, SP_DEFAULT);
if (daemon_filter_list.head) {
char *dir;
if (!*files_from)
if (daemon_filter_list.head) {
char *dir;
if (!*files_from)
#define SIGNIFICANT_ITEM_FLAGS (~(\
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
#define SIGNIFICANT_ITEM_FLAGS (~(\
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
-#define CFN_KEEP_LEADING_DOT_DIR (1<<0)
+#define CFN_KEEP_DOT_DIRS (1<<0)
#define CFN_KEEP_TRAILING_SLASH (1<<1)
#define CFN_DROP_TRAILING_DOT_DIR (1<<2)
#define CFN_COLLAPSE_DOT_DOT_DIRS (1<<3)
#define CFN_KEEP_TRAILING_SLASH (1<<1)
#define CFN_DROP_TRAILING_DOT_DIR (1<<2)
#define CFN_COLLAPSE_DOT_DOT_DIRS (1<<3)
+#define SP_DEFAULT 0
+#define SP_KEEP_DOT_DIRS (1<<0)
+
/* Log-message categories. FLOG only goes to the log file, not the client;
* FCLIENT is the opposite. */
enum logcode {
/* Log-message categories. FLOG only goes to the log file, not the client;
* FCLIENT is the opposite. */
enum logcode {
s = ".";
if (sanitize_paths)
s = ".";
if (sanitize_paths)
- s = sanitize_path(NULL, s, "", 0);
- else
+ s = sanitize_path(NULL, s, "", 0, SP_KEEP_DOT_DIRS);
+ else {
- if (!s)
- out_of_memory("glob_expand");
+ if (!s)
+ out_of_memory("glob_expand");
+ clean_fname(s, CFN_KEEP_DOT_DIRS
+ | CFN_KEEP_TRAILING_SLASH
+ | CFN_COLLAPSE_DOT_DOT_DIRS);
+ }
memset(&globbuf, 0, sizeof globbuf);
glob(s, 0, NULL, &globbuf);
memset(&globbuf, 0, sizeof globbuf);
glob(s, 0, NULL, &globbuf);
-/* Turns multiple adjacent slashes into a single slash, drops interior "."
- * elements, drops an intial "./" unless CFN_KEEP_LEADING_DOT_DIR is flagged,
- * will even drop a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is
- * flagged, removes a trailing slash (perhaps after removing the aforementioned
- * dot) unless CFN_KEEP_TRAILING_SLASH is flagged, will even collapse ".."
- * elements (except at the start of the string) if CFN_COLLAPSE_DOT_DOT_DIRS
- * is flagged. If the resulting name would be empty, we return ".". */
+/* Turns multiple adjacent slashes into a single slash, 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
+ * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements
+ * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the
+ * resulting name would be empty, returns ".". */
unsigned int clean_fname(char *name, int flags)
{
char *limit = name - 1, *t = name, *f = name;
unsigned int clean_fname(char *name, int flags)
{
char *limit = name - 1, *t = name, *f = name;
if ((anchored = *f == '/') != 0)
*t++ = *f++;
if ((anchored = *f == '/') != 0)
*t++ = *f++;
- else if (flags & CFN_KEEP_LEADING_DOT_DIR && *f == '.' && f[1] == '/') {
+ else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
*t++ = *f++;
*t++ = *f++;
}
*t++ = *f++;
*t++ = *f++;
}
}
if (*f == '.') {
/* discard interior "." dirs */
}
if (*f == '.') {
/* discard interior "." dirs */
+ if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) {
* 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 ".". */
* 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 *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
+ int flags)
- int rlen = 0, leave_one_dotdir = relative_paths;
+ int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
if (dest != p) {
int plen = strlen(p);
if (dest != p) {
int plen = strlen(p);
+ if (drop_dot_dirs) {
+ while (*p == '.' && p[1] == '/')
+ p += 2;
+ }
+
start = sanp = dest + rlen;
/* This loop iterates once per filename component in p, pointing at
* the start of the name (past any prior slash) for each iteration. */
start = sanp = dest + rlen;
/* This loop iterates once per filename component in p, pointing at
* the start of the name (past any prior slash) for each iteration. */
- if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
- if (leave_one_dotdir && p[1])
- leave_one_dotdir = 0;
- else {
+ if (drop_dot_dirs) {
+ if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
/* skip "." component */
p++;
continue;
/* skip "." component */
p++;
continue;
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
- while (sanp > start && sanp[-1] != '/') {
- /* skip back up to slash */
+ while (sanp > start && sanp[-1] != '/')