PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
fs_driver.c
1/*
2 * fat_driver.c - USB Mass storage driver for PS2
3 *
4 * (C) 2004, Marek Olejnik (ole00@post.cz)
5 * (C) 2004 Hermes (support for sector sizes from 512 to 4096 bytes)
6 * (C) 2004 raipsu (fs_dopen, fs_dclose, fs_dread, fs_getstat implementation)
7 *
8 * FAT filesystem layer
9 *
10 * See the file LICENSE included with this distribution for licensing terms.
11 */
12//---------------------------------------------------------------------------
13#include <errno.h>
14#include <iomanX.h>
15#include <stdio.h>
16
17#include <sysclib.h>
18#include <sysmem.h>
19#include <thbase.h>
20#include <thsemap.h>
21
22#include <bdm.h>
23
24#include <usbhdfsd-common.h>
25
26#include "fs_driver.h"
27
28//#define DEBUG //comment out this line when not debugging
29#include "module_debug.h"
30
31fatfs_fs_driver_mount_info fs_driver_mount_info[FF_VOLUMES];
32
33#define FATFS_FS_DRIVER_MOUNT_INFO_MAX ((int)(sizeof(fs_driver_mount_info) / sizeof(fs_driver_mount_info[0])))
34
35// Macros for defining the modified path on stack.
36#define FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(varname) \
37 const char *modified_##varname;
38
39#define FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(varname, vol) \
40 { \
41 if ((vol) != 0) \
42 { \
43 int strlen_##varname; \
44 char *modified_scope_##varname; \
45 \
46 strlen_##varname = strlen(varname); \
47 modified_scope_##varname = __builtin_alloca(3 + strlen_##varname + 1); \
48 modified_scope_##varname[0] = '0' + (vol); \
49 modified_scope_##varname[1] = ':'; \
50 modified_scope_##varname[2] = '/'; \
51 memcpy((modified_scope_##varname) + 3, varname, strlen_##varname); \
52 modified_scope_##varname[3 + strlen_##varname] = '\x00'; \
53 modified_##varname = modified_scope_##varname; \
54 } \
55 else \
56 { \
57 modified_##varname = varname; \
58 } \
59 }
60
61
62
63//---------------------------------------------------------------------------
64static int _fs_lock_sema_id = -1;
65
66//---------------------------------------------------------------------------
67static int _fs_init_lock(void)
68{
69 iop_sema_t sp;
70
71 M_DEBUG("%s\n", __func__);
72
73 sp.initial = 1;
74 sp.max = 1;
75 sp.option = 0;
76 sp.attr = 0;
77 if ((_fs_lock_sema_id = CreateSema(&sp)) < 0) {
78 return (-1);
79 }
80
81 return (0);
82}
83
84//---------------------------------------------------------------------------
85static void _fs_lock(void)
86{
87 //M_DEBUG("%s\n", __func__);
88
89 WaitSema(_fs_lock_sema_id);
90}
91
92//---------------------------------------------------------------------------
93static void _fs_unlock(void)
94{
95 //M_DEBUG("%s\n", __func__);
96
97 SignalSema(_fs_lock_sema_id);
98}
99
100//---------------------------------------------------------------------------
101static void fs_reset(void)
102{
103 M_DEBUG("%s\n", __func__);
104
105 if (_fs_lock_sema_id >= 0)
106 DeleteSema(_fs_lock_sema_id);
107
108 _fs_init_lock();
109}
110
111static void fatfs_fs_driver_initialize_all_mount_info(void)
112{
113 int i;
114 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
115 memset(&(fs_driver_mount_info[i].fatfs), 0, sizeof(fs_driver_mount_info[i].fatfs));
116 fs_driver_mount_info[i].mounted_bd = NULL;
117 }
118}
119
120static int fatfs_fs_driver_find_mount_info_index_from_block_device(const struct block_device *bd)
121{
122 int i;
123 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
124 if (fs_driver_mount_info[i].mounted_bd == bd) {
125 return i;
126 }
127 }
128 return -1;
129}
130
131static int fatfs_fs_driver_find_mount_info_index_free(void)
132{
133 return fatfs_fs_driver_find_mount_info_index_from_block_device(NULL);
134}
135
136struct block_device *fatfs_fs_driver_get_mounted_bd_from_index(int mount_info_index)
137{
138 struct block_device *mounted_bd;
139 if (mount_info_index > FATFS_FS_DRIVER_MOUNT_INFO_MAX) {
140 return NULL;
141 }
142 mounted_bd = fs_driver_mount_info[mount_info_index].mounted_bd;
143 return mounted_bd;
144}
145
146static FRESULT fatfs_fs_driver_mount_bd(int mount_info_index, struct block_device *bd)
147{
148 int ret;
149 char mount_point[3];
150
151 M_DEBUG("%s\n", __func__);
152
153 mount_point[0] = '0' + mount_info_index;
154 mount_point[1] = ':';
155 mount_point[2] = '\x00';
156
157 fs_driver_mount_info[mount_info_index].mounted_bd = bd;
158 ret = f_mount(&(fs_driver_mount_info[mount_info_index].fatfs), mount_point, 1);
159 if (ret != FR_OK) {
160 fs_driver_mount_info[mount_info_index].mounted_bd = NULL;
161 }
162 return ret;
163}
164
165static void fatfs_fs_driver_unmount_bd(int mount_info_index)
166{
167 char mount_point[3];
168 mount_point[0] = '0' + mount_info_index;
169 mount_point[1] = ':';
170 mount_point[2] = '\x00';
171
172 f_unmount(mount_point);
173 fs_driver_mount_info[mount_info_index].mounted_bd = NULL;
174}
175
176static void fatfs_fs_driver_stop_single_bd(int mount_info_index)
177{
178 struct block_device *mounted_bd;
179
180 mounted_bd = fatfs_fs_driver_get_mounted_bd_from_index(mount_info_index);
181 if (mounted_bd != NULL) {
182 fatfs_fs_driver_unmount_bd(mount_info_index);
183 mounted_bd->stop(mounted_bd);
184 }
185}
186
187static void fatfs_fs_driver_stop_all_bd(void)
188{
189 int i;
190 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
191 fatfs_fs_driver_stop_single_bd(i);
192 }
193}
194
195// Pool of dynamically-registered iop_device_t instances, one per unique bd->path value.
196// "mass" is always registered separately; this pool handles all other path values.
197#define FS_MAX_TYPED_DRIVERS 8
198static iop_device_t fs_typed_drivers[FS_MAX_TYPED_DRIVERS];
199static char fs_typed_driver_names[FS_MAX_TYPED_DRIVERS][16];
200static int fs_typed_driver_count = 0;
201
202// Forward declaration for the shared ops table used by all typed drivers.
203static iop_device_ops_t fs_functarray;
204
205// Ensures an iop_device_t named `path` is registered with iomanX.
206// No-op if already registered or if the pool is exhausted.
207static void fs_ensure_typed_driver(const char *path)
208{
209 int i;
210
211 if (path == NULL || strcmp(path, "mass") == 0)
212 return;
213
214 for (i = 0; i < fs_typed_driver_count; i++) {
215 if (strcmp(fs_typed_driver_names[i], path) == 0)
216 return; // already registered
217 }
218
219 if (fs_typed_driver_count >= FS_MAX_TYPED_DRIVERS) {
220 M_DEBUG("fs_ensure_typed_driver: pool exhausted, cannot register '%s'\n", path);
221 return;
222 }
223
224 i = fs_typed_driver_count;
225 strncpy(fs_typed_driver_names[i], path, sizeof(fs_typed_driver_names[i]) - 1);
226 fs_typed_driver_names[i][sizeof(fs_typed_driver_names[i]) - 1] = '\0';
227
228 fs_typed_drivers[i].name = fs_typed_driver_names[i];
229 fs_typed_drivers[i].type = IOP_DT_FS | IOP_DT_FSEXT;
230 fs_typed_drivers[i].version = 2;
231 fs_typed_drivers[i].desc = "FATFS driver";
232 fs_typed_drivers[i].ops = &fs_functarray;
233
234 DelDrv(fs_typed_driver_names[i]);
235 if (AddDrv(&fs_typed_drivers[i]) == 0) {
236 M_DEBUG("fs_ensure_typed_driver: registered '%s'\n", path);
237 fs_typed_driver_count++;
238 }
239}
240
241// Maps (iomanX driver name, unit) to a FatFs volume index (mount_info_index).
242// "mass" uses global connection order for full backward compatibility.
243// Any other name matches bd->path of mounted devices.
244// Returns -1 if no matching mounted volume is found.
245static int fs_driver_resolve_volume(const char *driver_name, int unit)
246{
247 int i, count;
248
249 if (strcmp(driver_name, "mass") == 0) {
250 if (unit >= 0 && unit < FATFS_FS_DRIVER_MOUNT_INFO_MAX)
251 return unit;
252 return -1;
253 }
254
255 count = 0;
256 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i++) {
257 struct block_device *bd = fs_driver_mount_info[i].mounted_bd;
258 if (bd != NULL && bd->path != NULL && strcmp(bd->path, driver_name) == 0) {
259 if (count == unit)
260 return i;
261 count++;
262 }
263 }
264 return -1;
265}
266
267int connect_bd(struct block_device *bd)
268{
269 int mount_info_index;
270
271 M_DEBUG("%s\n", __func__);
272
273 // Dynamically register a typed iop_device_t for this device's path prefix.
274 fs_ensure_typed_driver(bd->path);
275
276 _fs_lock();
277 mount_info_index = fatfs_fs_driver_find_mount_info_index_free();
278 if (mount_info_index != -1) {
279 M_DEBUG("connect_bd: trying to mount to index %d\n", mount_info_index);
280 if (fatfs_fs_driver_mount_bd(mount_info_index, bd) == FR_OK) {
281 _fs_unlock();
282 return 0;
283 }
284 }
285 _fs_unlock();
286 M_DEBUG("connect_bd: failed to mount device\n");
287 return -1;
288}
289
290void disconnect_bd(struct block_device *bd)
291{
292 int mount_info_index;
293
294 _fs_lock();
295 mount_info_index = fatfs_fs_driver_find_mount_info_index_from_block_device(bd);
296 if (mount_info_index != -1) {
297 fatfs_fs_driver_unmount_bd(mount_info_index);
298 }
299 _fs_unlock();
300}
301
302//---------------------------------------------------------------------------
303
304#define MAX_FILES 128
305static FIL fil_structures[MAX_FILES];
306
307#define MAX_DIRS 16
308static DIR dir_structures[MAX_DIRS];
309
310static FIL *fs_find_free_fil_structure(void)
311{
312 int i;
313
314 M_DEBUG("%s\n", __func__);
315
316 for (i = 0; i < MAX_FILES; i++) {
317 if (fil_structures[i].obj.fs == NULL) {
318 return &fil_structures[i];
319 }
320 }
321 return NULL;
322}
323
324static DIR *fs_find_free_dir_structure(void)
325{
326 int i;
327
328 M_DEBUG("%s\n", __func__);
329
330 for (i = 0; i < MAX_DIRS; i++) {
331 if (dir_structures[i].obj.fs == NULL) {
332 return &dir_structures[i];
333 }
334 }
335 return NULL;
336}
337
338//---------------------------------------------------------------------------
339static int fs_open(iop_file_t *fd, const char *name, int flags, int mode)
340{
341 M_DEBUG("%s: %s flags=%X mode=%X\n", __func__, name, flags, mode);
342
343 int ret;
344 int vol;
345 BYTE f_mode = FA_OPEN_EXISTING;
346 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
347
348 (void)mode;
349
350 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
351 if (vol < 0)
352 return -ENXIO;
353
354 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, vol);
355
356 _fs_lock();
357
358 // check if the slot is free
359 fd->privdata = fs_find_free_fil_structure();
360 if (fd->privdata == NULL) {
361 _fs_unlock();
362 return -EMFILE;
363 }
364
365 // translate mode
366 if (flags & O_RDONLY)
367 f_mode |= FA_READ;
368 if (flags & O_WRONLY)
369 f_mode |= FA_WRITE;
370 if (flags & O_CREAT)
371 f_mode |= FA_OPEN_ALWAYS;
372 if (flags & O_TRUNC)
373 f_mode |= FA_CREATE_ALWAYS;
374 if (flags & O_APPEND)
375 f_mode |= FA_OPEN_APPEND;
376
377 ret = f_open(fd->privdata, modified_name, f_mode);
378
379 if (ret != FR_OK) {
380 fd->privdata = NULL;
381 ret = -ret;
382 } else {
383 ret = 1;
384 }
385
386 _fs_unlock();
387 return ret;
388}
389
390//---------------------------------------------------------------------------
391static int fs_close(iop_file_t *fd)
392{
393 M_DEBUG("%s\n", __func__);
394
395 int ret = FR_OK;
396
397 _fs_lock();
398
399 if (fd->privdata) {
400 ret = f_close(fd->privdata);
401 fd->privdata = NULL;
402 }
403
404 _fs_unlock();
405 return -ret;
406}
407
408//---------------------------------------------------------------------------
409
410s64 fs_lseek64(iop_file_t *fd, s64 offset, int whence)
411{
412 M_DEBUG("%s\n", __func__);
413
414 int res;
415
416 if (fd->privdata == NULL)
417 return -ENOENT;
418
419 _fs_lock();
420
421 FIL *file = (FIL *)(fd->privdata);
422
423 FSIZE_t off = offset;
424
425 switch (whence) {
426 case SEEK_CUR:
427 off += file->fptr;
428 break;
429 case SEEK_END:
430 off = file->obj.objsize + offset;
431 break;
432 }
433
434 res = f_lseek(file, off);
435
436 _fs_unlock();
437 return (res == FR_OK) ? (s64)(file->fptr) : -res;
438}
439
440static int fs_lseek(iop_file_t *fd, int offset, int whence)
441{
442 return fs_lseek64(fd, (s64)offset, whence);
443}
444
445//---------------------------------------------------------------------------
446static int fs_write(iop_file_t *fd, void *buffer, int size)
447{
448 M_DEBUG("%s\n", __func__);
449
450 int ret;
451 UINT bw;
452
453 if (fd->privdata == NULL)
454 return -ENOENT;
455
456 _fs_lock();
457
458 ret = f_write(fd->privdata, buffer, size, &bw);
459
460 _fs_unlock();
461 return (ret == FR_OK) ? bw : 0;
462}
463
464//---------------------------------------------------------------------------
465static int fs_read(iop_file_t *fd, void *buffer, int size)
466{
467 M_DEBUG("%s\n", __func__);
468
469 int ret;
470 UINT br;
471
472 if (fd->privdata == NULL)
473 return -ENOENT;
474
475 _fs_lock();
476
477 ret = f_read(fd->privdata, buffer, size, &br);
478
479 _fs_unlock();
480 return (ret == FR_OK) ? br : 0;
481}
482
483//---------------------------------------------------------------------------
484static int fs_remove(iop_file_t *fd, const char *name)
485{
486 M_DEBUG("%s\n", __func__);
487
488 int ret;
489 int vol;
490 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
491
492 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
493 if (vol < 0)
494 return -ENXIO;
495
496 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, vol);
497
498 _fs_lock();
499
500 ret = f_unlink(modified_name);
501
502 _fs_unlock();
503 return -ret;
504}
505
506//---------------------------------------------------------------------------
507static int fs_mkdir(iop_file_t *fd, const char *name, int mode)
508{
509 M_DEBUG("%s\n", __func__);
510
511 int ret;
512 int vol;
513 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
514
515 (void)mode;
516
517 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
518 if (vol < 0)
519 return -ENXIO;
520
521 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, vol);
522
523 _fs_lock();
524
525 ret = f_mkdir(modified_name);
526
527 _fs_unlock();
528 return -ret;
529}
530
531//---------------------------------------------------------------------------
532static int fs_dopen(iop_file_t *fd, const char *name)
533{
534 M_DEBUG("%s: unit %d name %s\n", __func__, fd->unit, name);
535
536 int ret;
537 int vol;
538 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
539
540 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
541 if (vol < 0)
542 return -ENXIO;
543
544 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, vol);
545
546 _fs_lock();
547
548 // check if the slot is free
549 fd->privdata = fs_find_free_dir_structure();
550 if (fd->privdata == NULL) {
551 _fs_unlock();
552 return -EMFILE;
553 }
554
555 ret = f_opendir(fd->privdata, modified_name);
556
557 if (ret != FR_OK) {
558 fd->privdata = NULL;
559 ret = -ret;
560 }
561
562 _fs_unlock();
563 return ret;
564}
565
566//---------------------------------------------------------------------------
567static int fs_dclose(iop_file_t *fd)
568{
569 M_DEBUG("%s\n", __func__);
570
571 int ret = ENOENT;
572
573 _fs_lock();
574
575 if (fd->privdata) {
576 ret = f_closedir(fd->privdata);
577 fd->privdata = NULL;
578 }
579
580 _fs_unlock();
581 return -ret;
582}
583
584//--------------------------------------------------------------------------
585
586static void fileInfoToStat(FILINFO *fno, iox_stat_t *stat)
587{
588 WORD fdate = fno->fdate;
589 WORD ftime = fno->ftime;
590 unsigned char stime[8];
591 u16 year;
592
593 stat->attr = 0777;
594 stat->size = (unsigned int)(fno->fsize);
595 stat->hisize = (unsigned int)(fno->fsize>>32);
596
597 stat->mode = FIO_S_IROTH | FIO_S_IXOTH;
598 if (fno->fattrib & AM_DIR) {
599 stat->mode |= FIO_S_IFDIR;
600 } else {
601 stat->mode |= FIO_S_IFREG;
602 }
603 if (!(fno->fattrib & AM_RDO)) {
604 stat->mode |= FIO_S_IWOTH;
605 }
606
607 // Since the VFAT file system does not support timezones, the timezone offset will not be applied.
608 // exFAT does support timezones, but the feature is not used/exposed in the FatFs library.
609 // Thus, conversion to/from JST may be incorrect.
610 // For simplicity's sake, the timezone is not read from the system configuration and timezone conversion is not done.
611
612 stime[0] = 0; // Padding
613
614 stime[4] = (fdate & 31); // Day
615 stime[5] = (fdate >> 5) & 15; // Month
616
617 year = (fdate >> 9) + 1980;
618 stime[6] = year & 0xff; // Year (low bits)
619 stime[7] = (year >> 8) & 0xff; // Year (high bits)
620
621 stime[3] = (ftime >> 11); // Hours
622 stime[2] = (ftime >> 5) & 63; // Minutes
623 stime[1] = (ftime << 1) & 31; // Seconds (multiplied by 2)
624
625 memcpy(stat->ctime, stime, sizeof(stime));
626 memcpy(stat->atime, stime, sizeof(stime));
627 memcpy(stat->mtime, stime, sizeof(stime));
628}
629
630//---------------------------------------------------------------------------
631static int fs_dread(iop_file_t *fd, iox_dirent_t *buffer)
632{
633 M_DEBUG("%s\n", __func__);
634
635 int ret;
636 FILINFO fno;
637
638 if (fd->privdata == NULL)
639 return -ENOENT;
640
641 _fs_lock();
642
643 ret = f_readdir(fd->privdata, &fno);
644
645 if (ret == FR_OK && fno.fname[0]) {
646 strncpy(buffer->name, fno.fname, 255);
647 fileInfoToStat(&fno, &(buffer->stat));
648 ret = 1;
649 } else {
650 ret = 0;
651 }
652
653 _fs_unlock();
654 return ret;
655}
656
657//---------------------------------------------------------------------------
658static int fs_getstat(iop_file_t *fd, const char *name, iox_stat_t *stat)
659{
660 M_DEBUG("%s: unit %d name %s\n", __func__, fd->unit, name);
661
662 int ret;
663 int vol;
664 FILINFO fno;
665 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
666
667 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
668 if (vol < 0)
669 return -ENXIO;
670
671 // FatFs f_stat doesn't handle the root directory, so we'll handle this case ourselves.
672 {
673 const char *name_no_leading_slash = name;
674 while (*name_no_leading_slash == '/') {
675 name_no_leading_slash += 1;
676 }
677 if ((strcmp(name_no_leading_slash, "") == 0) || (strcmp(name_no_leading_slash, ".") == 0)) {
678 if (fatfs_fs_driver_get_mounted_bd_from_index(vol) == NULL) {
679 return -ENXIO;
680 }
681 // Return data indicating that it is a directory.
682 memset(stat, 0, sizeof(*stat));
684 return 0;
685 }
686 }
687
688 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, vol);
689
690 _fs_lock();
691
692 ret = f_stat(modified_name, &fno);
693
694 if (ret == FR_OK) {
695 fileInfoToStat(&fno, stat);
696 } else {
697 ret = -ret;
698 }
699
700 _fs_unlock();
701 return ret;
702}
703
704static int get_frag_list(FIL *file, void *rdata, unsigned int rdatalen)
705{
706 bd_fragment_t *f = (bd_fragment_t*)rdata;
707 int iMaxFragments = rdatalen / sizeof(bd_fragment_t);
708 int iFragCount = 0;
709
710 // Get the block device backing the file so we can get the starting LBA of the file system.
711 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
712
713 DWORD iClusterStart = file->obj.sclust;
714 DWORD iClusterCurrent = iClusterStart;
715
716 do {
717 DWORD iClusterNext = get_fat(&file->obj, iClusterCurrent);
718 if (iClusterNext != (iClusterCurrent + 1)) {
719 // Fragment or file end
720 M_DEBUG("fragment: %uc - %uc + 1\n", iClusterStart, iClusterCurrent + 1);
721 if (iFragCount < iMaxFragments) {
722 u64 sector = clst2sect(file->obj.fs, iClusterStart) + bd->sectorOffset;
723 f[iFragCount].sector = sector;
724 f[iFragCount].count = clst2sect(file->obj.fs, iClusterCurrent) - clst2sect(file->obj.fs, iClusterStart) + file->obj.fs->csize;
725 DEBUG_U64_2XU32(sector);
726 M_DEBUG(" - sectors: 0x%08x%08x count %u\n", sector_u32[1], sector_u32[0], f[iFragCount].count);
727 }
728 iFragCount++;
729 iClusterStart = iClusterNext;
730 }
731 iClusterCurrent = iClusterNext;
732 } while(iClusterCurrent < file->obj.fs->n_fatent);
733
734 return iFragCount;
735}
736
737//---------------------------------------------------------------------------
738int fs_ioctl2(iop_file_t *fd, int cmd, void *data, unsigned int datalen, void *rdata, unsigned int rdatalen)
739{
740 M_DEBUG("%s cmd=%d\n", __func__, cmd);
741
742 int ret = 0;
743 FIL *file = ((FIL *)(fd->privdata));
744
745 (void)data;
746 (void)datalen;
747
748 if (file == NULL)
749 return -ENXIO;
750
751 _fs_lock();
752
753 switch (cmd) {
755 // TODO
756 // f_rename() requires two string parameters (newpath, oldpath)
757 // figure out how to get the path from the current entry object
758 ret = -ENOENT;
759 break;
761 ret = file->obj.sclust;
762 break;
764 // Check for a return buffer and copy the 64bit LBA. If no buffer is provided return an error.
765 if (rdata == NULL || rdatalen < sizeof(u64))
766 {
767 ret = -EINVAL;
768 break;
769 }
770
771 // Get the block device backing the file so we can get the starting LBA of the file system.
772 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
773
774 *(u64*)rdata = clst2sect(file->obj.fs, file->obj.sclust) + bd->sectorOffset;
775 ret = 0;
776 break;
778 struct block_device *mounted_bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
779 ret = (mounted_bd == NULL) ? -ENXIO : *(int *)(mounted_bd->name);
780
781 // Check for a return buffer and copy the whole name.
782 if (rdata != NULL)
783 strncpy(rdata, mounted_bd->name, rdatalen);
784 break;
785 }
787 ret = get_frag_list(file, NULL, 0) == 1 ? 1 : 0;
788 break;
790 ret = get_frag_list(file, rdata, rdatalen);
791 break;
793 {
794 // Check for a return buffer and copy the device number. If no buffer is provided return an error.
795 if (rdata == NULL || rdatalen < sizeof(u32))
796 {
797 ret = -EINVAL;
798 break;
799 }
800
801 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
802 if (bd == NULL)
803 ret = -ENXIO;
804 else
805 {
806 *(u32*)rdata = bd->devNr;
807 ret = 0;
808 }
809 break;
810 }
811 default:
812 break;
813 }
814
815 _fs_unlock();
816 return ret;
817}
818
819//---------------------------------------------------------------------------
820int fs_ioctl(iop_file_t *fd, int cmd, void *data)
821{
822 return fs_ioctl2(fd, cmd, data, 1024, NULL, 0);
823}
824
825int fs_rename(iop_file_t *fd, const char *path, const char *newpath)
826{
827 M_DEBUG("%s\n", __func__);
828
829 int ret;
830 int vol;
831 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(path);
832 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(newpath);
833
834 vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
835 if (vol < 0)
836 return -ENXIO;
837
838 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(path, vol);
839 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(newpath, vol);
840
841 // If old and new path are the same, no need to do anything
842 if (strcmp(modified_path, modified_newpath) == 0) {
843 return 0;
844 }
845
846 _fs_lock();
847
848 ret = f_rename(modified_path, modified_newpath);
849
850 _fs_unlock();
851 return -ret;
852}
853
854static int fs_devctl(iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
855{
856 int ret;
857
858 (void)name;
859 (void)arg;
860 (void)arglen;
861 (void)buf;
862 (void)buflen;
863
864 _fs_lock();
865
866
867 switch (cmd) {
869 fatfs_fs_driver_stop_all_bd();
870 ret = FR_OK;
871 break;
872 }
874 int vol = fs_driver_resolve_volume(fd->device->name, fd->unit);
875 if (vol >= 0)
876 fatfs_fs_driver_stop_single_bd(vol);
877 ret = FR_OK;
878 break;
879 }
880 default: {
881 ret = -ENXIO;
882 break;
883 }
884 }
885
886 _fs_unlock();
887
888 return ret;
889}
890
891IOMANX_RETURN_VALUE_IMPL(0);
892IOMANX_RETURN_VALUE_IMPL(EIO);
893
894static iop_device_ops_t fs_functarray = {
895 IOMANX_RETURN_VALUE(0), // init
896 IOMANX_RETURN_VALUE(0), // deinit
897 IOMANX_RETURN_VALUE(EIO), // format
898 &fs_open, // open
899 &fs_close, // close
900 &fs_read, // read
901 &fs_write, // write
902 &fs_lseek, // lseek
903 &fs_ioctl, // ioctl
904 &fs_remove, // remove
905 &fs_mkdir, // mkdir
906 &fs_remove, // rmdir
907 &fs_dopen, // dopen
908 &fs_dclose, // dclose
909 &fs_dread, // dread
910 &fs_getstat, // getstat
911 IOMANX_RETURN_VALUE(EIO), // chstat
912 &fs_rename, // rename
913 IOMANX_RETURN_VALUE(EIO), // chdir
914 IOMANX_RETURN_VALUE(EIO), // sync
915 IOMANX_RETURN_VALUE(EIO), // mount
916 IOMANX_RETURN_VALUE(EIO), // umount
917 &fs_lseek64, // lseek64
918 &fs_devctl, // devctl
919 IOMANX_RETURN_VALUE(EIO), // symlink
920 IOMANX_RETURN_VALUE(EIO), // readlink
921 &fs_ioctl2, // ioctl2
922};
923static iop_device_t fs_driver = {
924 "mass",
925 IOP_DT_FS | IOP_DT_FSEXT,
926 2,
927 "FATFS driver",
928 &fs_functarray,
929};
930
931/* init file system driver */
932int InitFS(void)
933{
934 M_DEBUG("%s\n", __func__);
935
936 fs_reset();
937 fatfs_fs_driver_initialize_all_mount_info();
938 fs_typed_driver_count = 0;
939
940 DelDrv(fs_driver.name);
941 return (AddDrv(&fs_driver) == 0 ? 0 : -1);
942}
#define ENOENT
Definition errno.h:23
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define EMFILE
Definition errno.h:67
#define EIO
Definition errno.h:29
unsigned int version
Definition ioman.h:68
#define IOP_DT_FSEXT
Definition iomanX.h:66
#define FIO_S_IROTH
Definition iox_stat.h:76
#define FIO_S_IXOTH
Definition iox_stat.h:80
#define FIO_S_IWOTH
Definition iox_stat.h:78
#define FIO_S_IFDIR
Definition iox_stat.h:45
#define FIO_S_IFREG
Definition iox_stat.h:43
#define USBMASS_IOCTL_GET_CLUSTER
#define USBMASS_IOCTL_GET_DRIVERNAME
u32 count
start sector of fragmented bd/file
#define USBMASS_DEVCTL_STOP_ALL
#define USBMASS_DEVCTL_STOP_UNIT
#define USBMASS_IOCTL_RENAME
#define USBMASS_IOCTL_GET_DEVICE_NUMBER
#define USBMASS_IOCTL_GET_LBA
#define USBMASS_IOCTL_GET_FRAGLIST
#define USBMASS_IOCTL_CHECK_CHAIN