PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
fs_driver.c
1//---------------------------------------------------------------------------
2// File name: fs_driver.c
3//---------------------------------------------------------------------------
4/*
5 * fat_driver.c - USB Mass storage driver for PS2
6 *
7 * (C) 2004, Marek Olejnik (ole00@post.cz)
8 * (C) 2004 Hermes (support for sector sizes from 512 to 4096 bytes)
9 * (C) 2004 raipsu (fs_dopen, fs_dclose, fs_dread, fs_getstat implementation)
10 *
11 * FAT filesystem layer
12 *
13 * See the file LICENSE included with this distribution for licensing terms.
14 */
15//---------------------------------------------------------------------------
16#include <stdio.h>
17#include <errno.h>
18#include <iomanX.h>
19
20#ifdef WIN32
21#include <memory.h>
22#include <string.h>
23#include <stdlib.h>
24#else
25#include <sysclib.h>
26#include <thsemap.h>
27#include <thbase.h>
28#include <sysmem.h>
29#endif
30
31#ifdef BUILDING_USBHDFSD
32#include <usbhdfsd.h>
33#else
34#include <usbhdfsd-common.h>
35#endif /* BUILDING_USBHDFSD */
36#include "usbhd_common.h"
37#include "fat_driver.h"
38#include "fat_write.h"
39#include "fat.h"
40#ifdef BUILDING_USBHDFSD
41#include "mass_stor.h"
42#endif /* BUILDING_USBHDFSD */
43#ifdef BUILDING_IEEE1394_DISK
44#include "sbp2_disk.h"
45#endif /* BUILDING_IEEE1394_DISK */
46
47// #define DEBUG //comment out this line when not debugging
48
49#include "mass_debug.h"
50
51#define FLUSH_SECTORS fat_flushSectors
52
53enum FS_FILE_FLAG {
54 FS_FILE_FLAG_FOLDER = 0,
55 FS_FILE_FLAG_FILE
56};
57
59{ // Common structure for both directories and regular files.
60 // This flag is always 1 for a file, and always 0 for a folder (different typedef)
61 // Routines that handle both must test it, and then typecast the privdata pointer
62 // to the type that is appropriate for the given case. (see also fs_dir typedef)
63 short int file_flag;
64 short int sizeChange; // flag, used for regular files. Otherwise padding.
65 fat_dir fatdir;
66};
67
68typedef struct _fs_rec
69{
70 struct fs_dirent dirent;
71 short int sizeChange; // flag
72 unsigned int filePos;
73 int mode; // file open mode
74 unsigned int sfnSector; // short filename sector - write support
75 int sfnOffset; // short filename offset - write support
76} fs_rec;
77
78typedef struct _fs_dir
79{
80 struct fs_dirent dirent;
81 int status;
82 fat_dir_list fatdlist;
83 fat_dir current_fatdir;
84} fs_dir;
85
86#define MAX_FILES 128
87static fs_rec fsRec[MAX_FILES]; // file info record
88
89static void fillStat(iox_stat_t *stat, const fat_dir *fatdir)
90{
91 stat->mode = FIO_S_IROTH | FIO_S_IXOTH;
92 if (fatdir->attr & FAT_ATTR_DIRECTORY) {
93 stat->mode |= FIO_S_IFDIR;
94 } else {
95 stat->mode |= FIO_S_IFREG;
96 }
97 if (!(fatdir->attr & FAT_ATTR_READONLY)) {
98 stat->mode |= FIO_S_IWOTH;
99 }
100
101 stat->size = fatdir->size;
102
103 // set created Date: Day, Month, Year
104 stat->ctime[4] = fatdir->cdate[0];
105 stat->ctime[5] = fatdir->cdate[1];
106 stat->ctime[6] = fatdir->cdate[2];
107 stat->ctime[7] = fatdir->cdate[3];
108
109 // set created Time: Hours, Minutes, Seconds
110 stat->ctime[3] = fatdir->ctime[0];
111 stat->ctime[2] = fatdir->ctime[1];
112 stat->ctime[1] = fatdir->ctime[2];
113
114 // set accessed Date: Day, Month, Year
115 stat->atime[4] = fatdir->adate[0];
116 stat->atime[5] = fatdir->adate[1];
117 stat->atime[6] = fatdir->adate[2];
118 stat->atime[7] = fatdir->adate[3];
119
120 // set modified Date: Day, Month, Year
121 stat->mtime[4] = fatdir->mdate[0];
122 stat->mtime[5] = fatdir->mdate[1];
123 stat->mtime[6] = fatdir->mdate[2];
124 stat->mtime[7] = fatdir->mdate[3];
125
126 // set modified Time: Hours, Minutes, Seconds
127 stat->mtime[3] = fatdir->mtime[0];
128 stat->mtime[2] = fatdir->mtime[1];
129 stat->mtime[1] = fatdir->mtime[2];
130}
131
132/*************************************************************************************/
133/* File IO functions */
134/*************************************************************************************/
135
136//---------------------------------------------------------------------------
137static fs_rec *fs_findFreeFileSlot(void)
138{
139 int i;
140
141 M_DEBUG("%s\n", __func__);
142
143 for (i = 0; i < MAX_FILES; i++) {
144 if (fsRec[i].dirent.file_flag < 0) {
145 return &fsRec[i];
146 }
147 }
148 return NULL;
149}
150
151//---------------------------------------------------------------------------
152static fs_rec *fs_findFileSlotByCluster(unsigned int startCluster)
153{
154 int i;
155
156 M_DEBUG("%s\n", __func__);
157
158 for (i = 0; i < MAX_FILES; i++) {
159 if (fsRec[i].dirent.file_flag >= 0 && fsRec[i].dirent.fatdir.startCluster == startCluster) {
160 return &fsRec[i];
161 }
162 }
163 return NULL;
164}
165
166//---------------------------------------------------------------------------
167static int _lock_sema_id = -1;
168
169//---------------------------------------------------------------------------
170static int _fs_init_lock(void)
171{
172 M_DEBUG("%s\n", __func__);
173
174#ifndef WIN32
175 iop_sema_t sp;
176
177 sp.initial = 1;
178 sp.max = 1;
179 sp.option = 0;
180 sp.attr = 0;
181 if ((_lock_sema_id = CreateSema(&sp)) < 0) {
182 return (-1);
183 }
184#endif
185
186 return (0);
187}
188
189//---------------------------------------------------------------------------
190static void _fs_lock(void)
191{
192 M_DEBUG("%s\n", __func__);
193
194#ifndef WIN32
195 WaitSema(_lock_sema_id);
196#endif
197}
198
199//---------------------------------------------------------------------------
200static void _fs_unlock(void)
201{
202 M_DEBUG("%s\n", __func__);
203
204#ifndef WIN32
205 SignalSema(_lock_sema_id);
206#endif
207}
208
209//---------------------------------------------------------------------------
210static void fs_reset(void)
211{
212 int i;
213
214 M_DEBUG("%s\n", __func__);
215
216 for (i = 0; i < MAX_FILES; i++) {
217 fsRec[i].dirent.file_flag = -1;
218 }
219#ifndef WIN32
220 if (_lock_sema_id >= 0) {
221 DeleteSema(_lock_sema_id);
222 }
223#endif
224 _fs_init_lock();
225}
226
227//---------------------------------------------------------------------------
228static int fs_inited = 0;
229
230//---------------------------------------------------------------------------
231static int fs_init(iop_device_t *driver)
232{
233 (void)driver;
234
235 M_DEBUG("%s\n", __func__);
236
237 if (!fs_inited) {
238 fs_reset();
239 fs_inited = 1;
240 }
241
242 return 1;
243}
244
245//---------------------------------------------------------------------------
246static int fs_open(iop_file_t *fd, const char *name, int flags, int mode)
247{
248 fat_driver *fatd;
249 fs_rec *rec;
250 int ret;
251 unsigned int cluster;
252
253 (void)mode;
254
255 M_DEBUG("%s: %s flags=%X mode=%X\n", __func__, name, flags, mode);
256
257 _fs_lock();
258
259 XPRINTF("fs_open called: %s flags=%X mode=%X \n", name, flags, mode);
260
261 fatd = fat_getData(fd->unit);
262 if (fatd == NULL) {
263 _fs_unlock();
264 return -ENODEV;
265 }
266
267 // check if the slot is free
268 rec = fs_findFreeFileSlot();
269 if (rec == NULL) {
270 _fs_unlock();
271 return -EMFILE;
272 }
273
274 // find the file
275 cluster = 0; // allways start from root
276 XPRINTF("Calling fat_getFileStartCluster from fs_open\n");
277 ret = fat_getFileStartCluster(fatd, name, &cluster, &rec->dirent.fatdir);
278 if (ret < 0 && ret != -ENOENT) {
279 _fs_unlock();
280 return ret;
281 } else {
282 fs_rec *rec2;
283
284 // File exists. Check if the file is already open
285 rec2 = fs_findFileSlotByCluster(rec->dirent.fatdir.startCluster);
286 if (rec2 != NULL) {
287 if ((flags & O_WRONLY) || // current file is opened for write
288 (rec2->mode & O_WRONLY)) { // other file is opened for write
289 _fs_unlock();
290 return -EACCES;
291 }
292 }
293 }
294
295 if (flags & O_WRONLY) { // dlanor: corrected bad test condition
296 char escapeNotExist;
297
298 cluster = 0; // start from root
299
300 escapeNotExist = 1;
301 if (flags & O_CREAT) {
302 XPRINTF("FAT I: O_CREAT detected!\n");
303 escapeNotExist = 0;
304 }
305
306 rec->sfnSector = 0;
307 rec->sfnOffset = 0;
308 ret = fat_createFile(fatd, name, 0, escapeNotExist, &cluster, &rec->sfnSector, &rec->sfnOffset);
309 if (ret < 0) {
310 FLUSH_SECTORS(fatd);
311 _fs_unlock();
312 return ret;
313 }
314 // the file already exist but flags is set to truncate
315 if (ret == EEXIST && (flags & O_TRUNC)) {
316 XPRINTF("FAT I: O_TRUNC detected!\n");
317 ret = fat_truncateFile(fatd, cluster, rec->sfnSector, rec->sfnOffset);
318 if (ret < 0) {
319 FLUSH_SECTORS(fatd);
320 XPRINTF("FAT E: failed to truncate!\n");
321 _fs_unlock();
322 return ret;
323 }
324 }
325
326 // find the file
327 cluster = 0; // allways start from root
328 XPRINTF("Calling fat_getFileStartCluster from fs_open after file creation\n");
329 ret = fat_getFileStartCluster(fatd, name, &cluster, &rec->dirent.fatdir);
330 }
331
332 if (ret < 0) { // At this point, the file should be locatable without any errors.
333 _fs_unlock();
334 return ret;
335 }
336
337 if ((rec->dirent.fatdir.attr & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) {
338 // Can't open a directory with open
339 _fs_unlock();
340 return -EISDIR;
341 }
342
343 rec->dirent.file_flag = FS_FILE_FLAG_FILE;
344 rec->mode = flags;
345 rec->filePos = 0;
346 rec->sizeChange = 0;
347
348 if ((flags & O_APPEND) && (flags & O_WRONLY)) {
349 XPRINTF("FAT I: O_APPEND detected!\n");
350 rec->filePos = rec->dirent.fatdir.size;
351 }
352
353 // store the slot to user parameters
354 fd->privdata = rec;
355
356 _fs_unlock();
357 return 1;
358}
359
360//---------------------------------------------------------------------------
361static int fs_close(iop_file_t *fd)
362{
363 fat_driver *fatd;
364 fs_rec *rec = (fs_rec *)fd->privdata;
365
366 M_DEBUG("%s\n", __func__);
367
368 if (rec == NULL)
369 return -EBADF;
370
371 _fs_lock();
372
373 if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) {
374 _fs_unlock();
375 return -EISDIR;
376 }
377
378 rec->dirent.file_flag = -1;
379 fd->privdata = NULL;
380
381 fatd = fat_getData(fd->unit);
382 if (fatd == NULL) {
383 _fs_unlock();
384 return -ENODEV;
385 }
386
387 if ((rec->mode & O_WRONLY)) {
388 // update direntry size and time
389 if (rec->sizeChange) {
390 fat_updateSfn(fatd, rec->dirent.fatdir.size, rec->sfnSector, rec->sfnOffset);
391 }
392
393 FLUSH_SECTORS(fatd);
394 }
395
396 _fs_unlock();
397 return 0;
398}
399
400//---------------------------------------------------------------------------
401static int fs_lseek(iop_file_t *fd, int offset, int whence)
402{
403 fat_driver *fatd;
404 fs_rec *rec = (fs_rec *)fd->privdata;
405
406 M_DEBUG("%s\n", __func__);
407
408 if (rec == NULL)
409 return -EBADF;
410
411 _fs_lock();
412
413 fatd = fat_getData(fd->unit);
414 if (fatd == NULL) {
415 _fs_unlock();
416 return -ENODEV;
417 }
418
419 if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) {
420 _fs_unlock();
421 return -EISDIR;
422 }
423
424 switch (whence) {
425 case SEEK_SET:
426 rec->filePos = offset;
427 break;
428 case SEEK_CUR:
429 rec->filePos += offset;
430 break;
431 case SEEK_END:
432 rec->filePos = rec->dirent.fatdir.size + offset;
433 break;
434 default:
435 _fs_unlock();
436 return -EPERM;
437 }
438 if ((int)(rec->filePos) < 0) {
439 rec->filePos = 0;
440 }
441 if (rec->filePos > rec->dirent.fatdir.size) {
442 rec->filePos = rec->dirent.fatdir.size;
443 }
444
445 _fs_unlock();
446 return rec->filePos;
447}
448
449//---------------------------------------------------------------------------
450static int fs_write(iop_file_t *fd, void *buffer, int size)
451{
452 fat_driver *fatd;
453 fs_rec *rec = (fs_rec *)fd->privdata;
454 int result;
455 int updateClusterIndices = 0;
456
457 M_DEBUG("%s\n", __func__);
458
459 if (rec == NULL)
460 return -EBADF;
461
462 _fs_lock();
463
464 fatd = fat_getData(fd->unit);
465 if (fatd == NULL) {
466 _fs_unlock();
467 return -ENODEV;
468 }
469
470 if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) {
471 _fs_unlock();
472 return -EISDIR;
473 }
474
475 if (!(rec->mode & O_WRONLY)) {
476 _fs_unlock();
477 return -EACCES;
478 }
479
480 if (size <= 0) {
481 _fs_unlock();
482 return 0;
483 }
484
485 result = fat_writeFile(fatd, &rec->dirent.fatdir, &updateClusterIndices, rec->filePos, (unsigned char *)buffer, size);
486 if (result > 0) { // write succesful
487 rec->filePos += result;
488 if (rec->filePos > rec->dirent.fatdir.size) {
489 rec->dirent.fatdir.size = rec->filePos;
490 rec->sizeChange = 1;
491 // if new clusters allocated - then update file cluster indices
492 if (updateClusterIndices) {
493 fat_setFatDirChain(fatd, &rec->dirent.fatdir);
494 }
495 }
496 }
497
498 _fs_unlock();
499 return result;
500}
501
502//---------------------------------------------------------------------------
503static int fs_read(iop_file_t *fd, void *buffer, int size)
504{
505 fat_driver *fatd;
506 fs_rec *rec = (fs_rec *)fd->privdata;
507 int result;
508
509 M_DEBUG("%s\n", __func__);
510
511 if (rec == NULL)
512 return -EBADF;
513
514 _fs_lock();
515
516 fatd = fat_getData(fd->unit);
517 if (fatd == NULL) {
518 _fs_unlock();
519 return -ENODEV;
520 }
521
522 if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) {
523 _fs_unlock();
524 return -EISDIR;
525 }
526
527 if (!(rec->mode & O_RDONLY)) {
528 _fs_unlock();
529 return -EACCES;
530 }
531
532 if (size <= 0) {
533 _fs_unlock();
534 return 0;
535 }
536
537 if ((rec->filePos + size) > rec->dirent.fatdir.size) {
538 size = rec->dirent.fatdir.size - rec->filePos;
539 }
540
541 result = fat_readFile(fatd, &rec->dirent.fatdir, rec->filePos, (unsigned char *)buffer, size);
542 if (result > 0) { // read succesful
543 rec->filePos += result;
544 }
545
546 _fs_unlock();
547 return result;
548}
549
550//---------------------------------------------------------------------------
551static int fs_remove(iop_file_t *fd, const char *name)
552{
553 fat_driver *fatd;
554 fs_rec *rec;
555 int result;
556 unsigned int cluster;
557 fat_dir fatdir;
558
559 M_DEBUG("%s\n", __func__);
560
561 _fs_lock();
562
563 fatd = fat_getData(fd->unit);
564 if (fatd == NULL) {
565 result = -ENODEV;
566 _fs_unlock();
567 return result;
568 }
569
570 cluster = 0; // allways start from root
571 XPRINTF("Calling fat_getFileStartCluster from fs_remove\n");
572 result = fat_getFileStartCluster(fatd, name, &cluster, &fatdir);
573 if (result < 0) {
574 _fs_unlock();
575 return result;
576 }
577
578 rec = fs_findFileSlotByCluster(fatdir.startCluster);
579
580 // file is opened - can't delete the file
581 if (rec != NULL) {
582 result = -EINVAL;
583 _fs_unlock();
584 return result;
585 }
586
587 result = fat_deleteFile(fatd, name, 0);
588 FLUSH_SECTORS(fatd);
589
590 _fs_unlock();
591 return result;
592}
593
594//---------------------------------------------------------------------------
595static int fs_mkdir(iop_file_t *fd, const char *name, int mode)
596{
597 fat_driver *fatd;
598 int ret;
599 int sfnOffset;
600 unsigned int sfnSector;
601 unsigned int cluster;
602
603 M_DEBUG("%s\n", __func__);
604
605 (void)mode;
606
607 _fs_lock();
608
609 fatd = fat_getData(fd->unit);
610 if (fatd == NULL) {
611 _fs_unlock();
612 return -ENODEV;
613 }
614
615 XPRINTF("fs_mkdir: name=%s \n", name);
616 ret = fat_createFile(fatd, name, 1, 0, &cluster, &sfnSector, &sfnOffset);
617
618 // directory of the same name already exist
619 if (ret == 2) {
620 ret = -EEXIST;
621 }
622 FLUSH_SECTORS(fatd);
623
624 _fs_unlock();
625 return ret;
626}
627
628//---------------------------------------------------------------------------
629static int fs_rmdir(iop_file_t *fd, const char *name)
630{
631 fat_driver *fatd;
632 int ret;
633
634 M_DEBUG("%s\n", __func__);
635
636 _fs_lock();
637
638 fatd = fat_getData(fd->unit);
639 if (fatd == NULL) {
640 _fs_unlock();
641 return -ENODEV;
642 }
643
644 ret = fat_deleteFile(fatd, name, 1);
645 FLUSH_SECTORS(fatd);
646 _fs_unlock();
647 return ret;
648}
649
650//---------------------------------------------------------------------------
651static int fs_dopen(iop_file_t *fd, const char *name)
652{
653 fat_driver *fatd;
654 int is_root = 0;
655 fs_dir *rec;
656
657 M_DEBUG("%s: unit %d name %s\n", __func__, fd->unit, name);
658
659 _fs_lock();
660
661 XPRINTF("fs_dopen called: unit %d name %s\n", fd->unit, name);
662
663 fatd = fat_getData(fd->unit);
664 if (fatd == NULL) {
665 _fs_unlock();
666 return -ENODEV;
667 }
668
669 if (((name[0] == '/') && (name[1] == '\0')) || ((name[0] == '/') && (name[1] == '.') && (name[2] == '\0'))) {
670 name = "/";
671 is_root = 1;
672 }
673
674 fd->privdata = malloc(sizeof(fs_dir));
675 memset(fd->privdata, 0, sizeof(fs_dir)); // NB: also implies "file_flag = FS_FILE_FLAG_FOLDER;"
676 rec = (fs_dir *)fd->privdata;
677
678 rec->status = fat_getFirstDirentry(fatd, name, &rec->fatdlist, &rec->dirent.fatdir, &rec->current_fatdir);
679
680 // root directory may have no entries, nothing else may.
681 if (rec->status == 0 && !is_root)
682 rec->status = -EFAULT;
683
684 if (rec->status < 0)
685 free(fd->privdata);
686
687 _fs_unlock();
688 return rec->status;
689}
690
691//---------------------------------------------------------------------------
692static int fs_dclose(iop_file_t *fd)
693{
694 fs_dir *rec = (fs_dir *)fd->privdata;
695
696 M_DEBUG("%s\n", __func__);
697
698 if (fd->privdata == NULL)
699 return -EBADF;
700
701 _fs_lock();
702 XPRINTF("fs_dclose called: unit %d\n", fd->unit);
703 if (rec->dirent.file_flag != FS_FILE_FLAG_FOLDER) {
704 _fs_unlock();
705 return -ENOTDIR;
706 }
707
708 free(fd->privdata);
709 fd->privdata = NULL;
710 _fs_unlock();
711 return 0;
712}
713
714//---------------------------------------------------------------------------
715static int fs_dread(iop_file_t *fd, iox_dirent_t *buffer)
716{
717 fat_driver *fatd;
718 int ret;
719 fs_dir *rec = (fs_dir *)fd->privdata;
720
721 M_DEBUG("%s\n", __func__);
722
723 if (rec == NULL)
724 return -EBADF;
725
726 _fs_lock();
727
728 XPRINTF("fs_dread called: unit %d\n", fd->unit);
729
730 fatd = fat_getData(fd->unit);
731 if (fatd == NULL) {
732 _fs_unlock();
733 return -ENODEV;
734 }
735
736 if (rec->dirent.file_flag != FS_FILE_FLAG_FOLDER) {
737 _fs_unlock();
738 return -ENOTDIR;
739 }
740
741 while (rec->status > 0 && (rec->current_fatdir.attr & FAT_ATTR_VOLUME_LABEL || ((rec->current_fatdir.attr & (FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM)) == (FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM))))
742 rec->status = fat_getNextDirentry(fatd, &rec->fatdlist, &rec->current_fatdir);
743
744 ret = rec->status;
745 if (rec->status >= 0) {
746 memset(buffer, 0, sizeof(iox_dirent_t));
747 fillStat(&buffer->stat, &rec->current_fatdir);
748 strcpy(buffer->name, (const char *)rec->current_fatdir.name);
749 }
750
751 if (rec->status > 0)
752 rec->status = fat_getNextDirentry(fatd, &rec->fatdlist, &rec->current_fatdir);
753
754 _fs_unlock();
755 return ret;
756}
757
758//---------------------------------------------------------------------------
759static int fs_getstat(iop_file_t *fd, const char *name, iox_stat_t *stat)
760{
761 fat_driver *fatd;
762 int ret;
763 unsigned int cluster = 0;
764 fat_dir fatdir;
765
766 M_DEBUG("%s: unit %d name %s\n", __func__, fd->unit, name);
767
768 _fs_lock();
769
770 XPRINTF("fs_getstat called: unit %d name %s\n", fd->unit, name);
771
772 fatd = fat_getData(fd->unit);
773 if (fatd == NULL) {
774 _fs_unlock();
775 return -ENODEV;
776 }
777
778 XPRINTF("Calling fat_getFileStartCluster from fs_getstat\n");
779 ret = fat_getFileStartCluster(fatd, name, &cluster, &fatdir);
780 if (ret < 0) {
781 _fs_unlock();
782 return ret;
783 }
784
785 memset(stat, 0, sizeof(iox_stat_t));
786 fillStat(stat, &fatdir);
787
788 _fs_unlock();
789 return 0;
790}
791
792//---------------------------------------------------------------------------
793int fs_ioctl(iop_file_t *fd, int cmd, void *data)
794{
795 fat_driver *fatd;
796 struct fs_dirent *dirent = (struct fs_dirent *)fd->privdata; // Remember to re-cast this to the right structure (either fs_rec or fs_dir)!
797 int ret;
798
799 M_DEBUG("%s\n", __func__);
800
801 if (dirent == NULL)
802 return -EBADF;
803
804 _fs_lock();
805
806 fatd = fat_getData(fd->unit);
807 if (fatd == NULL) {
808 _fs_unlock();
809 return -ENODEV;
810 }
811
812 switch (cmd) {
814 ret = fat_renameFile(fatd, &dirent->fatdir, data); // No need to re-cast since this inner structure is a common one.
815 FLUSH_SECTORS(fatd);
816 break;
817#ifdef BUILDING_USBHDFSD
819 ret = ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster;
820 break;
822 ret = fat_cluster2sector(&fatd->partBpb, ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster);
823 break;
825 ret = fat_CheckChain(fatd, ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster);
826 break;
827#endif /* BUILDING_USBHDFSD */
828#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
830 ret = *(int *)fatd->bd->name;
831 break;
832#endif
833 default:
834 ret = -EIO;
835 }
836
837 _fs_unlock();
838 return ret;
839}
840
841int fs_rename(iop_file_t *fd, const char *path, const char *newpath)
842{
843 fat_dir fatdir;
844 fat_driver *fatd;
845 fs_rec *rec = NULL;
846 unsigned int cluster;
847 struct fs_dirent *dirent = (struct fs_dirent *)fd->privdata;
848 int ret;
849
850 if (dirent == NULL)
851 return -EBADF;
852
853 _fs_lock();
854
855 fatd = fat_getData(fd->unit);
856 if (fatd == NULL) {
857 _fs_unlock();
858 return -ENODEV;
859 }
860
861 // find the file
862 cluster = 0; // allways start from root
863 XPRINTF("Calling fat_getFileStartCluster from fs_rename\n");
864 ret = fat_getFileStartCluster(fatd, path, &cluster, &fatdir);
865 if (ret < 0 && ret != -ENOENT) {
866 _fs_unlock();
867 return ret;
868 } else {
869 // File exists. Check if the file is already open
870 rec = fs_findFileSlotByCluster(fatdir.startCluster);
871 if (rec != NULL) {
872 _fs_unlock();
873 return -EACCES;
874 }
875 }
876
877 ret = fat_renameFile(fatd, &fatdir, newpath);
878 FLUSH_SECTORS(fatd);
879
880 _fs_unlock();
881 return ret;
882}
883
884#ifndef BUILDING_IEEE1394_DISK
885static int fs_devctl(iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
886{
887#ifdef BUILDING_USBHDFSD
888 fat_driver *fatd;
889#endif
890 int ret;
891
892 (void)name;
893 (void)arg;
894 (void)arglen;
895 (void)buf;
896 (void)buflen;
897
898 _fs_lock();
899
900 switch (cmd) {
902#ifdef BUILDING_USBHDFSD
903 fatd = fat_getData(fd->unit);
904 ret = (fatd != NULL) ? mass_stor_stop_unit(fatd->dev) : -ENODEV;
905#else
906 ret = fat_stopUnit(fd->unit);
907#endif
908 break;
910#ifdef BUILDING_USBHDFSD
911 mass_store_stop_all();
912#else
913 fat_stopAll();
914#endif
915 ret = 0;
916 break;
917 default:
918 ret = -ENXIO;
919 }
920
921 _fs_unlock();
922
923 return ret;
924}
925#endif /* BUILDING_USBHDFSD */
926
927#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
928static int fs_ioctl2(iop_file_t *fd, int cmd, void *data, unsigned int datalen, void *rdata, unsigned int rdatalen)
929{
930 fat_driver *fatd;
931 int ret;
932
933 if (fd == NULL)
934 return -ENXIO;
935
936 struct fs_dirent *dirent = (struct fs_dirent *)fd->privdata; // Remember to re-cast this to the right structure (either fs_rec or fs_dir)!
937
938 M_DEBUG("%s\n", __func__);
939
940 if (dirent == NULL)
941 return -EBADF;
942
943 _fs_lock();
944
945 fatd = fat_getData(fd->unit);
946 if (fatd == NULL) {
947 _fs_unlock();
948 return -ENODEV;
949 }
950
951 switch (cmd) {
953 {
954 // Check for a return buffer and copy the 64bit LBA. If no buffer is provided return an error.
955 if (rdata == NULL || rdatalen < sizeof(u64))
956 {
957 ret = -EINVAL;
958 break;
959 }
960
961 // Get the block device backing the file so we can get the starting LBA of the file system.
962 struct block_device* bd = fatd->cache->bd;
963
964 *(u64*)rdata = (u64)fat_cluster2sector(&fatd->partBpb, ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster) + bd->sectorOffset;
965 ret = 0;
966 break;
967 }
969 {
970 // Check for a return buffer and copy the device number. If no buffer is provided return an error.
971 if (rdata == NULL || rdatalen < sizeof(u32))
972 {
973 ret = -EINVAL;
974 break;
975 }
976
977 struct block_device* bd = fatd->cache->bd;
978 if (bd == NULL)
979 ret = -ENXIO;
980 else
981 {
982 *(u32*)rdata = bd->devNr;
983 ret = 0;
984 }
985 break;
986 }
987 default:
988 ret = -EIO;;
989 }
990
991 _fs_unlock();
992 return ret;
993}
994#endif
995
996#ifndef WIN32
997
998IOMANX_RETURN_VALUE_IMPL(0);
999IOMANX_RETURN_VALUE_IMPL(EIO);
1000
1001static iop_device_ops_t fs_functarray = {
1002 &fs_init, // init
1003 IOMANX_RETURN_VALUE(0), // deinit
1004 IOMANX_RETURN_VALUE(EIO), // format
1005 &fs_open, // open
1006 &fs_close, // close
1007 &fs_read, // read
1008 &fs_write, // write
1009 &fs_lseek, // lseek
1010 &fs_ioctl, // ioctl
1011 &fs_remove, // remove
1012 &fs_mkdir, // mkdir
1013 &fs_rmdir, // rmdir
1014 &fs_dopen, // dopen
1015 &fs_dclose, // dclose
1016 &fs_dread, // dread
1017 &fs_getstat, // getstat
1018 IOMANX_RETURN_VALUE(EIO), // chstat
1019 &fs_rename, // rename
1020 IOMANX_RETURN_VALUE(EIO), // chdir
1021 IOMANX_RETURN_VALUE(EIO), // sync
1022 IOMANX_RETURN_VALUE(EIO), // mount
1023 IOMANX_RETURN_VALUE(EIO), // umount
1024 IOMANX_RETURN_VALUE_S64(EIO), // lseek64
1025#ifndef BUILDING_IEEE1394_DISK
1026 &fs_devctl, // devctl
1027#else
1028 IOMANX_RETURN_VALUE(EIO), // devctl
1029#endif /* BUILDING_IEEE1394_DISK */
1030 IOMANX_RETURN_VALUE(EIO), // symlink
1031 IOMANX_RETURN_VALUE(EIO), // readlink
1032#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
1033 &fs_ioctl2, // ioctl2
1034#else
1035 IOMANX_RETURN_VALUE(EIO), // ioctl2
1036#endif /* BUILDING_IEEE1394_DISK */
1037};
1038static iop_device_t fs_driver = {
1039#ifdef BUILDING_IEEE1394_DISK
1040 "sd",
1041#else
1042 "mass",
1043#endif /* BUILDING_IEEE1394_DISK */
1044 IOP_DT_FS | IOP_DT_FSEXT,
1045 2,
1046#ifdef BUILDING_USBHDFSD
1047 "USB mass storage driver",
1048#endif /* BUILDING_USBHDFSD */
1049#ifdef BUILDING_IEEE1394_DISK
1050 "IEEE1394_disk",
1051#endif /* BUILDING_IEEE1394_DISK */
1052#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
1053 "VFAT driver",
1054#endif
1055 &fs_functarray,
1056};
1057
1058/* init file system driver */
1059int InitFS(void)
1060{
1061 M_DEBUG("%s\n", __func__);
1062
1063 DelDrv(fs_driver.name);
1064 return (AddDrv(&fs_driver) == 0 ? 0 : -1);
1065}
1066#endif
1067
1068//---------------------------------------------------------------------------
1069// End of file: fs_driver.c
1070//---------------------------------------------------------------------------
#define ENOENT
Definition errno.h:23
#define EEXIST
Definition errno.h:53
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define EFAULT
Definition errno.h:47
#define EMFILE
Definition errno.h:67
#define EIO
Definition errno.h:29
#define ENOTDIR
Definition errno.h:59
#define ENODEV
Definition errno.h:57
#define EACCES
Definition errno.h:45
#define EBADF
Definition errno.h:37
#define EPERM
Definition errno.h:21
#define EISDIR
Definition errno.h:61
#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
#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_CHECK_CHAIN