+
+ return ps;
+}
+
+command_ret_t do_mkdir(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ int ret = CMD_RET_SUCCESS;
+ FRESULT res;
+
+ if (argc < 1)
+ return CMD_RET_USAGE;
+
+ for (uint8_t i = 1; i < argc; i++) {
+ if ((res = f_mkdir(argv[i])) != FR_OK) {
+ ret = CMD_RET_FAILURE;
+ cmd_error(0, res, PSTR("cannot create directory '%s'"), argv[i]);
+ }
+ }
+ return ret;
+}
+
+/*
+ * ls path - Directory listing
+ *
+ */
+command_ret_t do_ls(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ FATFS *fs;
+ DIR dir; /* Directory object */
+ FILINFO finfo;
+ unsigned long p1;
+ unsigned int s1, s2;
+ FRESULT res = FR_OK;
+ char buf[PATH_MAX];
+ char *path = buf;
+ char *pattern;
+
+
+ memset(buf, 0, PATH_MAX);
+ if (argc < 2) {
+ buf[0] = '.';
+ } else {
+ strncpy(path, argv[1], PATH_MAX-1);
+ }
+ pattern = path_split(path);
+ debug_ls("### path, pattern: '%s', '%s'\n", path[0] ? path : "<NULL>", pattern ? pattern : "<NULL>");
+
+ if (pattern == NULL) {
+ res = f_opendir(&dir, path);
+ if (res == FR_NO_PATH || res == FR_INVALID_NAME) {
+ pattern = path;
+ path = ".";
+ } else if (res != FR_OK) {
+ cmd_error(CMD_RET_FAILURE, res, PSTR("'%s'"), path);
+ }
+ }
+ debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : "<NULL>");
+
+ if (pattern == NULL || *pattern == '\0')
+ pattern = "*";
+
+ debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : "<NULL>");
+
+ res = f_findfirst(&dir, &finfo, path, pattern);
+
+ p1 = s1 = s2 = 0;
+ for(;;) {
+ if (res != FR_OK)
+ cmd_error(CMD_RET_FAILURE, res, NULL);
+ if (!finfo.fname[0])
+ break;
+ if (finfo.fattrib & AM_DIR) {
+ s2++;
+ } else {
+ s1++; p1 += finfo.fsize;
+ }
+ print_dirent(&finfo);
+ if (check_abort())
+ break;
+ res = f_findnext(&dir, &finfo);
+ }
+
+ 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)
+ printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
+ }
+
+ if (res)
+ cmd_error(CMD_RET_FAILURE, res, NULL);
+
+ return CMD_RET_SUCCESS;
+}
+
+
+typedef void (*fatfunc_t)(const TCHAR* path_old, const TCHAR* path_new);
+
+command_ret_t exit_val;
+uint8_t cmd_flags;
+#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 F_FLAG (1<<3) // overwrite existing file ignoring write protection
+#define P_FLAG (1<<4) // preserve attributes and timestamps
+#define V_FLAG (1<<5) // explain what is being done
+
+char* splitpath(const char* path)
+{
+ char* fs = strrchr(path, '/');
+ char* bs = strrchr(path, '\\');
+ if (fs > bs) {
+ *fs = '\0';
+ return fs + 1;
+ } else if (bs != NULL) {
+ *bs = '\0';
+ return bs + 1;
+ }
+ return NULL;
+}
+
+/*
+ * Copy File
+*/
+FRESULT copy_file(const TCHAR* src, const TCHAR* dst)
+{
+ FIL fsrc, fdst;
+ FRESULT res;
+
+ /* File copy buffer */
+ uint8_t *buffer = (uint8_t *) malloc(CPY_BUF_SIZE);
+ if (buffer == NULL) {
+ res = (FRESULT) ENOMEM;
+ } else {
+
+ /* Open source file */
+ res = f_open(&fsrc, src, FA_READ);
+ if (res == FR_OK) {
+
+ /* Create destination file */
+ res = f_open(&fdst, dst, FA_WRITE | FA_CREATE_NEW);
+ if (res == FR_OK) {
+ UINT br, bw; /* File read/write count */
+
+ /* Copy source to destination */
+ for (;;) {
+ res = f_read(&fsrc, buffer, CPY_BUF_SIZE, &br); /* Read a chunk of source file */
+ if (res || br == 0)
+ break; /* error or eof */
+ res = f_write(&fdst, buffer, br, &bw); /* Write it to the destination file */
+ if (res != FR_OK)
+ break;
+ if (bw < br) {
+ res = (FRESULT) EFULL; /* disk full */
+ break;
+ }
+ }
+
+debug_cp("==== copy() res: %d, br: %d, bw: %d\n", res, br, bw);
+ f_close(&fdst);
+ if (res != FR_OK)
+ f_unlink(dst);
+ }
+ f_close(&fsrc);
+ }
+ free(buffer);
+ }
+
+ return res;
+}
+
+void ff_remove(const TCHAR *file, const TCHAR *dest UNUSED)
+{
+ FRESULT res = FR_OK;
+
+ debug_rm("==== ff_remove: '%s'\n", file);
+
+ if (!(cmd_flags & N_FLAG)) {
+ if ((res = f_unlink(file)) == FR_OK) {
+ if (cmd_flags & V_FLAG)
+ printf_P(PSTR("removed: '%s'\n"), file);
+ } else {
+ cmd_error(0, res, PSTR("cannot remove '%s'"), file);
+ }
+ } else {
+ printf_P(PSTR("not removed: '%s'\n"), file);
+ }
+
+ exit_val = (res != FR_OK);
+ return;
+}
+
+void ff_copy(const TCHAR* path_old, const TCHAR* path_new)
+{
+ FRESULT res;
+
+ debug_cp("==== ff_copy: '%s' --> '%s'\n", path_old, path_new);
+
+ if (cmd_flags & V_FLAG)
+ printf_P(PSTR("'%s' -> '%s'\n"), path_old, path_new);
+ if ((res = copy_file(path_old, path_new)) != FR_OK)
+ cmd_error(0, res, PSTR("error copying '%s' to '%s'"), path_old, path_new);
+
+ exit_val = (res != FR_OK);
+ return;
+}
+
+void ff_move(const TCHAR* path_old, const TCHAR* path_new)
+{
+ FRESULT res;
+
+ if (cmd_flags & V_FLAG)
+ printf_P(PSTR("'%s' -> '%s'\n"), path_old, path_new);
+ if ((res = f_rename(path_old, path_new)) != FR_OK)
+ cmd_error(0, res, PSTR("error copying '%s' to '%s'"), path_old, path_new);
+
+ exit_val = (res != FR_OK);
+ return;
+}
+
+void ff_iterate(fatfunc_t fatfunc, int count, char* const file[], char* dest)
+{
+ FRESULT res = 0;
+ DIR dir;
+ FILINFO finfo;
+ char srcpath[PATH_MAX], destpath[PATH_MAX];
+
+ uint8_t dest_is_dir = dest != NULL && f_stat(dest, &finfo) == FR_OK && finfo.fattrib & AM_DIR;
+ for (uint8_t i = 0; i < count; i++) {
+ char* pattern = NULL;
+ strcpy(srcpath, file[i]);
+ char* p1 = path_split(srcpath);
+
+ if (p1 != NULL) {
+ pattern = (char *) malloc(strlen(p1)+1);
+ strcpy(pattern, p1);
+ }
+ if (pattern != NULL) {
+ res = f_findfirst(&dir, &finfo, srcpath, pattern);
+ p1 = srcpath+strlen(srcpath)-1;
+ if (*p1++ != '/')
+ *(p1++) = '/';
+ } else {
+ res = f_findfirst(&dir, &finfo, ".", file[i]);
+ p1 = srcpath;
+ }
+ if ((res != FR_OK) || (finfo.fname[0] == 0)) {
+ cmd_error(0, res, PSTR("'%s': no such file or directory"), file[i]);
+ exit_val = CMD_RET_FAILURE;
+ } else {
+
+ while (res == FR_OK && finfo.fname[0] != 0) {
+ strcpy(p1, finfo.fname);
+ if (dest != NULL) {
+ strcpy(destpath, dest);
+ if (dest_is_dir) {
+ strcat_P(destpath, PSTR("/"));
+ strcat(destpath, finfo.fname);
+ }
+ }
+ fatfunc(srcpath, destpath);
+ res = f_findnext(&dir, &finfo);
+ }
+ if (res != FR_OK)
+ cmd_error(CMD_RET_FAILURE, res, PSTR("error enumerating files"));
+ }
+ f_closedir(&dir);
+ free(pattern);
+ }
+}
+
+command_ret_t do_rm(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ exit_val = CMD_RET_SUCCESS;
+ cmd_flags = 0;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("nv"))) != -1) {
+ switch (opt) {
+ case 'n':
+ cmd_flags |= N_FLAG;
+ break;
+ case 'v':
+ cmd_flags |= V_FLAG;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ debug_rm("==== do_rm: argc, argv[0]: %d, '%s'\n", argc, argv[0]);
+
+ if (argc < 1)
+ return CMD_RET_USAGE;
+
+ ff_iterate(ff_remove, argc, argv, NULL);
+
+ return exit_val;
+}
+
+command_ret_t do_cp_or_mv(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ exit_val = CMD_RET_SUCCESS;
+ cmd_flags = 0;
+ fatfunc_t func = (argv[0][0] == 'c') ? ff_copy : ff_move;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("v"))) != -1) {
+ switch (opt) {
+ case 'v':
+ cmd_flags |= V_FLAG;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ debug_cp("==== do_rm: argc, argv[0]: %d, '%s'\n", argc, argv[0]);
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ ff_iterate(func, argc - 1, argv, argv[argc - 1]);
+
+ return exit_val;
+}
+
+/*
+ * tst path - for debugging: test access with different functions
+ *
+ */
+command_ret_t do_tst(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ DIR Dir; /* Directory object */
+ FILINFO finfo;
+ FRESULT res = FR_OK;
+ char *path = "";
+ char *pattern = "*";
+
+ printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO));
+
+ char * buf = (char *) malloc(BUFFER_SIZE);
+ if (buf == NULL) {
+ cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
+ }
+ res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
+
+ if (!res) {
+ printf_P(PSTR("cwd: '%s'\n"), buf);
+ }
+ free(buf);
+ if (res)
+ cmd_error(CMD_RET_FAILURE, res, NULL);
+
+ if (argc > 1)
+ path = argv[1];
+ 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);
+ cmd_error(0, res, NULL);
+ if (res == FR_OK) {
+ print_dirent(&finfo);
+ }
+
+ printf_P(PSTR("==== f_findfirst: "));
+ res = f_findfirst(&Dir, &finfo, path, pattern); /* Start to search for files */
+ cmd_error(CMD_RET_FAILURE, res, NULL);
+ if (res == FR_OK) {
+ print_dirent(&finfo);
+ }
+ f_closedir(&Dir);
+
+ printf_P(PSTR("==== f_opendir: "));
+ res = f_opendir(&Dir, path);
+ cmd_error(CMD_RET_FAILURE, res, NULL);
+ f_closedir(&Dir);
+
+ return CMD_RET_SUCCESS;