+ if (argc > 2)
+ pattern = argv[2];
+
+ printf_P(PSTR("arg: '%s' '%s'\n"), path, pattern);
+ printf_P(PSTR("==== f_stat: "));
+ res = f_stat(path, &Finfo);
+ put_rc(res);
+ if (res == FR_OK) {
+ print_dirent(&Finfo);
+ }
+
+ printf_P(PSTR("==== f_findfirst: "));
+ res = f_findfirst(&Dir, &Finfo, path, pattern); /* Start to search for files */
+ put_rc(res);
+ if (res == FR_OK) {
+ print_dirent(&Finfo);
+ }
+ f_closedir(&Dir);
+
+ printf_P(PSTR("==== f_opendir: "));
+ res = f_opendir(&Dir, path);
+ put_rc(res);
+ f_closedir(&Dir);
+
+ return CMD_RET_SUCCESS;
+}
+
+/******************************************************************************/
+
+static void
+setfile(FILINFO *fs)
+{
+ FRESULT fr;
+
+ 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));
+
+}
+
+void copy_file(FILINFO *fs, uint_fast8_t dne)
+{
+ FIL from_fd, to_fd;
+ UINT rcount, wcount;
+ FRESULT fr;
+ 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_cp("==== copy_file(): dne: %u, blockbuf_size: %d, freemem: %u\n", dne, blockbuf_size, get_freemem());
+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));
+ return;
+ }
+
+ /*
+ * If the file exists and we're interactive, verify with the user.
+ */
+ if (!dne) {
+ 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;
+ }
+ }
+ 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));
+ f_close(&from_fd);
+ return;
+ }
+
+ while ((fr = f_read(&from_fd, blockbuf, blockbuf_size, &rcount)) == FR_OK &&
+ rcount > 0) {
+ fr = f_write(&to_fd, blockbuf, rcount, &wcount);
+ if (fr || wcount < rcount) {
+ err(PSTR("%s: %S"), to.p_path, rctostr(fr));
+ break;
+ }
+ }
+ if (fr != FR_OK)
+ 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));
+
+ if (flags & P_FLAG)
+ setfile(fs);
+}
+
+static void copy();
+
+static void copy_dir(void)
+{
+ DIR Dir; /* Directory object */
+ FILINFO Finfo;
+ char *old_from, *old_to;
+ FRESULT res;
+ char *pattern = {"*"};
+
+debug_cp("==== copy_dir(): freemem: %u\n", get_freemem());
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
+
+#if 0
+
+ printf_P(PSTR("directory copy not supported, ommitting dir '%s'\n"),
+ from->p_path);
+ command_ret = CMD_RET_FAILURE;
+
+#else
+
+ 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);
+ }
+ }
+
+ 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
+
+/*
+ * copy file or directory at "from" to "to".
+ */
+static void copy()
+{
+ FILINFO from_stat, to_stat;
+ uint_fast8_t dne;
+ FRESULT fr;
+
+debug_cp("==== copy(); freemem: %u\n", get_freemem());
+debug_cp(" from:'%s' to:'%s'\n", from.p_path, to.p_path);
+
+ fr = f_stat(from.p_path, &from_stat);
+ if (fr != FR_OK) {
+ 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)
+ dne = 1;
+ else {
+ 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);
+ command_ret = CMD_RET_FAILURE;
+ return;
+ }
+ dne = 0;
+ }
+
+ if(from_stat.fattrib & AM_DIR) {
+ if (!(flags & R_FLAG)) {
+ (void)printf_P(PSTR("-r not specified; ommitting dir '%s'\n"),
+ from.p_path);
+ command_ret = CMD_RET_FAILURE;
+ return;
+ }
+ if (dne) {
+ /*
+ * 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));
+ return;
+ }
+ } else if (!(to_stat.fattrib & AM_DIR)) {
+ (void)printf_P(PSTR("%s: not a directory.\n"), to.p_path);
+ return;
+ }
+ copy_dir();
+ if (flags & P_FLAG)
+ setfile(&from_stat);
+
+ return;
+ }
+ copy_file(&from_stat, dne);
+}
+
+command_ret_t do_cp(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+
+ FRESULT fr; /* Return value */
+ //DIR dj; /* Directory search object */
+ FILINFO to_stat; /* File information */
+ char *old_to;
+
+
+ cmdname = argv[0];
+ uint8_t tflags = 0;
+ command_ret = CMD_RET_SUCCESS;
+
+ /* reset getopt() */
+ optind = 0;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("finprv"))) != -1) {
+ switch (opt) {
+ case 'f':
+ tflags &= ~(I_FLAG | N_FLAG);
+ tflags |= F_FLAG;
+ break;
+ case 'i':
+ tflags &= ~(F_FLAG | N_FLAG);
+ tflags |= I_FLAG;
+ break;
+ case 'n':
+ tflags &= ~(F_FLAG | I_FLAG);
+ tflags |= N_FLAG;
+ break;
+ case 'p':
+ tflags |= P_FLAG;
+ break;
+ case 'r':
+ tflags |= R_FLAG;
+ break;
+ case 'v':
+ tflags |= V_FLAG;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ break;
+ }
+ }
+ flags = tflags;
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;