]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_fat.c
Add copyright notice
[z180-stamp.git] / avr / cmd_fat.c
CommitLineData
35edb766
L
1/*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7/*
8 * FAT filesystem commands
9 */
10
2f53dd65
L
11#include "common.h"
12#include <stdlib.h>
13#include <string.h>
14#include <stdbool.h>
15
16#include "command.h"
17#include "ff.h"
18#include "z80-if.h"
4565be9a 19#include "con-utils.h"
2f53dd65 20#include "print-utils.h"
19b9a7d8 21#include "time.h"
2f53dd65 22#include "timer.h"
4f881b02 23#include "debug.h"
2f53dd65
L
24
25
4565be9a 26#define MAX_MEMORY (1ul << 20)
19b9a7d8
L
27#define BUFFER_SIZE 512
28
4565be9a 29
2f53dd65
L
30DWORD get_fattime (void)
31{
19b9a7d8
L
32 time_t timer;
33 struct tm tm_timer;
34
35 time(&timer);
36 gmtime_r(&timer, &tm_timer);
37
38 return fatfs_time(&tm_timer);
2f53dd65
L
39}
40
41
b15d22a4
L
42static bool check_abort(void)
43{
44 bool ret = ctrlc();
45
46 if (ret)
47 printf_P(PSTR("Abort\n"));
48
49 return ret;
50}
51
52
2f53dd65
L
53static const FLASH char * const FLASH rc_names[] = {
54 FSTR("OK"),
55 FSTR("DISK_ERR"),
56 FSTR("INT_ERR"),
57 FSTR("NOT_READY"),
58 FSTR("NO_FILE"),
59 FSTR("NO_PATH"),
60 FSTR("INVALID_NAME"),
61 FSTR("DENIED"),
62 FSTR("EXIST"),
63 FSTR("INVALID_OBJECT"),
64 FSTR("WRITE_PROTECTED"),
65 FSTR("INVALID_DRIVE"),
66 FSTR("NOT_ENABLED"),
67 FSTR("NO_FILE_SYSTEM"),
68 FSTR("MKFS_ABORTED"),
69 FSTR("TIMEOUT"),
70 FSTR("LOCKED"),
71 FSTR("NOT_ENOUGH_CORE"),
72 FSTR("TOO_MANY_OPEN_FILES")
73 };
74
75static
76void put_rc (FRESULT rc)
77{
b15d22a4 78 if (rc < ARRAY_SIZE(rc_names)) {
2f53dd65 79#if GCC_BUG_61443
b15d22a4
L
80 printf_P(PSTR("rc=%u FR_"), rc);
81 my_puts_P(rc_names[rc]);
82 my_puts_P(PSTR("\n"));
2f53dd65 83#else
b15d22a4 84 printf_P(PSTR("rc=%u FR_%S\n"), rc, rc_names[rc]);
2f53dd65 85#endif
b15d22a4 86 }
2f53dd65
L
87}
88
b15d22a4
L
89
90static void swirl(void)
91{
6204987c 92 static const FLASH char swirlchar[] = { '-','\\','|','/' };
b15d22a4
L
93 static uint_fast8_t cnt;
94 static uint32_t tstamp;
95
96 if (get_timer(0) > tstamp) {
97 printf_P(PSTR("\b%c"), swirlchar[cnt]);
98 cnt = (cnt+1) % ARRAY_SIZE(swirlchar);
6204987c 99 tstamp = get_timer(0) + 250;
b15d22a4
L
100 }
101}
102
6204987c
L
103/* Work register for fs command */
104struct stat_dat_s {
105 DWORD AccSize;
106 WORD AccFiles, AccDirs;
107 FILINFO Finfo;
108};
109
2f53dd65
L
110static
111FRESULT scan_files (
6204987c
L
112 char *path, /* Pointer to the working buffer with start path */
113 struct stat_dat_s *statp
2f53dd65
L
114)
115{
116 DIR dirs;
117 FRESULT res;
118 int i;
119 char *fn;
120
121 res = f_opendir(&dirs, path);
b15d22a4 122 swirl();
2f53dd65
L
123 if (res == FR_OK) {
124 i = strlen(path);
6204987c
L
125 while (((res = f_readdir(&dirs, &statp->Finfo)) == FR_OK) &&
126 statp->Finfo.fname[0]) {
127 if (_FS_RPATH && statp->Finfo.fname[0] == '.')
128 continue;
129 fn = statp->Finfo.fname;
130 if (statp->Finfo.fattrib & AM_DIR) {
131 statp->AccDirs++;
132 path[i] = '/';
133 strcpy(path+i+1, fn);
134 res = scan_files(path, statp);
2f53dd65 135 path[i] = '\0';
6204987c
L
136 if (res != FR_OK)
137 break;
2f53dd65 138 } else {
6204987c
L
139 //printf_P(PSTR("%s/%s\n"), path, fn);
140 statp->AccFiles++;
141 statp->AccSize += statp->Finfo.fsize;
2f53dd65 142 }
b15d22a4
L
143 if (check_abort()) {
144 res = 255;
145 break;
146 }
2f53dd65
L
147 }
148 }
149
150 return res;
151}
152
153
154/*
155 * fatstat path - Show logical drive status
156 *
157 */
158command_ret_t do_fat_stat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
159{
4565be9a
L
160 FATFS *FatFs, *fs;
161 DWORD nfreeclst;
2f53dd65 162 FRESULT res;
6204987c
L
163 char *path;
164 struct stat_dat_s statp;
2f53dd65
L
165
166 (void) cmdtp; (void) flag; (void) argc;
167
4565be9a 168 FatFs = (FATFS *) malloc(sizeof (FATFS));
6204987c
L
169 path = (char *) malloc(BUFFER_SIZE);
170 if (FatFs == NULL || path == NULL) {
4565be9a 171 printf_P(PSTR("fatstat: Out of Memory!\n"));
6204987c 172 free(path);
19b9a7d8 173 free(FatFs);
2f53dd65
L
174 return CMD_RET_FAILURE;
175 }
176
4565be9a
L
177 res = f_mount(FatFs, argv[1], 0);
178 if (!res) {
179 res = f_getfree(argv[1], &nfreeclst, &fs);
180 if (!res) {
181 printf_P(PSTR(
182 "FAT type: %u\n"
183 "Bytes/Cluster: %lu\n"
184 "Number of FATs: %u\n"
185 "Root DIR entries: %u\n"
186 "Sectors/FAT: %lu\n"
187 "Number of clusters: %lu\n"
188 "FAT start (lba): %lu\n"
189 "DIR start (lba,cluster): %lu\n"
190 "Data start (lba): %lu\n"),
191 fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
192 fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
193 fs->fatbase, fs->dirbase, fs->database);
2f53dd65
L
194
195#if _USE_LABEL
4565be9a
L
196 TCHAR label[12];
197 DWORD serial;
198 res = f_getlabel(argv[1], label, &serial);
199 if (!res) {
200 printf_P(PSTR(
201 "Volume name: %s\n"
202 "Volume S/N: %04X-%04X\n"),
203 label, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
204 }
2f53dd65 205#endif
4565be9a 206 if (!res) {
b15d22a4 207 my_puts_P(PSTR("\nCounting... "));
6204987c
L
208 statp.AccSize = statp.AccFiles = statp.AccDirs = 0;
209 strcpy(path, argv[1]);
2f53dd65 210
6204987c 211 res = scan_files(path, &statp);
4565be9a
L
212 }
213 if (!res) {
214 printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
215 "%lu KB total disk space.\n%lu KB available.\n"),
6204987c 216 statp.AccFiles, statp.AccSize, statp.AccDirs,
4565be9a
L
217 (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
218 );
219 }
220 }
2f53dd65 221 }
2f53dd65 222
6204987c 223 free(path);
19b9a7d8 224 free(FatFs);
6204987c 225 f_mount(NULL, argv[1], 0);
2f53dd65
L
226 if (res) {
227 put_rc(res);
228 return CMD_RET_FAILURE;
229 }
230 return CMD_RET_SUCCESS;
231}
232
233
234/*
235 * fatls path - Directory listing
236 *
237 */
238command_ret_t do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
239{
240 FATFS FatFs, *fs;
241 DIR Dir; /* Directory object */
242 FILINFO Finfo;
243 unsigned long p1;
244 unsigned int s1, s2;
245 FRESULT res;
246#if _USE_LFN
247 char Lfname[_MAX_LFN+1];
248 Finfo.lfname = Lfname;
249 Finfo.lfsize = sizeof Lfname;
250#endif
251
252 (void) cmdtp; (void) flag; (void) argc;
253
254 res = f_mount(&FatFs, argv[1], 0);
255 if (!res)
256 res = f_opendir(&Dir, argv[1]);
257 if (res) {
258 put_rc(res);
259 return CMD_RET_FAILURE;
260 }
261
262 p1 = s1 = s2 = 0;
263 for(;;) {
264 res = f_readdir(&Dir, &Finfo);
265 if ((res != FR_OK) || !Finfo.fname[0])
266 break;
267 if (Finfo.fattrib & AM_DIR) {
268 s2++;
269 } else {
270 s1++; p1 += Finfo.fsize;
271 }
19b9a7d8 272 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu "),
2f53dd65
L
273 (Finfo.fattrib & AM_DIR) ? 'D' : '-',
274 (Finfo.fattrib & AM_RDO) ? 'R' : '-',
275 (Finfo.fattrib & AM_HID) ? 'H' : '-',
276 (Finfo.fattrib & AM_SYS) ? 'S' : '-',
277 (Finfo.fattrib & AM_ARC) ? 'A' : '-',
278 (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31,
19b9a7d8 279 (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63, Finfo.fsize);
2f53dd65 280#if _USE_LFN
19b9a7d8 281 printf_P(PSTR("%s\n"), *Lfname ? Lfname : Finfo.fname);
2f53dd65 282#else
19b9a7d8 283 printf_P(PSTR("%s\n"), Finfo.fname);
2f53dd65 284#endif
b15d22a4
L
285 if (check_abort())
286 break;
2f53dd65
L
287 }
288
289 if (res == FR_OK) {
290 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
291 if (f_getfree(argv[1], (DWORD*)&p1, &fs) == FR_OK)
292 printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
293 }
294
295 if (res) {
296 put_rc(res);
297 return CMD_RET_FAILURE;
298 }
299
300 return CMD_RET_SUCCESS;
301}
302
35edb766
L
303static
304FRESULT mkpath(TCHAR *path)
305{
306 /* TODO: */
307 (void) path;
308#if 0
309 FILINFO fd
310 TCHAR *p, *q;
311 FRESULT ret;
312
313#if _USE_LFN
314 fd.lfname = 0;
315#endif
316
317
318 res = f_stat (path, &fd)
319
320 p = strchr(path, ':');
321 if (p == NULL || *++p == '\0' || *p++ != '/')
322 return FR_OK;
323
324 while ((q = strchr(p, '/')) != NULL) {
325 *q = '\0';
326 ret = f_mkdir(path);
327 *q = '/';
328 if (ret != FR_OK && ret != FR_EXIST)
329 return ret;
330 p = q + 1;
331 }
332#endif
333
334 return FR_OK;
335}
2f53dd65 336
4565be9a
L
337/*
338 * fatread/write - load binary file to/from a dos filesystem
339 * read <d:/path/filename> <addr> [bytes [pos]]
340 * write <d:/path/filename> <addr> <bytes>
341 */
342command_ret_t do_fat_rw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
343{
19b9a7d8 344 FATFS *FatFs;
4565be9a
L
345 FIL File;
346 uint32_t addr;
347 unsigned long bytes;
348 unsigned long pos;
349 unsigned long bytes_rw;
350
351 bool dowrite = (argv[0][3] == 'w');
352 FRESULT res;
353 bool buserr = 0;
354 uint32_t timer;
19b9a7d8 355 uint8_t *buffer;
4565be9a
L
356
357 (void) cmdtp; (void) flag;
358
359 if (argc < (dowrite ? 4 : 3))
360 return CMD_RET_USAGE;
361
362 addr = strtoul(argv[2], 0, 16);
363 if (addr >= MAX_MEMORY) {
364 printf_P(PSTR("address too high: 0x%0lx\n"), addr);
365 return CMD_RET_FAILURE;
366 }
367 if (argc > 3)
368 bytes = strtoul(argv[3], 0, 16);
369 else
370 bytes = MAX_MEMORY;
371 if (argc > 4)
372 pos = strtoul(argv[4], 0, 16);
373 else
374 pos = 0;
375
376 if (addr + bytes > MAX_MEMORY)
377 bytes = MAX_MEMORY - addr;
378
19b9a7d8
L
379 FatFs = (FATFS *) malloc(sizeof (FATFS));
380 buffer = (uint8_t *) malloc(BUFFER_SIZE);
381 if (FatFs == NULL || buffer == NULL) {
382 printf_P(PSTR("fatstat: Out of Memory!\n"));
383 free(FatFs);
384 free(buffer);
385 return CMD_RET_FAILURE;
386 }
387
388 res = f_mount(FatFs, argv[1], 0);
35edb766
L
389
390 if (!res) {
391 if (dowrite) {
392 res = mkpath(argv[1]);
393 }
394 }
4565be9a
L
395 if (!res) {
396 res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
397 : FA_READ );
398
399 if (!res) {
400 res = f_lseek(&File, pos);
401 if (!res) {
402 bytes_rw = 0;
403 timer = get_timer(0);
404 while (bytes) {
405 unsigned int cnt, br;
406
19b9a7d8
L
407 if (bytes >= BUFFER_SIZE) {
408 cnt = BUFFER_SIZE;
409 bytes -= BUFFER_SIZE;
4565be9a
L
410 } else {
411 cnt = bytes; bytes = 0;
412 }
413 if (dowrite) {
414 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
415 buserr = 1;
416 break;
417 }
418 z80_read_block(buffer, addr, cnt);
419 z80_bus_cmd(Release);
420 res = f_write(&File, buffer, cnt, &br);
421 if (res != FR_OK)
422 break;
423 } else {
424 res = f_read(&File, buffer, cnt, &br);
425 if (res != FR_OK)
426 break;
427 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
428 buserr = 1;
429 break;
430 }
431 z80_write_block(buffer, addr, br);
432 z80_bus_cmd(Release);
433 }
434 addr += br;
435
436 bytes_rw += br;
437 if (cnt != br) {
438 if (dowrite)
439 printf_P(PSTR("Disk full?\n"));
440 break;
441 }
b15d22a4 442 if (check_abort())
4565be9a 443 break;
4565be9a
L
444 }
445
446 FRESULT fr = f_close(&File);
447 if (!res)
448 res = fr;
449 timer = get_timer(timer);
450 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
451 bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
452 }
453 }
454 f_mount(NULL, argv[1], 0);
455 }
456
19b9a7d8
L
457 free(buffer);
458 free(FatFs);
459
4565be9a
L
460 if (buserr)
461 my_puts_P(PSTR("Bus timeout\n"));
462 if (res)
463 put_rc(res);
464 if (buserr || res)
465 return CMD_RET_FAILURE;
466
467 return CMD_RET_SUCCESS;
468}