s32 handleFFSIoctl(ipcmessage *msg) { s32 ret = 0; u32 cmd = msg->ioctl.command; u32 length_io = msg->ioctl.length_io; u32 *buffer_io = msg->ioctl.buffer_io; u32 *buffer_in = msg->ioctl.buffer_in; switch(cmd) { case FFS_IOCTL_CREATEDIR: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; char dirname[MAX_FILENAME_SIZE]; preappend_nand_dev_name((const char *) buffer_in, dirname); ret = FAT_MakeDir(dirname); break; } case FFS_IOCTL_CREATEFILE: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; char filename[MAX_FILENAME_SIZE]; preappend_nand_dev_name((const char *) buffer_in, filename); ret = FAT_MakeFile(filename); break; } case FFS_IOCTL_DELETE: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; char filename[MAX_FILENAME_SIZE]; preappend_nand_dev_name((const char *) buffer_in, filename); ret = FAT_Delete(filename); break; } case FFS_IOCTL_RENAME: { u8 *names = (u8 *) buffer_in; if (emulationType == FFS_EMU_NONE) goto originalIoctl; char newname[MAX_FILENAME_SIZE]; char oldname[MAX_FILENAME_SIZE]; struct stat filestat; preappend_nand_dev_name((const char *)names, oldname); preappend_nand_dev_name((const char *) names+OFFSET_NEW_NAME, newname); // Check if newname exists if (FAT_Stat(newname, &filestat) >=0) { if (S_ISDIR(filestat.st_mode)) FAT_DeleteDir(newname); else FAT_Delete(newname); } ret = FAT_Rename(oldname, newname); break; } case FFS_IOCTL_GETSTATS: { char drive[MAX_FILENAME_SIZE]; struct statvfs vfsstat; if (emulationType == FFS_EMU_NONE) goto originalIoctl; preappend_nand_dev_name("/", drive); ret = FAT_VFSStats(drive, &vfsstat); if (ret >= 0) { fsstats *s = (fsstats *) buffer_io; Memset(buffer_io, 0, length_io); s->block_size = vfsstat.f_bsize; s->free_blocks = vfsstat.f_bfree; s->free_inodes = vfsstat.f_ffree; s->used_blocks = vfsstat.f_blocks - vfsstat.f_bfree; os_sync_after_write(buffer_io, length_io); } break; } case FFS_IOCTL_GETFILESTATS: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; if (msg->fd > FFS_FD_MAGIC) goto originalIoctl; struct fstats *s = (struct fstats *) buffer_io; ret = FAT_FileStats(msg->fd, s); break; } case FFS_IOCTL_GETATTR: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; char name[MAX_FILENAME_SIZE]; preappend_nand_dev_name((const char *)buffer_in, name); ret = FAT_Stat(name, NULL); // if it exists, return the same permissions always if (ret >= 0) { fsattr *attributes = (fsattr *) buffer_io; attributes->owner_id = 0; attributes->group_id = 0; attributes->attributes = 0; attributes->ownerperm = ISFS_OPEN_RW; attributes->groupperm = ISFS_OPEN_RW; attributes->otherperm = ISFS_OPEN_RW; os_sync_after_write(buffer_io, length_io); ret = 0; } break; } case FFS_IOCTL_SETATTR: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; char name[MAX_FILENAME_SIZE]; preappend_nand_dev_name((const char *)buffer_in, name); ret = FAT_Stat(name, NULL); // Ignore permission, success if the file exists break; } case FFS_IOCTL_FORMAT: { if (emulationType == FFS_EMU_NONE) goto originalIoctl; ret = 0; break; } case FFS_IOCTL_SETNANDEMULATION: { char tmpdir[MAX_FILENAME_SIZE]; u32 state = buffer_in[0]; if (state) { preappend_nand_dev_name("/tmp", tmpdir); if (FAT_Init() >= 0) { FAT_DeleteDir(tmpdir); } } emulationType = state; break; } originalIoctl: default: ret = FFS_HandleIoctl(msg); break; } return ret; }
s32 FAT_Ioctlv(s32 fd, u32 cmd, ioctlv *vector, u32 inlen, u32 iolen) { s32 ret = IPC_EINVAL; /* Invalidate ache */ InvalidateVector(vector, inlen, iolen); /* Parse command */ switch (cmd) { /** Create directory **/ case IOCTL_FAT_MKDIR: { char *dirpath = (char *)vector[0].data; /* Create directory */ ret = FAT_CreateDir(dirpath); break; } /** Create file **/ case IOCTL_FAT_MKFILE: { char *filepath = (char *)vector[0].data; /* Create file */ ret = FAT_CreateFile(filepath); break; } /** Read directory **/ case IOCTL_FAT_READDIR: { char *dirpath = (char *)vector[0].data; char *outbuf = NULL; u32 *outlen = NULL; u32 buflen = 0; u32 entries = 0; /* Input values */ if (iolen > 1) { entries = *(u32 *)vector[1].data; outbuf = (char *)vector[2].data; outlen = (u32 *)vector[3].data; buflen = vector[2].len; } else outlen = (u32 *)vector[1].data; /* Clear buffer */ if (outbuf) memset(outbuf, 0, buflen); /* Read directory */ ret = FAT_ReadDir(dirpath, outbuf, outlen, entries); break; } /** Read directory (LFN) **/ case IOCTL_FAT_READDIR_LFN: { char *dirpath = (char *)vector[0].data; char *outbuf = NULL; u32 *outlen = NULL; u32 buflen = 0; u32 entries = 0; /* Input values */ if (iolen > 1) { entries = *(u32 *)vector[1].data; outbuf = (char *)vector[2].data; outlen = (u32 *)vector[3].data; buflen = vector[2].len; } else outlen = (u32 *)vector[1].data; /* Clear buffer */ if (outbuf) memset(outbuf, 0, buflen); /* Read directory (LFN) */ ret = FAT_ReadDirLfn(dirpath, outbuf, outlen, entries); break; } /** Delete object **/ case IOCTL_FAT_DELETE: { char *path = (char *)vector[0].data; /* Delete file/directory */ ret = FAT_Delete(path); break; } /** Delete directory **/ case IOCTL_FAT_DELETEDIR: { char *dirpath = (char *)vector[0].data; /* Delete directory */ ret = FAT_DeleteDir(dirpath); break; } /** Rename object **/ case IOCTL_FAT_RENAME: { char *oldname = (char *)vector[0].data; char *newname = (char *)vector[1].data; /* Rename file/directory */ ret = FAT_Rename(oldname, newname); break; } /** Get stats **/ case IOCTL_FAT_STAT: { char *path = (char *)vector[0].data; void *stats = vector[1].data; /* Get stats */ ret = FAT_Stat(path, stats); break; } /** Get filesystem stats **/ case IOCTL_FAT_VFSSTATS: { char *path = (char *)vector[0].data; void *stats = vector[1].data; /* Get filesystem stats */ ret = FAT_GetVfsStats(path, stats); break; } /** Get usage **/ case IOCTL_FAT_GETUSAGE: { char *path = (char *)vector[0].data; u32 *blocks = (u32 *)vector[1].data; u32 *inodes = (u32 *)vector[2].data; u64 size; /* Reset values */ *blocks = 0; *inodes = 0; /* Get usage */ ret = FAT_GetUsage(path, &size, inodes); /* Not a directory */ if (ret == -ENOTDIR) { ret = 0; break; } /* Calculate blocks */ *blocks = (size / 0x4000); break; } /** Mount SD card **/ case IOCTL_FAT_MOUNTSD: { /* Initialize SDIO */ ret = !__io_wiisd.startup(); if (ret) break; /* Mount SD card */ ret = !fatMountSimple("sd", &__io_wiisd); break; } /** Unmount SD card **/ case IOCTL_FAT_UMOUNTSD: { /* Unmount SD card */ fatUnmount("sd"); /* Deinitialize SDIO */ ret = !__io_wiisd.shutdown(); break; } /** Mount USB card **/ case IOCTL_FAT_MOUNTUSB: { /* Initialize USB */ ret = !__io_usbstorage.startup(); if (ret) break; /* Mount USB */ ret = !fatMountSimple("usb", &__io_usbstorage); break; } /** Unmount USB card **/ case IOCTL_FAT_UMOUNTUSB: { /* Unmount USB */ fatUnmount("usb"); /* Deinitialize USB */ ret = !__io_usbstorage.shutdown(); break; } default: break; } /* Flush cache */ FlushVector(vector, inlen, iolen); return ret; }