diff --git a/include/coreinit/filesystem.h b/include/coreinit/filesystem.h index 72949636..d22ca2a8 100644 --- a/include/coreinit/filesystem.h +++ b/include/coreinit/filesystem.h @@ -193,6 +193,16 @@ typedef enum FSMountSourceType { FS_MOUNT_SOURCE_UNK = 1, } FSMountSourceType; +typedef enum FSOpenFileFlags +{ + //! Open file normally + FS_OPEN_FLAG_NONE = (0 << 0), + //! Open (new) unencrypted file. Used for vWii files since it allows for direct access without the Wii U filesystem through it's block address. + FS_OPEN_FLAG_UNENCRYPTED = (1 << 0), + //! Preallocates new file size using given size + FS_OPEN_FLAG_PREALLOC_SIZE = (1 << 1) +} FSOpenFileFlags; + typedef void(*FSAsyncCallback)(FSClient *, FSCmdBlock *, FSStatus, uint32_t); typedef void(*FSStateChangeCallback)(FSClient *, FSVolumeState, void *); @@ -562,6 +572,29 @@ FSCloseFileAsync(FSClient *client, FSErrorFlag errorMask, FSAsyncData *asyncData); +FSStatus +FSOpenFileEx(FSClient *client, + FSCmdBlock *block, + const char *path, + const char *mode, + FSMode createMode, + FSOpenFileFlags openFlag, + uint32_t preallocSize, + FSFileHandle *handle, + FSErrorFlag errorMask); + +FSStatus +FSOpenFileExAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + const char *mode, + FSFileHandle *outHandle, + FSMode createMode, + FSOpenFileFlags openFlag, + uint32_t preallocSize, + FSErrorFlag errorMask, + FSAsyncData *asyncData); + FSStatus FSOpenDir(FSClient *client, FSCmdBlock *block, diff --git a/include/coreinit/filesystem_fsa.h b/include/coreinit/filesystem_fsa.h index bf3c175c..06485655 100644 --- a/include/coreinit/filesystem_fsa.h +++ b/include/coreinit/filesystem_fsa.h @@ -280,15 +280,6 @@ WUT_CHECK_OFFSET(FSAClientAttachAsyncData, 0x04, userContext); WUT_CHECK_OFFSET(FSAClientAttachAsyncData, 0x08, ioMsgQueue); WUT_CHECK_SIZE(FSAClientAttachAsyncData, 0xC); -typedef enum FSOpenFileFlags { - //! Open file normally - FS_OPEN_FLAG_NONE = (0 << 0), - //! Open (new) encrypted file - FS_OPEN_FLAG_ENCRYPTED = (1 << 0), - //! Preallocates new file size using given size - FS_OPEN_FLAG_PREALLOC_SIZE = (1 << 1) -} FSOpenFileFlags; - /** * Block information. */ @@ -392,12 +383,6 @@ FSAChangeMode(FSAClientHandle client, const char *path, FSMode permission); -FSError -FSOpenFileEx(FSAClientHandle client, - const char *path, - const char *mode, - FSAFileHandle *outFileHandle); - FSError FSAOpenFileEx(FSAClientHandle client, const char *path, diff --git a/libraries/wutdevoptab/devoptab_fs.h b/libraries/wutdevoptab/devoptab_fs.h index 67ed4835..05f2169f 100644 --- a/libraries/wutdevoptab/devoptab_fs.h +++ b/libraries/wutdevoptab/devoptab_fs.h @@ -83,4 +83,6 @@ int __wut_fs_utimes(struct _reent *r, const char *filename, const struct t char * __wut_fs_fixpath(struct _reent *r, const char *path); int __wut_fs_translate_error(FSStatus error); time_t __wut_fs_translate_time(FSTime timeValue); -mode_t __wut_fs_translate_mode(FSStat fileStat); +mode_t __wut_fs_translate_stat_mode(FSStat *fsStat); +FSMode __wut_fs_translate_permission_mode(mode_t mode); +void __wut_fs_translate_stat(FSStat *fsStat, struct stat* posStat); diff --git a/libraries/wutdevoptab/devoptab_fs_chmod.c b/libraries/wutdevoptab/devoptab_fs_chmod.c index bc4de68a..a644d2f6 100644 --- a/libraries/wutdevoptab/devoptab_fs_chmod.c +++ b/libraries/wutdevoptab/devoptab_fs_chmod.c @@ -1,13 +1,6 @@ #include #include "devoptab_fs.h" -static inline FSMode -__wut_fs_convert_mode(mode_t mode) -{ - // Convert normal Unix octal permission bits into CafeOS hexadecimal permission bits - return (FSMode) (((mode & S_IRWXU) << 2) | ((mode & S_IRWXG) << 1) | (mode & S_IRWXO)); -} - int __wut_fs_chmod(struct _reent *r, const char *path, @@ -26,7 +19,7 @@ __wut_fs_chmod(struct _reent *r, return -1; } - FSMode translatedMode = __wut_fs_convert_mode(mode); + FSMode translatedMode = __wut_fs_translate_permission_mode(mode); FSInitCmdBlock(&cmd); status = FSChangeMode(__wut_devoptab_fs_client, &cmd, fixedPath, diff --git a/libraries/wutdevoptab/devoptab_fs_dirnext.c b/libraries/wutdevoptab/devoptab_fs_dirnext.c index 83f57b78..e145516d 100644 --- a/libraries/wutdevoptab/devoptab_fs_dirnext.c +++ b/libraries/wutdevoptab/devoptab_fs_dirnext.c @@ -25,19 +25,7 @@ __wut_fs_dirnext(struct _reent *r, return -1; } - // Fill in the stat info - memset(filestat, 0, sizeof(struct stat)); - filestat->st_ino = 0; - - if (dir->entry_data.info.flags & FS_STAT_DIRECTORY) { - filestat->st_mode = S_IFDIR; - } else { - filestat->st_mode = S_IFREG; - } - - filestat->st_uid = dir->entry_data.info.owner; - filestat->st_gid = dir->entry_data.info.group; - filestat->st_size = dir->entry_data.info.size; + __wut_fs_translate_stat(&dir->entry_data.info, filestat); memset(filename, 0, NAME_MAX); strcpy(filename, dir->entry_data.name); diff --git a/libraries/wutdevoptab/devoptab_fs_fstat.c b/libraries/wutdevoptab/devoptab_fs_fstat.c index 95d1eb8a..78fa880c 100644 --- a/libraries/wutdevoptab/devoptab_fs_fstat.c +++ b/libraries/wutdevoptab/devoptab_fs_fstat.c @@ -24,15 +24,7 @@ __wut_fs_fstat(struct _reent *r, return -1; } - memset(st, 0, sizeof(struct stat)); - st->st_size = fsStat.size; - st->st_uid = fsStat.owner; - st->st_gid = fsStat.group; - st->st_nlink = 1; - st->st_mode = __wut_fs_translate_mode(fsStat); - st->st_atime = __wut_fs_translate_time(fsStat.modified); - st->st_ctime = __wut_fs_translate_time(fsStat.created); - st->st_mtime = __wut_fs_translate_time(fsStat.modified); + __wut_fs_translate_stat(&fsStat, st); return 0; } diff --git a/libraries/wutdevoptab/devoptab_fs_open.c b/libraries/wutdevoptab/devoptab_fs_open.c index c6628527..4888d70e 100644 --- a/libraries/wutdevoptab/devoptab_fs_open.c +++ b/libraries/wutdevoptab/devoptab_fs_open.c @@ -1,5 +1,8 @@ #include "devoptab_fs.h" +// Extended "magic" value that allows opening files with FS_OPEN_FLAG_UNENCRYPTED in underlying FSOpenFileEx() call similar to O_DIRECTORY +#define O_UNENCRYPTED 0x4000000 + int __wut_fs_open(struct _reent *r, void *fileStruct, @@ -19,32 +22,34 @@ __wut_fs_open(struct _reent *r, } // Map flags to open modes - if (flags == 0) { + int commonFlagMask = O_CREAT | O_TRUNC | O_APPEND; + if (((flags & O_ACCMODE) == O_RDONLY) && !(flags & commonFlagMask)) { fsMode = "r"; - } else if (flags == 2) { + } else if (((flags & O_ACCMODE) == O_RDWR) && !(flags & commonFlagMask)) { fsMode = "r+"; - } else if (flags == 0x601) { + } else if (((flags & O_ACCMODE) == O_WRONLY) && ((flags & commonFlagMask) == (O_CREAT | O_TRUNC))) { fsMode = "w"; - } else if(flags == 0x602) { + } else if (((flags & O_ACCMODE) == O_RDWR) && ((flags & commonFlagMask) == (O_CREAT | O_TRUNC))) { fsMode = "w+"; - } else if(flags == 0x209) { + } else if (((flags & O_ACCMODE) == O_WRONLY) && ((flags & commonFlagMask) == (O_CREAT | O_APPEND))) { fsMode = "a"; - } else if(flags == 0x20A) { + } else if (((flags & O_ACCMODE) == O_RDWR) && ((flags & commonFlagMask) == (O_CREAT | O_APPEND))) { fsMode = "a+"; } else { r->_errno = EINVAL; return -1; } - char *fixedPath = __wut_fs_fixpath(r,path); + char *fixedPath = __wut_fs_fixpath(r, path); if (!fixedPath) { return -1; } // Open the file FSInitCmdBlock(&cmd); - status = FSOpenFile(__wut_devoptab_fs_client, &cmd, fixedPath, fsMode, &fd, - FS_ERROR_FLAG_ALL); + FSOpenFileFlags openFlags = (mode & O_UNENCRYPTED) ? FS_OPEN_FLAG_UNENCRYPTED : FS_OPEN_FLAG_NONE; + uint32_t preallocSize = 0; + status = FSOpenFileEx(__wut_devoptab_fs_client, &cmd, fixedPath, fsMode, __wut_fs_translate_permission_mode(mode), openFlags, preallocSize, &fd, FS_ERROR_FLAG_ALL); free(fixedPath); if (status < 0) { r->_errno = __wut_fs_translate_error(status); @@ -54,6 +59,14 @@ __wut_fs_open(struct _reent *r, file = (__wut_fs_file_t *)fileStruct; file->fd = fd; file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC)); - FSGetPosFile(__wut_devoptab_fs_client, &cmd, fd, &file->offset, FS_ERROR_FLAG_ALL); + if (flags & O_APPEND) { + status = FSGetPosFile(__wut_devoptab_fs_client, &cmd, fd, &file->offset, FS_ERROR_FLAG_ALL); + if (status < 0) { + FSCloseFile(__wut_devoptab_fs_client, &cmd, fd, FS_ERROR_FLAG_ALL); + r->_errno = __wut_fs_translate_error(status); + return -1; + } + } + return 0; } diff --git a/libraries/wutdevoptab/devoptab_fs_rmdir.c b/libraries/wutdevoptab/devoptab_fs_rmdir.c index 70b89eb6..0c252681 100644 --- a/libraries/wutdevoptab/devoptab_fs_rmdir.c +++ b/libraries/wutdevoptab/devoptab_fs_rmdir.c @@ -21,7 +21,7 @@ __wut_fs_rmdir(struct _reent *r, status = FSRemove(__wut_devoptab_fs_client, &cmd, fixedPath, FS_ERROR_FLAG_ALL); free(fixedPath); if (status < 0) { - r->_errno = __wut_fs_translate_error(status); + r->_errno = status == FS_STATUS_EXISTS ? ENOTEMPTY : __wut_fs_translate_error(status); return -1; } diff --git a/libraries/wutdevoptab/devoptab_fs_stat.c b/libraries/wutdevoptab/devoptab_fs_stat.c index 1ad8c41b..9a189305 100644 --- a/libraries/wutdevoptab/devoptab_fs_stat.c +++ b/libraries/wutdevoptab/devoptab_fs_stat.c @@ -20,7 +20,6 @@ __wut_fs_stat(struct _reent *r, FSInitCmdBlock(&cmd); - // First try open as file status = FSGetStat(__wut_devoptab_fs_client, &cmd, fixedPath, &fsStat, FS_ERROR_FLAG_ALL); if (status < 0) { free(fixedPath); @@ -29,19 +28,7 @@ __wut_fs_stat(struct _reent *r, } free(fixedPath); - memset(st, 0, sizeof(struct stat)); - - st->st_nlink = 1; - st->st_atime = __wut_fs_translate_time(fsStat.modified); - st->st_ctime = __wut_fs_translate_time(fsStat.created); - st->st_mtime = __wut_fs_translate_time(fsStat.modified); - st->st_mode = __wut_fs_translate_mode(fsStat); - - if (!(fsStat.flags & FS_STAT_DIRECTORY)) { - st->st_size = fsStat.size; - st->st_uid = fsStat.owner; - st->st_gid = fsStat.group; - } + __wut_fs_translate_stat(&fsStat, st); return 0; } \ No newline at end of file diff --git a/libraries/wutdevoptab/devoptab_fs_unlink.c b/libraries/wutdevoptab/devoptab_fs_unlink.c index ae0c0da9..d53c6ec4 100644 --- a/libraries/wutdevoptab/devoptab_fs_unlink.c +++ b/libraries/wutdevoptab/devoptab_fs_unlink.c @@ -22,7 +22,7 @@ __wut_fs_unlink(struct _reent *r, status = FSRemove(__wut_devoptab_fs_client, &cmd, fixedPath, FS_ERROR_FLAG_ALL); free(fixedPath); if (status < 0) { - r->_errno = __wut_fs_translate_error(status); + r->_errno = status == FS_STATUS_EXISTS ? EISDIR : __wut_fs_translate_error(status); return -1; } diff --git a/libraries/wutdevoptab/devoptab_fs_utils.c b/libraries/wutdevoptab/devoptab_fs_utils.c index 3ac326f6..bc2b5f91 100644 --- a/libraries/wutdevoptab/devoptab_fs_utils.c +++ b/libraries/wutdevoptab/devoptab_fs_utils.c @@ -17,12 +17,19 @@ __wut_fs_fixpath(struct _reent *r, p = (char *) path; } - if (strlen(p) > PATH_MAX) { + size_t pathLength = strlen(p); + if (pathLength > FS_MAX_PATH) { r->_errno = ENAMETOOLONG; return NULL; } - fixedPath = memalign(0x40, PATH_MAX + 1); + // wii u softlocks on empty strings so give expected error back + if (pathLength == 0) { + r->_errno = ENOENT; + return NULL; + } + + fixedPath = memalign(0x40, FS_MAX_PATH + 1); if (!fixedPath) { r->_errno = ENOMEM; return NULL; @@ -33,35 +40,56 @@ __wut_fs_fixpath(struct _reent *r, return fixedPath; } -mode_t __wut_fs_translate_mode(FSStat fileStat) { +mode_t __wut_fs_translate_stat_mode(FSStat* fsStat) { mode_t retMode = 0; - if ((fileStat.flags & FS_STAT_LINK) == FS_STAT_LINK) { + if ((fsStat->flags & FS_STAT_LINK) == FS_STAT_LINK) { retMode |= S_IFLNK; - } else if ((fileStat.flags & FS_STAT_DIRECTORY) == FS_STAT_DIRECTORY) { + } else if ((fsStat->flags & FS_STAT_DIRECTORY) == FS_STAT_DIRECTORY) { retMode |= S_IFDIR; - } else if ((fileStat.flags & FS_STAT_FILE) == FS_STAT_FILE) { + } else if ((fsStat->flags & FS_STAT_FILE) == FS_STAT_FILE) { retMode |= S_IFREG; - } else if(fileStat.size == 0) { + } else if (fsStat->size == 0) { // Mounted paths like /vol/external01 have no flags set. // If no flag is set and the size is 0, it's a (root) dir retMode |= S_IFDIR; - } else if (fileStat.size > 0) { + } else if (fsStat->size > 0) { // Some regular Wii U files have no type info but will have a size retMode |= S_IFREG; } - mode_t ownerFlags = (fileStat.mode & (FS_MODE_READ_OWNER | FS_MODE_WRITE_OWNER | FS_MODE_EXEC_OWNER)) >> 2; - mode_t groupFlags = (fileStat.mode & (FS_MODE_READ_GROUP | FS_MODE_WRITE_GROUP | FS_MODE_EXEC_GROUP)) >> 1; - mode_t userFlags = (fileStat.mode & (FS_MODE_READ_OTHER | FS_MODE_WRITE_OTHER | FS_MODE_EXEC_OTHER)); + // Convert normal CafeOS hexadecimal permission bits into Unix octal permission bits + mode_t permissionMode = (((fsStat->mode >> 2) & S_IRWXU) | ((fsStat->mode >> 1) & S_IRWXG) | (fsStat->mode & S_IRWXO)); - return retMode | ownerFlags | groupFlags | userFlags; + return retMode | permissionMode; +} + +FSMode __wut_fs_translate_permission_mode(mode_t mode) { + // Convert normal Unix octal permission bits into CafeOS hexadecimal permission bits + return (FSMode) (((mode & S_IRWXU) << 2) | ((mode & S_IRWXG) << 1) | (mode & S_IRWXO)); } time_t __wut_fs_translate_time(FSTime timeValue) { return (timeValue /1000000) + EPOCH_DIFF_SECS(WIIU_FSTIME_EPOCH_YEAR); } +void __wut_fs_translate_stat(FSStat* fsStat, struct stat* posStat) { + memset(posStat, 0, sizeof(struct stat)); + posStat->st_dev = (dev_t)__wut_devoptab_fs_client; + posStat->st_ino = fsStat->entryId; + posStat->st_mode = __wut_fs_translate_stat_mode(fsStat); + posStat->st_nlink = 1; + posStat->st_uid = fsStat->owner; + posStat->st_gid = fsStat->group; + posStat->st_rdev = posStat->st_dev; + posStat->st_size = fsStat->size; + posStat->st_atime = __wut_fs_translate_time(fsStat->modified); + posStat->st_ctime = __wut_fs_translate_time(fsStat->created); + posStat->st_mtime = __wut_fs_translate_time(fsStat->modified); + posStat->st_blksize = 512; + posStat->st_blocks = (posStat->st_size + posStat->st_blksize - 1) / posStat->st_size; +} + int __wut_fs_translate_error(FSStatus error) { switch ((int) error) {