PS2SDK
PS2 Homebrew Libraries
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 
31 fatfs_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 //---------------------------------------------------------------------------
64 static int _fs_lock_sema_id = -1;
65 
66 //---------------------------------------------------------------------------
67 static 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 //---------------------------------------------------------------------------
85 static void _fs_lock(void)
86 {
87  //M_DEBUG("%s\n", __func__);
88 
89  WaitSema(_fs_lock_sema_id);
90 }
91 
92 //---------------------------------------------------------------------------
93 static void _fs_unlock(void)
94 {
95  //M_DEBUG("%s\n", __func__);
96 
97  SignalSema(_fs_lock_sema_id);
98 }
99 
100 //---------------------------------------------------------------------------
101 static 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 
111 static 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 
120 static 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 
131 static 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 
136 struct 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 
146 static 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 
165 static 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 
176 static 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 
187 static 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
198 static iop_device_t fs_typed_drivers[FS_MAX_TYPED_DRIVERS];
199 static char fs_typed_driver_names[FS_MAX_TYPED_DRIVERS][16];
200 static int fs_typed_driver_count = 0;
201 
202 // Forward declaration for the shared ops table used by all typed drivers.
203 static 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.
207 static 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.
245 static 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 
267 int 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 
290 void 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
305 static FIL fil_structures[MAX_FILES];
306 
307 #define MAX_DIRS 16
308 static DIR dir_structures[MAX_DIRS];
309 
310 static 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 
324 static 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 //---------------------------------------------------------------------------
339 static 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 //---------------------------------------------------------------------------
391 static 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 
410 s64 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 
440 static int fs_lseek(iop_file_t *fd, int offset, int whence)
441 {
442  return fs_lseek64(fd, (s64)offset, whence);
443 }
444 
445 //---------------------------------------------------------------------------
446 static 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 //---------------------------------------------------------------------------
465 static 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 //---------------------------------------------------------------------------
484 static 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 //---------------------------------------------------------------------------
507 static 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 //---------------------------------------------------------------------------
532 static 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 //---------------------------------------------------------------------------
567 static 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 
586 static 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 //---------------------------------------------------------------------------
631 static 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 //---------------------------------------------------------------------------
658 static 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));
683  stat->mode = FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH | FIO_S_IFDIR;
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 
704 static 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 //---------------------------------------------------------------------------
738 int 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 //---------------------------------------------------------------------------
820 int fs_ioctl(iop_file_t *fd, int cmd, void *data)
821 {
822  return fs_ioctl2(fd, cmd, data, 1024, NULL, 0);
823 }
824 
825 int 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 
854 static 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 
891 IOMANX_RETURN_VALUE_IMPL(0);
892 IOMANX_RETURN_VALUE_IMPL(EIO);
893 
894 static 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 };
923 static 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 */
932 int 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 }
USBMASS_IOCTL_GET_FRAGLIST
#define USBMASS_IOCTL_GET_FRAGLIST
Definition: usbhdfsd-common.h:37
iomanX.h
USBMASS_IOCTL_GET_CLUSTER
#define USBMASS_IOCTL_GET_CLUSTER
Definition: usbhdfsd-common.h:29
bdm.h
USBMASS_DEVCTL_STOP_UNIT
#define USBMASS_DEVCTL_STOP_UNIT
Definition: usbhdfsd-common.h:43
iox_stat_t
Definition: iox_stat.h:92
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
FIO_S_IFDIR
#define FIO_S_IFDIR
Definition: iox_stat.h:45
thbase.h
iop_sema_t
Definition: thsemap.h:38
sysclib.h
ENXIO
#define ENXIO
Definition: errno.h:31
FIO_S_IFREG
#define FIO_S_IFREG
Definition: iox_stat.h:43
USBMASS_DEVCTL_STOP_ALL
#define USBMASS_DEVCTL_STOP_ALL
Definition: usbhdfsd-common.h:45
usbhdfsd-common.h
EIO
#define EIO
Definition: errno.h:29
USBMASS_IOCTL_GET_DEVICE_NUMBER
#define USBMASS_IOCTL_GET_DEVICE_NUMBER
Definition: usbhdfsd-common.h:39
ENOENT
#define ENOENT
Definition: errno.h:23
fatfs_fs_driver_mount_info_
Definition: fs_driver.h:7
USBMASS_IOCTL_RENAME
#define USBMASS_IOCTL_RENAME
Definition: usbhdfsd-common.h:27
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
FIO_S_IXOTH
#define FIO_S_IXOTH
Definition: iox_stat.h:80
thsemap.h
_iop_file
Definition: ioman.h:53
FIO_S_IROTH
#define FIO_S_IROTH
Definition: iox_stat.h:76
stdio.h
USBMASS_IOCTL_CHECK_CHAIN
#define USBMASS_IOCTL_CHECK_CHAIN
Definition: usbhdfsd-common.h:35
USBMASS_IOCTL_GET_LBA
#define USBMASS_IOCTL_GET_LBA
Definition: usbhdfsd-common.h:31
iox_dirent_t
Definition: iox_stat.h:111
_iop_device_ops
Definition: ioman.h:79
_iop_device::version
unsigned int version
Definition: ioman.h:68
sysmem.h
FIO_S_IWOTH
#define FIO_S_IWOTH
Definition: iox_stat.h:78
EINVAL
#define EINVAL
Definition: errno.h:63
_iop_device
Definition: ioman.h:64
block_device
Definition: bdm.h:21
USBMASS_IOCTL_GET_DRIVERNAME
#define USBMASS_IOCTL_GET_DRIVERNAME
Definition: usbhdfsd-common.h:33
errno.h
EMFILE
#define EMFILE
Definition: errno.h:67