]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_fat.c
working fat ls whith relative path and wildcards
[z180-stamp.git] / avr / cmd_fat.c
CommitLineData
35edb766 1/*
2d914b45 2 * (C) Copyright 2014,2016 Leo C. <erbl259-lmu@yahoo.de>
35edb766 3 *
2d914b45 4 * SPDX-License-Identifier: GPL-2.0
35edb766
L
5 */
6
7/*
8 * FAT filesystem commands
9 */
10
b6c04275 11#include "cmd_fat.h"
2f53dd65 12#include "common.h"
2f53dd65
L
13#include <string.h>
14#include <stdbool.h>
15
16#include "command.h"
17#include "ff.h"
18#include "z80-if.h"
2d914b45 19#include "eval_arg.h"
4565be9a 20#include "con-utils.h"
2f53dd65 21#include "print-utils.h"
19b9a7d8 22#include "time.h"
2f53dd65 23#include "timer.h"
4f881b02 24#include "debug.h"
b6c04275 25#include "env.h"
3d8c1907 26#include "getopt-min.h"
2f53dd65 27
5f7f3586
L
28/* TODO: use memory size test function (cmd_mem.c) */
29#define MAX_MEMORY (1ul << 19)
19b9a7d8
L
30#define BUFFER_SIZE 512
31
4565be9a 32
b6c04275
L
33FATFS FatFs0;
34FATFS FatFs1;
35
36char chur_drv[3];
37
2f53dd65
L
38DWORD get_fattime (void)
39{
19b9a7d8
L
40 time_t timer;
41 struct tm tm_timer;
42
43 time(&timer);
44 gmtime_r(&timer, &tm_timer);
45
46 return fatfs_time(&tm_timer);
2f53dd65
L
47}
48
49
b15d22a4
L
50static bool check_abort(void)
51{
52 bool ret = ctrlc();
53
54 if (ret)
55 printf_P(PSTR("Abort\n"));
56
57 return ret;
58}
59
60
2f53dd65
L
61static const FLASH char * const FLASH rc_names[] = {
62 FSTR("OK"),
63 FSTR("DISK_ERR"),
64 FSTR("INT_ERR"),
65 FSTR("NOT_READY"),
66 FSTR("NO_FILE"),
67 FSTR("NO_PATH"),
68 FSTR("INVALID_NAME"),
69 FSTR("DENIED"),
70 FSTR("EXIST"),
71 FSTR("INVALID_OBJECT"),
72 FSTR("WRITE_PROTECTED"),
73 FSTR("INVALID_DRIVE"),
74 FSTR("NOT_ENABLED"),
75 FSTR("NO_FILE_SYSTEM"),
76 FSTR("MKFS_ABORTED"),
77 FSTR("TIMEOUT"),
78 FSTR("LOCKED"),
79 FSTR("NOT_ENOUGH_CORE"),
7af9364e
L
80 FSTR("TOO_MANY_OPEN_FILES"),
81 FSTR("INVALID_PARAMETER")
2f53dd65
L
82 };
83
84static
85void put_rc (FRESULT rc)
86{
87#if GCC_BUG_61443
7af9364e
L
88 printf_P(PSTR("rc=%u FR_"), rc);
89 my_puts_P(rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
90 my_puts_P(PSTR("\n"));
2f53dd65 91#else
7af9364e
L
92 printf_P(PSTR("rc=%u FR_%S\n"), rc,
93 rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
2f53dd65
L
94#endif
95}
96
b15d22a4 97
b6c04275
L
98void setup_fatfs(void)
99{
100 f_mount(&FatFs0, "0:", 0);
101 f_mount(&FatFs1, "1:", 0);
102}
103
104
b15d22a4
L
105static void swirl(void)
106{
6204987c 107 static const FLASH char swirlchar[] = { '-','\\','|','/' };
b15d22a4
L
108 static uint_fast8_t cnt;
109 static uint32_t tstamp;
110
111 if (get_timer(0) > tstamp) {
112 printf_P(PSTR("\b%c"), swirlchar[cnt]);
113 cnt = (cnt+1) % ARRAY_SIZE(swirlchar);
6204987c 114 tstamp = get_timer(0) + 250;
b15d22a4
L
115 }
116}
117
6204987c
L
118/* Work register for fs command */
119struct stat_dat_s {
120 DWORD AccSize;
121 WORD AccFiles, AccDirs;
122 FILINFO Finfo;
123};
124
2f53dd65
L
125static
126FRESULT scan_files (
6204987c
L
127 char *path, /* Pointer to the working buffer with start path */
128 struct stat_dat_s *statp
2f53dd65
L
129)
130{
131 DIR dirs;
132 FRESULT res;
133 int i;
134 char *fn;
135
136 res = f_opendir(&dirs, path);
b15d22a4 137 swirl();
2f53dd65
L
138 if (res == FR_OK) {
139 i = strlen(path);
6204987c
L
140 while (((res = f_readdir(&dirs, &statp->Finfo)) == FR_OK) &&
141 statp->Finfo.fname[0]) {
142 if (_FS_RPATH && statp->Finfo.fname[0] == '.')
143 continue;
144 fn = statp->Finfo.fname;
145 if (statp->Finfo.fattrib & AM_DIR) {
146 statp->AccDirs++;
147 path[i] = '/';
148 strcpy(path+i+1, fn);
149 res = scan_files(path, statp);
2f53dd65 150 path[i] = '\0';
6204987c
L
151 if (res != FR_OK)
152 break;
2f53dd65 153 } else {
6204987c
L
154 //printf_P(PSTR("%s/%s\n"), path, fn);
155 statp->AccFiles++;
156 statp->AccSize += statp->Finfo.fsize;
2f53dd65 157 }
b15d22a4
L
158 if (check_abort()) {
159 res = 255;
160 break;
161 }
2f53dd65
L
162 }
163 }
164
165 return res;
166}
167
168
169/*
170 * fatstat path - Show logical drive status
171 *
172 */
b6c04275 173command_ret_t do_stat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2f53dd65 174{
bbd45c46 175 FATFS *fs;
4565be9a 176 DWORD nfreeclst;
2f53dd65 177 FRESULT res;
3d8c1907
L
178 char *buf;
179 char *path = "";
6204987c 180 struct stat_dat_s statp;
2f53dd65
L
181
182 (void) cmdtp; (void) flag; (void) argc;
183
3d8c1907
L
184 buf = (char *) malloc(BUFFER_SIZE);
185 if (buf == NULL) {
186 printf_P(PSTR("fat stat: Out of Memory!\n"));
2f53dd65
L
187 return CMD_RET_FAILURE;
188 }
189
3d8c1907
L
190 if (argc > 1)
191 path = argv[1];
192 res = f_getfree(path, &nfreeclst, &fs);
4565be9a 193 if (!res) {
bbd45c46
L
194 printf_P(PSTR(
195 "FAT type: %u\n"
196 "Bytes/Cluster: %lu\n"
197 "Number of FATs: %u\n"
198 "Root DIR entries: %u\n"
199 "Sectors/FAT: %lu\n"
200 "Number of clusters: %lu\n"
201 "FAT start (lba): %lu\n"
202 "DIR start (lba,cluster): %lu\n"
203 "Data start (lba): %lu\n"),
204 fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
205 fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
206 fs->fatbase, fs->dirbase, fs->database);
2f53dd65
L
207
208#if _USE_LABEL
bbd45c46 209 DWORD serial;
3d8c1907 210 res = f_getlabel(path, buf, &serial);
bbd45c46
L
211 if (!res) {
212 printf_P(PSTR(
213 "Volume name: %s\n"
214 "Volume S/N: %04X-%04X\n"),
3d8c1907 215 buf, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
bbd45c46 216 }
2f53dd65 217#endif
bbd45c46
L
218 if (!res) {
219 my_puts_P(PSTR("\nCounting... "));
220 statp.AccSize = statp.AccFiles = statp.AccDirs = 0;
3d8c1907 221 strcpy(buf, path);
2f53dd65 222
3d8c1907 223 res = scan_files(buf, &statp);
bbd45c46
L
224 }
225 if (!res) {
226 printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
227 "%lu KB total disk space.\n%lu KB available.\n"),
228 statp.AccFiles, statp.AccSize, statp.AccDirs,
229 (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
230 );
4565be9a 231 }
2f53dd65 232 }
2f53dd65 233
3d8c1907 234 free(buf);
2f53dd65
L
235 if (res) {
236 put_rc(res);
237 return CMD_RET_FAILURE;
238 }
239 return CMD_RET_SUCCESS;
240}
241
b6c04275
L
242/*
243 * pwd - Print current directory of the current drive.
244 *
245 */
246command_ret_t do_pwd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
247{
248 FRESULT res;
249 char *buf;
250
251 (void) cmdtp; (void) flag; (void) argc; (void) argv;
252
253 buf = (char *) malloc(BUFFER_SIZE);
254 if (buf == NULL) {
255 printf_P(PSTR("pwd: Out of Memory!\n"));
256 free(buf);
257 return CMD_RET_FAILURE;
258 }
259
260 res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
261
262 if (!res) {
263 puts(buf);
264 }
265 free(buf);
266 if (res) {
267 put_rc(res);
268 return CMD_RET_FAILURE;
269 }
270 return CMD_RET_SUCCESS;
271}
272
273
274/*
275 * cd - Change the current/working directory.
276 *
277 */
278command_ret_t do_cd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
279{
280 char *arg;
281 FRESULT res = 0;
282
283 (void) cmdtp; (void) flag; (void) argc;
284
285 if (argc < 2) {
ee5c86e9 286 arg = getenv_str(PSTR(ENV_HOME));
b6c04275 287 if (arg == NULL) {
ee5c86e9 288 printf_P(PSTR("%s: \"%S\" is not set\n"), argv[0], PSTR(ENV_HOME));
b6c04275
L
289 return CMD_RET_FAILURE;
290 }
291 } else
292 arg = argv[1];
293
294 if (arg[1] == ':') {
295 char drv[3];
296 drv[2] = '\0';
297 drv[1] = ':';
298 drv[0] = arg[0];
299 res = f_chdrive(drv);
300 }
301 if (!res) {
302 res = f_chdir(arg);
303 }
304
305 if (res) {
306 put_rc(res);
307 return CMD_RET_FAILURE;
308 }
309 return CMD_RET_SUCCESS;
310}
311
3d8c1907
L
312#define MAX_PATHLEN 255
313
314 /* Remove trailing slashes,
315 * but keep a leading slash (absolute path)
316 */
317void strip_trailing_slash_relpath(char *p)
318{
319 int n = strlen(p);
320
321 if (n >= 2 && (p[0] & 0x38) == '0' && p[1] == ':') {
322 p += 2;
323 n -= 2;
324 }
325 if (n >= 1 && p[0] == '/') {
326 p++;
327 n--;
328 }
329 while (n-- != 0 && p[n] == '/')
330 p[n] = '\0';
331}
332
333int print_dirent(FILINFO *f)
334{
335 return printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
336 (f->fattrib & AM_DIR) ? 'D' : '-',
337 (f->fattrib & AM_RDO) ? 'R' : '-',
338 (f->fattrib & AM_HID) ? 'H' : '-',
339 (f->fattrib & AM_SYS) ? 'S' : '-',
340 (f->fattrib & AM_ARC) ? 'A' : '-',
341 (f->fdate >> 9) + 1980, (f->fdate >> 5) & 15, f->fdate & 31,
342 (f->ftime >> 11), (f->ftime >> 5) & 63,
343 f->fsize, f->fname);
344}
2f53dd65
L
345
346/*
347 * fatls path - Directory listing
348 *
349 */
b6c04275 350command_ret_t do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2f53dd65 351{
bbd45c46 352 FATFS *fs;
2f53dd65
L
353 DIR Dir; /* Directory object */
354 FILINFO Finfo;
355 unsigned long p1;
356 unsigned int s1, s2;
3d8c1907 357 FRESULT res;
2f53dd65
L
358 (void) cmdtp; (void) flag; (void) argc;
359
b6c04275 360
3d8c1907
L
361 char *path = "";
362 if (argc > 1)
363 path = argv[1];
364 strip_trailing_slash_relpath(path);
b6c04275 365
3d8c1907
L
366 char *p = strrchr(path, '/');
367 if (p)
368 p++;
369 else {
370 p = path;
371 char *q = p;
372 if ((*q++ & 0x38) == '0' && *q++ == ':')
373 p = q;
374 }
375
376 char *pattern = NULL;
377 if (strpbrk_P(p, PSTR("*?")) ||
378 (f_stat(path, &Finfo) == FR_OK && !(Finfo.fattrib & AM_DIR))) {
379 pattern = strdup(p);
380 *p = '\0';
2f53dd65 381 }
3d8c1907
L
382 strip_trailing_slash_relpath(path);
383
384printf_P(PSTR("*: |%s| |%s|\n"), path ? path : "<NULL>", pattern ? pattern : "<NULL>");
2f53dd65
L
385
386 p1 = s1 = s2 = 0;
3d8c1907
L
387 res = f_findfirst(&Dir, &Finfo, path, pattern ? pattern : "*"); /* Start to search for files */
388 while (res == FR_OK && Finfo.fname[0]) {
2f53dd65
L
389 if (Finfo.fattrib & AM_DIR) {
390 s2++;
391 } else {
392 s1++; p1 += Finfo.fsize;
393 }
3d8c1907 394 print_dirent(&Finfo);
b15d22a4
L
395 if (check_abort())
396 break;
3d8c1907 397 res = f_findnext(&Dir, &Finfo);
2f53dd65 398 }
3d8c1907
L
399 f_closedir(&Dir);
400 free(pattern);
2f53dd65
L
401
402 if (res == FR_OK) {
403 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
3d8c1907 404 if (f_getfree(path, (DWORD*)&p1, &fs) == FR_OK)
2f53dd65
L
405 printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
406 }
407
3d8c1907
L
408 if (res) {
409 put_rc(res);
410 return CMD_RET_FAILURE;
411 }
412
413 return CMD_RET_SUCCESS;
414}
415
416command_ret_t do_tst(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
417{
418 DIR Dir; /* Directory object */
419 FILINFO Finfo;
420 FRESULT res = FR_OK;
421 char *path;
422
423 (void) cmdtp; (void) flag;
424
425 printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO));
426
427 char * buf = (char *) malloc(BUFFER_SIZE);
428 if (buf == NULL) {
429 printf_P(PSTR("pwd: Out of Memory!\n"));
430 free(buf);
431 return CMD_RET_FAILURE;
432 }
433 res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
434
435 if (!res) {
436 printf_P(PSTR("cwd: |%s|\n"), buf);
437 }
b6c04275 438 free(buf);
2f53dd65
L
439 if (res) {
440 put_rc(res);
441 return CMD_RET_FAILURE;
442 }
443
3d8c1907
L
444 if (argc > 1)
445 path = argv[1];
446 else
447 path = "";
448
449 printf_P(PSTR("arg: |%s|\n"), path);
450 printf_P(PSTR("==== f_stat: "));
451 res = f_stat(path, &Finfo);
452 put_rc(res);
453 if (res == FR_OK) {
454 print_dirent(&Finfo);
455 }
456
457 printf_P(PSTR("==== f_findfirst: "));
458 res = f_findfirst(&Dir, &Finfo, path, "*"); /* Start to search for files */
459 put_rc(res);
460 if (res == FR_OK) {
461 print_dirent(&Finfo);
462 }
463 f_closedir(&Dir);
464
465 printf_P(PSTR("==== f_opendir: "));
466 res = f_opendir(&Dir, path);
467 put_rc(res);
468 f_closedir(&Dir);
469
2f53dd65
L
470 return CMD_RET_SUCCESS;
471}
472
35edb766
L
473static
474FRESULT mkpath(TCHAR *path)
475{
476 /* TODO: */
477 (void) path;
478#if 0
479 FILINFO fd
480 TCHAR *p, *q;
481 FRESULT ret;
482
35edb766
L
483 res = f_stat (path, &fd)
484
485 p = strchr(path, ':');
486 if (p == NULL || *++p == '\0' || *p++ != '/')
487 return FR_OK;
488
489 while ((q = strchr(p, '/')) != NULL) {
490 *q = '\0';
491 ret = f_mkdir(path);
492 *q = '/';
493 if (ret != FR_OK && ret != FR_EXIST)
494 return ret;
495 p = q + 1;
496 }
497#endif
498
499 return FR_OK;
500}
2f53dd65 501
4565be9a
L
502/*
503 * fatread/write - load binary file to/from a dos filesystem
504 * read <d:/path/filename> <addr> [bytes [pos]]
505 * write <d:/path/filename> <addr> <bytes>
506 */
b6c04275 507command_ret_t do_rw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
4565be9a 508{
4565be9a
L
509 FIL File;
510 uint32_t addr;
511 unsigned long bytes;
512 unsigned long pos;
513 unsigned long bytes_rw;
514
3d8c1907 515 bool dowrite = (argv[0][0] == 'w');
3b841cea 516 FRESULT res = FR_OK;
4565be9a
L
517 bool buserr = 0;
518 uint32_t timer;
19b9a7d8 519 uint8_t *buffer;
4565be9a
L
520
521 (void) cmdtp; (void) flag;
522
523 if (argc < (dowrite ? 4 : 3))
524 return CMD_RET_USAGE;
525
2d914b45 526 addr = eval_arg(argv[2], NULL);
4565be9a
L
527 if (addr >= MAX_MEMORY) {
528 printf_P(PSTR("address too high: 0x%0lx\n"), addr);
529 return CMD_RET_FAILURE;
530 }
531 if (argc > 3)
2d914b45 532 bytes = eval_arg(argv[3], NULL);
4565be9a
L
533 else
534 bytes = MAX_MEMORY;
535 if (argc > 4)
2d914b45 536 pos = eval_arg(argv[4], NULL);
4565be9a
L
537 else
538 pos = 0;
539
540 if (addr + bytes > MAX_MEMORY)
541 bytes = MAX_MEMORY - addr;
542
19b9a7d8 543 buffer = (uint8_t *) malloc(BUFFER_SIZE);
bbd45c46 544 if (buffer == NULL) {
19b9a7d8 545 printf_P(PSTR("fatstat: Out of Memory!\n"));
19b9a7d8
L
546 free(buffer);
547 return CMD_RET_FAILURE;
548 }
549
bbd45c46
L
550 if (dowrite) {
551 res = mkpath(argv[1]);
35edb766 552 }
4565be9a
L
553 if (!res) {
554 res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
555 : FA_READ );
556
557 if (!res) {
558 res = f_lseek(&File, pos);
559 if (!res) {
560 bytes_rw = 0;
561 timer = get_timer(0);
562 while (bytes) {
563 unsigned int cnt, br;
564
19b9a7d8
L
565 if (bytes >= BUFFER_SIZE) {
566 cnt = BUFFER_SIZE;
567 bytes -= BUFFER_SIZE;
4565be9a
L
568 } else {
569 cnt = bytes; bytes = 0;
570 }
571 if (dowrite) {
572 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
573 buserr = 1;
574 break;
575 }
576 z80_read_block(buffer, addr, cnt);
577 z80_bus_cmd(Release);
578 res = f_write(&File, buffer, cnt, &br);
579 if (res != FR_OK)
580 break;
581 } else {
582 res = f_read(&File, buffer, cnt, &br);
583 if (res != FR_OK)
584 break;
585 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
586 buserr = 1;
587 break;
588 }
589 z80_write_block(buffer, addr, br);
590 z80_bus_cmd(Release);
591 }
592 addr += br;
593
594 bytes_rw += br;
595 if (cnt != br) {
596 if (dowrite)
597 printf_P(PSTR("Disk full?\n"));
598 break;
599 }
b15d22a4 600 if (check_abort())
4565be9a 601 break;
4565be9a
L
602 }
603
604 FRESULT fr = f_close(&File);
605 if (!res)
606 res = fr;
607 timer = get_timer(timer);
608 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
609 bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
610 }
611 }
4565be9a
L
612 }
613
19b9a7d8 614 free(buffer);
19b9a7d8 615
4565be9a
L
616 if (buserr)
617 my_puts_P(PSTR("Bus timeout\n"));
618 if (res)
619 put_rc(res);
620 if (buserr || res)
621 return CMD_RET_FAILURE;
622
623 return CMD_RET_SUCCESS;
624}
b6c04275 625
3d8c1907
L
626/* ========================================================================== */
627
628
629typedef struct {
630 char *p_end; /* pointer to NULL at end of path */
631 char p_path[MAX_PATHLEN + 1]; /* pointer to the start of a path */
632} PATH_T;
633
634static inline void strip_trailing_slash(PATH_T *p)
635{
636 while (p->p_end > p->p_path && p->p_end[-1] == '/')
637 *--p->p_end = 0;
638}
639
640/*
641 * Move specified string into path. Convert "" to "." to handle BSD
642 * semantics for a null path. Strip trailing slashes.
643 */
644int
645path_set(PATH_T *p, char *string)
646{
647 if (strlen(string) > MAX_PATHLEN) {
648 //err("%s: name too long", string);
649 return(0);
650 }
651
652 (void)strcpy(p->p_path, string);
653 p->p_end = p->p_path + strlen(p->p_path);
654
655 if (p->p_path == p->p_end) {
656 *p->p_end++ = '.';
657 *p->p_end = 0;
658 }
659
660 strip_trailing_slash(p);
661 return(1);
662}
663
664#define R_FLAG (1<<0)
665#define I_FLAG (1<<1)
666#define N_FLAG (1<<2)
667#define F_FLAG (1<<3)
668#define P_FLAG (1<<4)
669#define V_FLAG (1<<5)
670
671command_ret_t do_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
672{
673
674 FRESULT fr; /* Return value */
675 DIR dj; /* Directory search object */
676 FILINFO fno; /* File information */
677
678 uint8_t flags = 0;
679
680
681 /* reset getopt() */
682 optind = 0;
683
684 int opt;
685 while ((opt = getopt(argc, argv, PSTR("Rrfip"))) != -1) {
686 switch (opt) {
687 case 'f':
688 flags &= I_FLAG;
689 break;
690 case 'i':
691 flags |= I_FLAG;
692 flags &= F_FLAG;
693 break;
694 case 'p':
695 flags |= P_FLAG;
696 break;
697 case 'R':
698 case 'r':
699 flags |= R_FLAG;
700 break;
701 case 'v':
702 flags |= V_FLAG;
703 break;
704 default:
705 return CMD_RET_USAGE;
706 break;
707 }
708 }
709 argc -= optind;
710 argv += optind;
711
712 if (argc < 2)
713 return CMD_RET_USAGE;
714
715#if 0
716 /* consume last argument first. */
717 if (!path_set(&to, argv[--argc]))
718 exit(1);
719
720
721 if (flags & V_FLAG)
722 printf_P((PSTR("%s %s -> %s\n", badcp ? : "ERR:" : " ",
723 curr->fts_path, to.p_path);
724#endif
725
726/* Search a directory for objects and display it */
727
728
729 fr = f_findfirst(&dj, &fno, argv[1], argv[2]); /* Start to search for files */
730
731 while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */
732 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
733 (fno.fattrib & AM_DIR) ? 'D' : '-',
734 (fno.fattrib & AM_RDO) ? 'R' : '-',
735 (fno.fattrib & AM_HID) ? 'H' : '-',
736 (fno.fattrib & AM_SYS) ? 'S' : '-',
737 (fno.fattrib & AM_ARC) ? 'A' : '-',
738 (fno.fdate >> 9) + 1980, (fno.fdate >> 5) & 15, fno.fdate & 31,
739 (fno.ftime >> 11), (fno.ftime >> 5) & 63,
740 fno.fsize, fno.fname);
741 fr = f_findnext(&dj, &fno); /* Search for next item */
742 }
743
744 f_closedir(&dj);
745
746 return CMD_RET_SUCCESS;
747}
748
b6c04275
L
749
750static
751command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
752
753cmd_tbl_t cmd_fat_sub[] = {
754CMD_TBL_ITEM(
755 stat, 2, 1, do_stat,
756 "Show logical drive status",
757 "dev"
758),
759CMD_TBL_ITEM(
760 pwd, 2, 1, do_pwd,
761 "Print name of current/working directory",
762 ""
763),
764CMD_TBL_ITEM(
765 cd, 2, 1, do_cd,
766 "Change the current/working directory.",
767 "path"
768),
769CMD_TBL_ITEM(
3d8c1907 770 ls, CONFIG_SYS_MAXARGS, 1, do_ls,
b6c04275
L
771 "Directory listing",
772 "path"
773),
3d8c1907
L
774CMD_TBL_ITEM(
775 tst, 2, 1, do_tst,
776 "FatFS test function",
777 "path"
778),
b6c04275
L
779CMD_TBL_ITEM(
780 load, 5, 0, do_rw,
781 "load binary file from a dos filesystem",
782 "<d:/path/filename> <addr> [bytes [pos]]\n"
783 " - Load binary file 'path/filename' on logical drive 'd'\n"
784 " to address 'addr' from dos filesystem.\n"
785 " 'pos' gives the file position to start loading from.\n"
786 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
787 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
788 " the load stops on end of file."
789),
790CMD_TBL_ITEM(
791 write, 4, 0, do_rw,
792 "write file into a dos filesystem",
793 "<d:/path/filename> <addr> <bytes>\n"
794 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
795 " starting at address 'addr'.\n"
796),
797
3d8c1907
L
798CMD_TBL_ITEM(
799 cp, CONFIG_SYS_MAXARGS, 0, do_cp,
800 "copy files",
801 "cp [-R] [-f | -i | -n] [-aprv] source_file target_file\n"
802 " - \n"
803),
804
ee5c86e9
L
805CMD_TBL_ITEM(
806 help, CONFIG_SYS_MAXARGS, 1, do_help,
807 "Print sub command description/usage",
808 "\n"
809 " - print brief description of all sub commands\n"
810 "fat help command ...\n"
811 " - print detailed usage of sub cmd 'command'"
812),
813
b6c04275
L
814/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
815 {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
816 FSTR("Alias for 'help'"),
817#ifdef CONFIG_SYS_LONGHELP
818 FSTR(""),
819#endif /* CONFIG_SYS_LONGHELP */
820#ifdef CONFIG_AUTO_COMPLETE
821 0,
822#endif
823},
824};
825
826static
827command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
828{
829 return _do_help(cmd_fat_sub, ARRAY_SIZE(cmd_fat_sub), cmdtp, flag, argc, argv);
830}
831
832
833command_ret_t do_fat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
834{
835 cmd_tbl_t *cp;
836
837 if (argc < 2)
838 return CMD_RET_USAGE;
839
840 /* drop initial "fat" arg */
841 argc--;
842 argv++;
843
844 cp = find_cmd_tbl(argv[0], cmd_fat_sub, ARRAY_SIZE(cmd_fat_sub));
845
846 if (cp)
847 return cp->cmd(cmdtp, flag, argc, argv);
848
849 return CMD_RET_USAGE;
850}