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