#include "env.h"
#include "getopt-min.h"
+
+#define DEBUG_CP 1 /* set to 1 to debug */
+#define DEBUG_LS 1 /* set to 1 to debug */
+
+#define debug_cp(fmt, args...) \
+ debug_cond(DEBUG_CP, fmt, ##args)
+#define debug_ls(fmt, args...) \
+ debug_cond(DEBUG_LS, fmt, ##args)
+
+
/* TODO: use memory size test function (detect_ramsize() in cmd_loadihex.c) */
/* TODO: detect_ramsize() should be moved to z80-if.c */
#define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX
#define BUFFER_SIZE 512
-#define MAXBSIZE 512 /* TODO */
+#define MAX_PATHLEN CONFIG_SYS_MAX_PATHLEN
+typedef struct {
+ char *p_end; /* pointer to NULL at end of path */
+ char p_path[MAX_PATHLEN + 1]; /* pointer to the start of a path */
+} PATH_T;
+
/*
* Multible (fat) partitions per physical drive are not supported,
* but we have up to 2 sdcard slots.
FATFS FatFs0;
FATFS FatFs1;
+uint8_t *blockbuf;
+int blockbuf_size;
+PATH_T from;
+PATH_T to;
command_ret_t command_ret;
void setup_fatfs(void)
command_ret = CMD_RET_FAILURE;
}
+/******************************************************************************/
+
+/*
+ * These functions manipulate paths in PATH_T structures.
+ *
+ * They eliminate multiple slashes in paths when they notice them,
+ * and keep the path non-slash terminated.
+ *
+ * Both path_set() and path_append() return 0 if the requested name
+ * would be too long.
+ */
+
+
+static void path_init(void)
+{
+ from.p_end = from.p_path; from.p_path[0] = '\0';
+ to.p_end = to.p_path; to.p_path[0] = '\0';
+}
+
+static void strip_trailing_slash(PATH_T *p)
+{
+ char *beg = p->p_path;
+ char *end = p->p_end;
+ if ((beg + 2) < end && (*beg & 0x38) == '0' && *(beg+1) == ':')
+ beg += 2;
+ if (beg < end && *beg == '/')
+ ++beg;
+ while (end > beg && end[-1] == '/')
+ *--end = '\0';
+
+ p->p_end =end;
+}
+
+/*
+ * Move specified string into path. Convert "" to "." to handle BSD
+ * semantics for a null path. Strip trailing slashes.
+ */
+int
+path_set(PATH_T *p, char *string)
+{
+ if (strlen(string) > MAX_PATHLEN) {
+ err(PSTR("set: '%s': name too long"), string);
+ return 0;
+ }
+
+ (void)strcpy(p->p_path, string);
+ p->p_end = p->p_path + strlen(p->p_path);
+
+ if (p->p_path == p->p_end) {
+ *p->p_end++ = '.';
+ *p->p_end = 0;
+ }
+
+ strip_trailing_slash(p);
+ return 1;
+}
+
+/*
+ * Append specified string to path, inserting '/' if necessary. Return a
+ * pointer to the old end of path for restoration.
+ */
+char *
+path_append(PATH_T *p, char *name)
+{
+ char *old = p->p_end;
+ int len = strlen(name);
+
+ /* The "+ 1" accounts for the '/' between old path and name. */
+ if ((len + p->p_end - p->p_path + 1) > MAX_PATHLEN) {
+ err(PSTR("append: '%s/%s': name too long"), p->p_path, name);
+ return(0);
+ }
+
+ /*
+ * This code should always be executed, since paths shouldn't
+ * end in '/'.
+ */
+ if (p->p_end[-1] != '/') {
+ *p->p_end++ = '/';
+ *p->p_end = '\0';
+ }
+
+ (void)strncat(p->p_end, name, len);
+ p->p_end += len;
+ *p->p_end = '\0';
+
+ strip_trailing_slash(p);
+ return old;
+}
+
+/*
+ * Restore path to previous value. (As returned by path_append.)
+ */
+void
+path_restore(PATH_T *p, char *old)
+{
+ p->p_end = old;
+ *p->p_end = '\0';
+}
+
+/*
+ * Return basename of path.
+ */
+char *path_basename(PATH_T *p)
+{
+ char *basename = strrchr(p->p_path, '/');
+
+ if (basename) {
+ ++basename;
+ } else {
+ basename = p->p_path;
+ if ((basename[0] & 0x38) == '0' && basename[1] == ':')
+ basename += 2;
+ }
+
+ return basename;
+}
+
static void swirl(void)
return CMD_RET_SUCCESS;
}
-#define MAX_PATHLEN CONFIG_SYS_MAX_PATHLEN
-
+#if 0
/*
* Remove trailing slashes,
* but keep a leading slash (absolute path)
while (n-- != 0 && p[n] == '/')
p[n] = '\0';
}
+#endif
int print_dirent(FILINFO *f)
{
unsigned int s1, s2;
FRESULT res;
- char *path = "";
- if (argc > 1)
- path = argv[1];
- strip_trailing_slash_relpath(path);
- char *p = strrchr(path, '/');
- if (p)
- p++;
- else {
- p = path;
- char *q = p;
- if ((*q++ & 0x38) == '0' && *q++ == ':')
- p = q;
- }
+ path_init();
+ if (argc > 1)
+ if (!path_set(&from, argv[1])) {
+ /* TODO: error out*/
+ }
- char *pattern;
+ char *p = path_basename(&from);
if (strpbrk_P(p, PSTR("*?")) ||
- (f_stat(path, &Finfo) == FR_OK && !(Finfo.fattrib & AM_DIR))) {
- pattern = strdup(p);
+ (f_stat(from.p_path, &Finfo) == FR_OK && !(Finfo.fattrib & AM_DIR))) {
+ path_set(&to, p);
*p = '\0';
- } else
- pattern = strdup("*");
- strip_trailing_slash_relpath(path);
+ } else {
+ to.p_path[0] = '*';
+ to.p_path[1] = '\0';
+ }
-//printf_P(PSTR("*: |%s| |%s|\n"), path ? path : "<NULL>", pattern ? pattern : "<NULL>");
+debug_ls("==== path: '%s', pattern: '%s'\n", from.p_path ? from.p_path : "<NULL>", to.p_path ? to.p_path : "<NULL>");
p1 = s1 = s2 = 0;
- res = f_findfirst(&Dir, &Finfo, path, pattern); /* Start to search for files */
+ res = f_findfirst(&Dir, &Finfo, from.p_path, to.p_path); /* Start to search for files */
while (res == FR_OK && Finfo.fname[0]) {
if (Finfo.fattrib & AM_DIR) {
s2++;
res = f_findnext(&Dir, &Finfo);
}
f_closedir(&Dir);
- free(pattern);
if (res == FR_OK) {
printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
- if (f_getfree(path, (DWORD*)&p1, &fs) == FR_OK)
+ if (f_getfree(from.p_path, (DWORD*)&p1, &fs) == FR_OK)
printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
}
char * buf = (char *) malloc(BUFFER_SIZE);
if (buf == NULL) {
- printf_P(PSTR("pwd: Out of Memory!\n"));
+ printf_P(PSTR("tst: Out of Memory!\n"));
free(buf);
return CMD_RET_FAILURE;
}
res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
if (!res) {
- printf_P(PSTR("cwd: |%s|\n"), buf);
+ printf_P(PSTR("cwd: '%s'\n"), buf);
}
free(buf);
if (res) {
else
path = "";
- printf_P(PSTR("arg: |%s|\n"), path);
+ printf_P(PSTR("arg: '%s'\n"), path);
printf_P(PSTR("==== f_stat: "));
res = f_stat(path, &Finfo);
put_rc(res);
return CMD_RET_SUCCESS;
}
-#if 0
-static
-FRESULT mkpath(TCHAR *path)
-{
- /* TODO: */
- (void) path;
- FILINFO fd
- TCHAR *p, *q;
- FRESULT ret;
-
- res = f_stat (path, &fd)
-
- p = strchr(path, ':');
- if (p == NULL || *++p == '\0' || *p++ != '/')
- return FR_OK;
-
- while ((q = strchr(p, '/')) != NULL) {
- *q = '\0';
- ret = f_mkdir(path);
- *q = '/';
- if (ret != FR_OK && ret != FR_EXIST)
- return ret;
- p = q + 1;
- }
-
- return FR_OK;
-}
-#endif
-
/******************************************************************************/
-/*
- * These functions manipulate paths in PATH_T structures.
- *
- * They eliminate multiple slashes in paths when they notice them,
- * and keep the path non-slash terminated.
- *
- * Both path_set() and path_append() return 0 if the requested name
- * would be too long.
- */
-
-
-typedef struct {
- char *p_end; /* pointer to NULL at end of path */
- char p_path[MAX_PATHLEN + 1]; /* pointer to the start of a path */
-} PATH_T;
-
-static void strip_trailing_slash(PATH_T *p)
-{
- while (p->p_end > p->p_path && p->p_end[-1] == '/')
- *--p->p_end = '\0';
-}
-
-/*
- * Move specified string into path. Convert "" to "." to handle BSD
- * semantics for a null path. Strip trailing slashes.
- */
-int
-path_set(PATH_T *p, char *string)
-{
- if (strlen(string) > MAX_PATHLEN) {
- err(PSTR("set: '%s': name too long"), string);
- return 0;
- }
-
- (void)strcpy(p->p_path, string);
- p->p_end = p->p_path + strlen(p->p_path);
-
- if (p->p_path == p->p_end) {
- *p->p_end++ = '.';
- *p->p_end = 0;
- }
-
- strip_trailing_slash(p);
- return 1;
-}
-
-/*
- * Append specified string to path, inserting '/' if necessary. Return a
- * pointer to the old end of path for restoration.
- */
-char *
-path_append(PATH_T *p, char *name, int len)
-{
- char *old;
-
- old = p->p_end;
- if (len == -1)
- len = strlen(name);
-
- /* The "+ 1" accounts for the '/' between old path and name. */
- if ((len + p->p_end - p->p_path + 1) > MAX_PATHLEN) {
- err(PSTR("append: '%s/%s': name too long"), p->p_path, name);
- return(0);
- }
-
- /*
- * This code should always be executed, since paths shouldn't
- * end in '/'.
- */
- if (p->p_end[-1] != '/') {
- *p->p_end++ = '/';
- *p->p_end = '\0';
- }
-
- (void)strncat(p->p_end, name, len);
- p->p_end += len;
- *p->p_end = '\0';
-
- strip_trailing_slash(p);
- return old;
-}
-
-/*
- * Restore path to previous value. (As returned by path_append.)
- */
-void
-path_restore(PATH_T *p, char *old)
-{
- p->p_end = old;
- *p->p_end = '\0';
-}
-
-/*
- * Return basename of path.
- */
-char *path_basename(PATH_T *p)
-{
- char *basename;
-
- basename = strrchr(p->p_path, '/');
- return(basename ? basename + 1 : p->p_path);
-}
-
-
static uint8_t flags;
-PATH_T *from;
-PATH_T *to;
-
#define F_FLAG (1<<3) // overwrite existing file ignoring write protection
#define I_FLAG (1<<1) // prompt before overwrite (overrides a previous -n option)
#define N_FLAG (1<<2) // do not overwrite an existing file (overrides a previous -i option)
#define V_FLAG (1<<5) // explain what is being done
static void
-setfile(FILINFO *fs, FIL *fd)
+setfile(FILINFO *fs)
{
- (void) fs;(void) fd;
-#if 0 /* TODO: */
- static struct timeval tv[2];
+ FRESULT fr;
- fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
+ fr = f_utime(to.p_path, fs);
+ if (fr != FR_OK)
+ err(PSTR("f_utime: %s: %S"), to.p_path, rctostr(fr));
+ fr = f_chmod(to.p_path, fs->fattrib, AM_RDO|AM_ARC|AM_SYS|AM_HID);
+ if (fr != FR_OK)
+ err(PSTR("f_chmod: %s: %S"), to.p_path, rctostr(fr));
- tv[0].tv_sec = fs->st_atime;
- tv[1].tv_sec = fs->st_mtime;
- if (utimes(to->p_path, tv))
- err(PSTR("utimes: %s: %s"), to->p_path, strerror(errno));
-#endif
}
void copy_file(FILINFO *fs, uint_fast8_t dne)
{
FIL from_fd, to_fd;
UINT rcount, wcount;
- //FILINFO to_stat;
- //char *p;
FRESULT fr;
-
- int buf_size = get_freemem() / 512 * 512;
- uint8_t * buf = (uint8_t *) malloc(buf_size);
- if (buf == NULL) {
- free(buf);
- err(PSTR("cp: Out of Memory!\n"));
- return;
+ BYTE open_mode;
+
+ if (blockbuf == NULL) {
+ blockbuf_size = get_freemem() / 512 * 512;
+ if (blockbuf_size != 0)
+ blockbuf = (uint8_t *) malloc(blockbuf_size);
+ if (blockbuf == NULL) {
+ err(PSTR("Not enough memory!\n"));
+ return;
+ }
}
-debug("==== copy_file(): dne: %u, buf_zize: %d\n", dne, buf_size);
-debug(" from:'%s' to:'%s'\n", from->p_path, to->p_path);
+debug_cp("==== copy_file(): dne: %u, blockbuf_size: %d\n", dne, blockbuf_size);
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
- if ((fr = f_open(&from_fd, from->p_path, FA_READ)) != FR_OK) {
- err(PSTR("%s: %S"), from->p_path, rctostr(fr));
+ if ((fr = f_open(&from_fd, from.p_path, FA_READ)) != FR_OK) {
+ err(PSTR("%s: %S"), from.p_path, rctostr(fr));
return;
}
/*
* If the file exists and we're interactive, verify with the user.
- * If the file DNE, set the mode to be the from file, minus setuid
- * bits, modified by the umask; arguably wrong, but it makes copying
- * executables work right and it's been that way forever. (The
- * other choice is 666 or'ed with the execute bits on the from file
- * modified by the umask.)
*/
if (!dne) {
- if (flags & I_FLAG) {
- printf_P(PSTR("overwrite '%s'? "), to->p_path);
+ if (flags & N_FLAG) {
+ if (flags & V_FLAG)
+ printf_P(PSTR("%s not overwritten\n"), to.p_path);
+ f_close(&from_fd);
+ return;
+ } if (flags & I_FLAG) {
+ printf_P(PSTR("overwrite '%s'? "), to.p_path);
if (!confirm_yes()) {
f_close(&from_fd);
return;
}
}
- fr = f_open(&to_fd, to->p_path, FA_WRITE|FA_CREATE_ALWAYS);
- } else
- fr = f_open(&to_fd, to->p_path, FA_WRITE|FA_CREATE_NEW);
+ if (flags & F_FLAG) {
+ /* Remove existing destination file name create a new file. */
+ f_chmod(to.p_path,0, AM_RDO);
+ f_unlink(to.p_path);
+ open_mode = FA_WRITE|FA_CREATE_NEW;
+ } else {
+ /* Overwrite existing destination file name. */
+ open_mode = FA_WRITE|FA_CREATE_ALWAYS;
+ }
+ } else {
+ open_mode = FA_WRITE|FA_CREATE_NEW;
+ }
+ fr = f_open(&to_fd, to.p_path, open_mode);
if (fr != FR_OK) {
- err(PSTR("%s: %S"), to->p_path, rctostr(fr));
+ err(PSTR("%s: %S"), to.p_path, rctostr(fr));
f_close(&from_fd);
return;
}
- while ((fr = f_read(&from_fd, buf, buf_size, &rcount)) == FR_OK &&
+ while ((fr = f_read(&from_fd, blockbuf, blockbuf_size, &rcount)) == FR_OK &&
rcount > 0) {
- fr = f_write(&to_fd, buf, rcount, &wcount);
+ fr = f_write(&to_fd, blockbuf, rcount, &wcount);
if (fr || wcount < rcount) {
- err(PSTR("%s: %S"), to->p_path, rctostr(fr));
+ err(PSTR("%s: %S"), to.p_path, rctostr(fr));
break;
}
}
if (fr != FR_OK)
- err(PSTR("%s: S"), from->p_path, rctostr(fr));
-
- if (flags & P_FLAG)
- setfile(fs, &to_fd);
+ err(PSTR("%s: S"), from.p_path, rctostr(fr));
f_close(&from_fd);
if ((fr = f_close(&to_fd)) != FR_OK)
- err(PSTR("%s: %S"), to->p_path, rctostr(fr));
+ err(PSTR("%s: %S"), to.p_path, rctostr(fr));
+
+ if (flags & P_FLAG)
+ setfile(fs);
}
-#if 1
+static void copy();
+
+#if 0
static void copy_dir(void)
{
-debug("==== copy_dir()");
-debug(" from:'%s' to:'%s'\n", from->p_path, to->p_path);
+debug_cp("==== copy_dir()");
+debug_cp(" from:'%s' to:'%s'\n", from->p_path, to.p_path);
printf_P(PSTR("directory copy not supported, ommitting dir '%s'\n"),
from->p_path);
}
#else
static void copy_dir(void)
+{
+ DIR Dir; /* Directory object */
+ FILINFO Finfo;
+ char *old_from, *old_to;
+ FRESULT res;
+ char *pattern = {"*"};
+
+debug_cp("==== copy_dir()");
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
+
+
+ for (res = f_findfirst(&Dir, &Finfo, from.p_path, pattern);
+ res == FR_OK && Finfo.fname[0];
+ res = f_findfirst(&Dir, &Finfo, from.p_path, pattern)) {
+
+ if (!(Finfo.fattrib & AM_DIR) &&
+ (old_from = path_append(&from, Finfo.fname))) {
+ if ((old_to = path_append(&to, Finfo.fname))) {
+ copy();
+ path_restore(&to, old_to);
+ }
+ path_restore(&from, old_from);
+ }
+ }
+
+ for (res = f_findfirst(&Dir, &Finfo, from.p_path, pattern);
+ res == FR_OK && Finfo.fname[0];
+ res = f_findnext(&Dir, &Finfo)) {
+
+ if ((Finfo.fattrib & AM_DIR) &&
+ (old_from = path_append(&from, Finfo.fname))) {
+ if ((old_to = path_append(&to, Finfo.fname))) {
+ copy();
+ path_restore(&to, old_to);
+ }
+ path_restore(&from, old_from);
+ }
+ }
+}
+#endif
+#if 0
+static void copy_dir(void)
{
FILINFO from_stat;
struct dirent *dp, **dir_list;
int dir_cnt, i;
char *old_from, *old_to;
-debug("==== copy_file(): dne: %u\n", dne);
-debug(" from:'%s' to:'%s'\n", from->p_path, to->p_path);
+debug_cp("==== copy_file(): dne: %u\n", dne);
+debug_cp(" from:'%s' to:'%s'\n", from->p_path, to.p_path);
dir_cnt = scandir(from->p_path, &dir_list, NULL, NULL);
if (dir_cnt == -1) {
uint_fast8_t dne;
FRESULT fr;
-debug("==== copy()\n");
-debug(" from:'%s' to:'%s'\n", from->p_path, to->p_path);
+debug_cp("==== copy()\n");
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
- fr = f_stat(from->p_path, &from_stat);
+ fr = f_stat(from.p_path, &from_stat);
if (fr != FR_OK) {
- err(PSTR("%s: %S"), from->p_path, rctostr(fr));
+ err(PSTR("%s: %S"), from.p_path, rctostr(fr));
return;
}
/* not an error, but need to remember it happened */
- if (f_stat(to->p_path, &to_stat) != FR_OK)
+ if (f_stat(to.p_path, &to_stat) != FR_OK)
dne = 1;
else {
- if (strcmp(to->p_path, from->p_path) == 0) {
+ if (strcmp(to.p_path, from.p_path) == 0) {
(void)printf_P(PSTR("%s and %s are identical (not copied).\n"),
- to->p_path, from->p_path);
+ to.p_path, from.p_path);
command_ret = CMD_RET_FAILURE;
return;
}
if(from_stat.fattrib & AM_DIR) {
if (!(flags & R_FLAG)) {
(void)printf_P(PSTR("-r not specified; ommitting dir '%s'\n"),
- from->p_path);
+ from.p_path);
command_ret = CMD_RET_FAILURE;
return;
}
/*
* If the directory doesn't exist, create the new one.
*/
- if ((fr = f_mkdir(to->p_path)) != FR_OK) {
- err(PSTR("%s: %S"), to->p_path, rctostr(fr));
+ if ((fr = f_mkdir(to.p_path)) != FR_OK) {
+ err(PSTR("%s: %S"), to.p_path, rctostr(fr));
return;
}
}
else if (!(to_stat.fattrib & AM_DIR)) {
- (void)printf_P(PSTR("%s: not a directory.\n"), to->p_path);
+ (void)printf_P(PSTR("%s: not a directory.\n"), to.p_path);
return;
}
copy_dir();
if (flags & P_FLAG)
- setfile(&from_stat, 0);
+ setfile(&from_stat);
return;
}
optind = 0;
int opt;
-// while ((opt = getopt(argc, argv, PSTR("fiprv"))) != -1) {
- while ((opt = getopt(argc, argv, PSTR("fiprv"))) != -1) {
+ while ((opt = getopt(argc, argv, PSTR("finprv"))) != -1) {
switch (opt) {
case 'f':
tflags &= ~(I_FLAG | N_FLAG);
if (argc < 2)
return CMD_RET_USAGE;
- from = (PATH_T *) malloc(sizeof(PATH_T));
- to = (PATH_T *) malloc(sizeof(PATH_T));
- if (from == NULL || to == NULL) {
- printf_P(PSTR("cp: Out of Memory!\n"));
- command_ret = CMD_RET_FAILURE;
- goto cleanup;
- }
- from->p_end = from->p_path; *from->p_path = '\0';
- to->p_end = to->p_path; *to->p_path = '\0';
+ path_init();
- /* consume last argument first. */
- if (!path_set(to, argv[--argc])) {
- command_ret = CMD_RET_FAILURE;
+ /* last argument is destination */
+ if (!path_set(&to, argv[--argc]))
goto cleanup;
- }
/*
* Cp has two distinct cases:
* In (2), the real target is not directory, but "directory/source".
*/
- fr = f_stat(to->p_path, &to_stat);
-debug("==== main, stat to: fr: %d, attr: %02x, flags:%02x\n", fr, to_stat.fattrib, flags);
-debug(" from:'%s' to:'%s'\n", from->p_path, to->p_path);
+ fr = f_stat(to.p_path, &to_stat);
+debug_cp("==== main, stat to: fr: %d, attr: %02x, flags:%02x\n", fr, to_stat.fattrib, flags);
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
if (fr != FR_OK && fr != FR_NO_FILE && fr != FR_NO_PATH) {
- err(PSTR("Test1: %s: %S"), to->p_path, rctostr(fr));
+ err(PSTR("Test1: %s: %S"), to.p_path, rctostr(fr));
command_ret = CMD_RET_FAILURE;
goto cleanup;
}
* Case (1). Target is not a directory.
*/
if (argc > 1) {
- err(PSTR("target '%s' is not a directory"), to->p_path);
+ err(PSTR("target '%s' is not a directory"), to.p_path);
//command_ret = CMD_RET_USAGE;
goto cleanup;
}
- if (!path_set(from, *argv)) {
+ if (!path_set(&from, *argv)) {
command_ret = CMD_RET_FAILURE;
goto cleanup;
}
* Case (2). Target is a directory.
*/
for (;; ++argv) {
- if (!path_set(from, *argv))
+ if (!path_set(&from, *argv))
continue;
- if (!(old_to = path_append(to, path_basename(from), -1)))
+ if (!(old_to = path_append(&to, path_basename(&from))))
continue;
copy();
if (!--argc)
break;
- path_restore(to, old_to);
+ path_restore(&to, old_to);
}
}
cleanup:
- free(to);
- free(from);
+ free(blockbuf);
+ blockbuf = NULL;
+ blockbuf_size = 0;
return command_ret;
}
#if 0
if (flags & V_FLAG)
- printf_P((PSTR("%s %s -> %s\n", badcp ? : "ERR:" : " ", curr->fts_path, to->p_path)));
+ printf_P((PSTR("%s %s -> %s\n", badcp ? : "ERR:" : " ", curr->fts_path, to.p_path)));
#endif