mirror of
https://github.com/devkitPro/wut.git
synced 2026-09-30 13:58:04 -05:00
devoptab: Implement various functions and fixes (#223)
- Improved error codes for unlink and rmdir regarding non-empty directories. - Return ENOENT on empty strings since it softlocks the Wii U. Since the devoptab relies on the cwd it's pretty easy to run into with stuff like recursive path creation for example. - Clean up open_r mode_t->string conversion - Improved FSStat->mode_t conversion - Add FSOpenFileEx and flags
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
#include <sys/stat.h>
|
||||
#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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user