Support time, fix modes and translate errors

Thanks to @koolkdev for figuring out the FSStat flags and structs.
Thanks to WUT for the error codes.
This commit is contained in:
Crementif 2022-03-30 02:37:45 +02:00 committed by Maschell
parent 70e9aee0fe
commit 41a318cac5
7 changed files with 283 additions and 192 deletions

View File

@ -1,4 +1,4 @@
FROM wiiuenv/devkitppc:20211229 FROM wiiuenv/devkitppc:20220507
WORKDIR tmp_build WORKDIR tmp_build
COPY . . COPY . .

View File

@ -1,3 +1,3 @@
FROM wiiuenv/devkitppc:20211229 FROM wiiuenv/devkitppc:20220507
WORKDIR project WORKDIR project

View File

@ -9,6 +9,9 @@ Make you to have [wut](https://github.com/devkitPro/wut/) installed and use the
``` ```
make install make install
``` ```
Note:
You might have to build the latest wut from source if you use the prebuild devkitpro packages until it has a new release.
It won't work with wut versions like wut 1.0.0-beta12 and older.
## Use this lib in Dockerfiles. ## Use this lib in Dockerfiles.
A prebuilt version of this lib can found on dockerhub. To use it for your projects, add this to your Dockerfile. A prebuilt version of this lib can found on dockerhub. To use it for your projects, add this to your Dockerfile.

View File

@ -23,32 +23,17 @@
***************************************************************************/ ***************************************************************************/
#pragma once #pragma once
#include <coreinit/filesystem.h>
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct { // Deprecated: Use FS_STAT_DIRECTORY
uint32_t flag; #ifndef DIR_ENTRY_IS_DIRECTORY
uint32_t permission; #define DIR_ENTRY_IS_DIRECTORY FS_STAT_FILE
uint32_t owner_id; #endif
uint32_t group_id;
uint32_t size; // size in bytes
uint32_t physsize; // physical size on disk in bytes
uint32_t unk[3];
uint32_t id;
uint32_t ctime;
uint32_t mtime;
uint32_t unk2[0x0D];
} fileStat_s;
typedef struct {
fileStat_s stat;
char name[0x100];
} directoryEntry_s;
#define DIR_ENTRY_IS_DIRECTORY 0x80000000
#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) #define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0)
#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) #define FSA_MOUNTFLAGS_GLOBAL (1 << 1)
@ -88,7 +73,7 @@ int IOSUHAX_FSA_MakeDir(int fsaFd, const char *path, uint32_t flags);
int IOSUHAX_FSA_OpenDir(int fsaFd, const char *path, int *outHandle); int IOSUHAX_FSA_OpenDir(int fsaFd, const char *path, int *outHandle);
int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s *out_data); int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, FSDirectoryEntry *out_data);
int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle); int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle);
@ -102,13 +87,13 @@ int IOSUHAX_FSA_ReadFile(int fsaFd, void *data, uint32_t size, uint32_t cnt, int
int IOSUHAX_FSA_WriteFile(int fsaFd, const void *data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); int IOSUHAX_FSA_WriteFile(int fsaFd, const void *data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags);
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s *out_data); int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data);
int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle); int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle);
int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position); int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position);
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s *out_data); int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data);
int IOSUHAX_FSA_Remove(int fsaFd, const char *path); int IOSUHAX_FSA_Remove(int fsaFd, const char *path);

View File

@ -465,7 +465,7 @@ int IOSUHAX_FSA_OpenDir(int fsaFd, const char *path, int *outHandle) {
return result_vec[0]; return result_vec[0];
} }
int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s *out_data) { int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, FSDirectoryEntry *out_data) {
if (iosuhaxHandle < 0) if (iosuhaxHandle < 0)
return iosuhaxHandle; return iosuhaxHandle;
@ -480,7 +480,7 @@ int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s *out_data) {
io_buf[0] = fsaFd; io_buf[0] = fsaFd;
io_buf[1] = handle; io_buf[1] = handle;
int result_vec_size = 4 + sizeof(directoryEntry_s); int result_vec_size = 4 + sizeof(FSDirectoryEntry);
uint8_t *result_vec = (uint8_t *) memalign(0x20, result_vec_size); uint8_t *result_vec = (uint8_t *) memalign(0x20, result_vec_size);
if (!result_vec) { if (!result_vec) {
free(io_buf); free(io_buf);
@ -495,7 +495,7 @@ int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s *out_data) {
} }
int result = *(int *) result_vec; int result = *(int *) result_vec;
memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s)); memcpy(out_data, result_vec + 4, sizeof(FSDirectoryEntry));
free(io_buf); free(io_buf);
free(result_vec); free(result_vec);
return result; return result;
@ -688,7 +688,7 @@ int IOSUHAX_FSA_WriteFile(int fsaFd, const void *data, uint32_t size, uint32_t c
return result; return result;
} }
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s *out_data) { int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data) {
if (iosuhaxHandle < 0) if (iosuhaxHandle < 0)
return iosuhaxHandle; return iosuhaxHandle;
@ -703,7 +703,7 @@ int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s *out_data) {
io_buf[0] = fsaFd; io_buf[0] = fsaFd;
io_buf[1] = fileHandle; io_buf[1] = fileHandle;
int out_buf_size = 4 + sizeof(fileStat_s); int out_buf_size = 4 + sizeof(FSStat);
uint32_t *out_buffer = (uint32_t *) memalign(0x20, out_buf_size); uint32_t *out_buffer = (uint32_t *) memalign(0x20, out_buf_size);
if (!out_buffer) { if (!out_buffer) {
free(io_buf); free(io_buf);
@ -718,7 +718,7 @@ int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s *out_data) {
} }
int result = out_buffer[0]; int result = out_buffer[0];
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); memcpy(out_data, out_buffer + 1, sizeof(FSStat));
free(io_buf); free(io_buf);
free(out_buffer); free(out_buffer);
@ -780,7 +780,7 @@ int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) {
return result; return result;
} }
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s *out_data) { int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data) {
if (iosuhaxHandle < 0) if (iosuhaxHandle < 0)
return iosuhaxHandle; return iosuhaxHandle;
@ -796,7 +796,7 @@ int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s *out_data) {
io_buf[1] = sizeof(uint32_t) * input_cnt; io_buf[1] = sizeof(uint32_t) * input_cnt;
strcpy(((char *) io_buf) + io_buf[1], path); strcpy(((char *) io_buf) + io_buf[1], path);
int out_buf_size = 4 + sizeof(fileStat_s); int out_buf_size = 4 + sizeof(FSStat);
uint32_t *out_buffer = (uint32_t *) memalign(0x20, out_buf_size); uint32_t *out_buffer = (uint32_t *) memalign(0x20, out_buf_size);
if (!out_buffer) { if (!out_buffer) {
free(io_buf); free(io_buf);
@ -811,7 +811,7 @@ int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s *out_data) {
} }
int result = out_buffer[0]; int result = out_buffer[0];
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); memcpy(out_data, out_buffer + 1, sizeof(FSStat));
free(io_buf); free(io_buf);
free(out_buffer); free(out_buffer);

View File

@ -26,6 +26,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <malloc.h> #include <malloc.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -44,9 +45,9 @@ typedef struct _fs_dev_file_state_t {
fs_dev_private_t *dev; fs_dev_private_t *dev;
int fd; /* File descriptor */ int fd; /* File descriptor */
int flags; /* Opening flags */ int flags; /* Opening flags */
int read; /* True if allowed to read from file */ bool read; /* True if allowed to read from file */
int write; /* True if allowed to write to file */ bool write; /* True if allowed to write to file */
int append; /* True if allowed to append to file */ bool append; /* True if allowed to append to file */
uint32_t pos; /* Current position within the file (in bytes) */ uint32_t pos; /* Current position within the file (in bytes) */
uint32_t len; /* Total length of the file (in bytes) */ uint32_t len; /* Total length of the file (in bytes) */
struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */
@ -104,6 +105,85 @@ static char *fs_dev_real_path(const char *path, fs_dev_private_t *dev) {
return new_name; return new_name;
} }
static int fs_dev_translate_error(FSStatus error) {
switch ((int) error) {
case FS_STATUS_END:
return ENOENT;
case FS_STATUS_CANCELLED:
return ECANCELED;
case FS_STATUS_EXISTS:
return EEXIST;
case FS_STATUS_MEDIA_ERROR:
return EIO;
case FS_STATUS_NOT_FOUND:
return ENOENT;
case FS_STATUS_PERMISSION_ERROR:
return EPERM;
case FS_STATUS_STORAGE_FULL:
return ENOSPC;
case FS_STATUS_FILE_TOO_BIG:
return EFBIG;
case FS_STATUS_NOT_DIR:
return ENOTDIR;
case FS_STATUS_NOT_FILE:
return EISDIR;
case FS_STATUS_MAX:
return ENFILE;
case FS_STATUS_ACCESS_ERROR:
return EACCES;
case FS_STATUS_JOURNAL_FULL:
return ENOSPC;
case FS_STATUS_UNSUPPORTED_CMD:
return ENOTSUP;
case FS_STATUS_MEDIA_NOT_READY:
return EOWNERDEAD;
case FS_STATUS_ALREADY_OPEN:
case FS_STATUS_CORRUPTED:
case FS_STATUS_FATAL_ERROR:
return EIO;
}
return (int) error;
}
static mode_t fs_dev_translate_stat_mode(FSStat fileStat, bool isRootDirectory) {
// Convert file types
mode_t typeMode = 0;
if (isRootDirectory) {
typeMode |= S_IFDIR;
} else if ((fileStat.flags & FS_STAT_LINK) == FS_STAT_LINK) {
typeMode |= S_IFLNK;
} else if ((fileStat.flags & FS_STAT_DIRECTORY) == FS_STAT_DIRECTORY) {
typeMode |= S_IFDIR;
} else if ((fileStat.flags & FS_STAT_FILE) == FS_STAT_FILE) {
typeMode |= S_IFREG;
}
// Convert normal CafeOS hexadecimal permission bits into Unix octal permission bits
mode_t permissionMode = (((fileStat.mode >> 2) & S_IRWXU) | ((fileStat.mode >> 1) & S_IRWXG) | (fileStat.mode & S_IRWXO));
return typeMode | permissionMode;
}
static FSMode fs_dev_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));
}
static time_t fs_dev_translate_time(FSTime timeValue) {
OSCalendarTime fileTime;
FSTimeToCalendarTime(timeValue, &fileTime);
struct tm posixTime = {0};
posixTime.tm_year = fileTime.tm_year - 1900;
posixTime.tm_mon = fileTime.tm_mon;
posixTime.tm_mday = fileTime.tm_mday;
posixTime.tm_hour = fileTime.tm_hour;
posixTime.tm_min = fileTime.tm_min;
posixTime.tm_sec = fileTime.tm_sec;
posixTime.tm_yday = fileTime.tm_yday;
posixTime.tm_wday = fileTime.tm_wday;
return mktime(&posixTime);
}
static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
fs_dev_private_t *dev = fs_dev_get_device_data(path); fs_dev_private_t *dev = fs_dev_get_device_data(path);
if (!dev) { if (!dev) {
@ -121,34 +201,34 @@ static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, i
// Map flags to open modes // Map flags to open modes
if (flags == 0) { if (flags == 0) {
file->read = 1; file->read = true;
file->write = 0; file->write = false;
file->append = 0; file->append = false;
fsMode = "r"; fsMode = "r";
} else if (flags == 2) { } else if (flags == 2) {
file->read = 1; file->read = true;
file->write = 1; file->write = true;
file->append = 0; file->append = false;
fsMode = "r+"; fsMode = "r+";
} else if (flags == 0x601) { } else if (flags == 0x601) {
file->read = 0; file->read = false;
file->write = 1; file->write = true;
file->append = 0; file->append = false;
fsMode = "w"; fsMode = "w";
} else if (flags == 0x602) { } else if (flags == 0x602) {
file->read = 1; file->read = true;
file->write = 1; file->write = true;
file->append = 0; file->append = false;
fsMode = "w+"; fsMode = "w+";
} else if (flags == 0x209) { } else if (flags == 0x209) {
file->read = 0; file->read = false;
file->write = 1; file->write = true;
file->append = 1; file->append = true;
fsMode = "a"; fsMode = "a";
} else if (flags == 0x20A) { } else if (flags == 0x20A) {
file->read = 1; file->read = true;
file->write = 1; file->write = true;
file->append = 1; file->append = true;
fsMode = "a+"; fsMode = "a+";
} else { } else {
r->_errno = EINVAL; r->_errno = EINVAL;
@ -172,11 +252,11 @@ static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, i
free(real_path); free(real_path);
if (result == 0) { if (result == 0) {
fileStat_s stats; FSStat stats;
result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats); result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats);
if (result != 0) { if (result != 0) {
IOSUHAX_FSA_CloseFile(dev->fsaFd, fd); IOSUHAX_FSA_CloseFile(dev->fsaFd, fd);
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
return -1; return -1;
} }
@ -187,7 +267,7 @@ static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, i
return (int) file; return (int) file;
} }
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
return -1; return -1;
} }
@ -207,7 +287,7 @@ static int fs_dev_close_r(struct _reent *r, void *fd) {
OSUnlockMutex(file->dev->pMutex); OSUnlockMutex(file->dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
return 0; return 0;
@ -269,7 +349,7 @@ static ssize_t fs_dev_write_r(struct _reent *r, void *fd, const char *ptr, size_
int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0); int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
break; break;
} else if (result == 0) { } else if (result == 0) {
if (write_size > 0) if (write_size > 0)
@ -306,7 +386,7 @@ static ssize_t fs_dev_read_r(struct _reent *r, void *fd, char *ptr, size_t len)
int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0); int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
done = 0; done = 0;
break; break;
} else if (result == 0) { } else if (result == 0) {
@ -335,55 +415,32 @@ static int fs_dev_fstat_r(struct _reent *r, void *fd, struct stat *st) {
// Zero out the stat buffer // Zero out the stat buffer
memset(st, 0, sizeof(struct stat)); memset(st, 0, sizeof(struct stat));
fileStat_s stats; FSStat stats;
int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int) fd, &stats); int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int) fd, &stats);
if (result != 0) { if (result != 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(file->dev->pMutex); OSUnlockMutex(file->dev->pMutex);
return -1; return -1;
} }
st->st_mode = S_IFREG; // Convert fields to posix stat
st->st_size = stats.size; st->st_dev = (dev_t) file->dev;
st->st_blocks = (stats.size + 511) >> 9; st->st_ino = stats.entryId;
st->st_nlink = 1; st->st_mode = fs_dev_translate_stat_mode(stats, false);
st->st_nlink = 1;
// Fill in the generic entry stats st->st_uid = stats.owner;
st->st_dev = stats.id; st->st_gid = stats.group;
st->st_uid = stats.owner_id; st->st_rdev = st->st_dev;
st->st_gid = stats.group_id; st->st_size = stats.size;
st->st_ino = stats.id; st->st_blksize = 512;
st->st_atime = stats.mtime; st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
st->st_ctime = stats.ctime; st->st_atime = fs_dev_translate_time(stats.modified);
st->st_mtime = stats.mtime; st->st_ctime = fs_dev_translate_time(stats.created);
st->st_mtime = fs_dev_translate_time(stats.modified);
OSUnlockMutex(file->dev->pMutex); OSUnlockMutex(file->dev->pMutex);
return 0; return 0;
} }
static int fs_dev_ftruncate_r(struct _reent *r, void *fd, off_t len) {
fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd;
if (!file->dev) {
r->_errno = ENODEV;
return -1;
}
r->_errno = ENOTSUP;
// TODO
return -1;
}
static int fs_dev_fsync_r(struct _reent *r, void *fd) {
fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd;
if (!file->dev) {
r->_errno = ENODEV;
return -1;
}
r->_errno = ENOTSUP;
// TODO
return -1;
}
static int fs_dev_stat_r(struct _reent *r, const char *path, struct stat *st) { static int fs_dev_stat_r(struct _reent *r, const char *path, struct stat *st) {
fs_dev_private_t *dev = fs_dev_get_device_data(path); fs_dev_private_t *dev = fs_dev_get_device_data(path);
if (!dev) { if (!dev) {
@ -403,34 +460,78 @@ static int fs_dev_stat_r(struct _reent *r, const char *path, struct stat *st) {
return -1; return -1;
} }
fileStat_s stats; FSStat stats;
int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats);
free(real_path); free(real_path);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
return -1; return -1;
} }
// mark root also as directory // Convert fields to posix stat
st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path))) ? S_IFDIR : S_IFREG; st->st_dev = (dev_t) dev;
st->st_nlink = 1; st->st_ino = stats.entryId;
st->st_size = stats.size; st->st_mode = fs_dev_translate_stat_mode(stats, (strlen(dev->mount_path) + 1 == strlen(real_path)));
st->st_blocks = (stats.size + 511) >> 9; st->st_nlink = 1;
// Fill in the generic entry stats st->st_uid = stats.owner;
st->st_dev = stats.id; st->st_gid = stats.group;
st->st_uid = stats.owner_id; st->st_rdev = st->st_dev;
st->st_gid = stats.group_id; st->st_size = stats.size;
st->st_ino = stats.id; st->st_blksize = 512;
st->st_atime = stats.mtime; st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
st->st_ctime = stats.ctime; st->st_atime = fs_dev_translate_time(stats.modified);
st->st_mtime = stats.mtime; st->st_ctime = fs_dev_translate_time(stats.created);
st->st_mtime = fs_dev_translate_time(stats.modified);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
return 0;
}
static int fs_dev_lstat_r(struct _reent *r, const char *path, struct stat *st) {
fs_dev_private_t *dev = fs_dev_get_device_data(path);
if (!dev) {
r->_errno = ENODEV;
return -1;
}
OSLockMutex(dev->pMutex);
// Zero out the stat buffer
memset(st, 0, sizeof(struct stat));
char *real_path = fs_dev_real_path(path, dev);
if (!real_path) {
r->_errno = ENOMEM;
OSUnlockMutex(dev->pMutex);
return -1;
}
FSStat stats;
int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats);
free(real_path);
if (result < 0) {
r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dev->pMutex);
return -1;
}
// Convert fields to posix stat
st->st_dev = (dev_t) dev;
st->st_ino = stats.entryId;
st->st_mode = fs_dev_translate_stat_mode(stats, (strlen(dev->mount_path) + 1 == strlen(real_path)));
st->st_nlink = 1;
st->st_uid = stats.owner;
st->st_gid = stats.group;
st->st_rdev = st->st_dev;
st->st_size = stats.size;
st->st_blksize = 512;
st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
st->st_atime = fs_dev_translate_time(stats.modified);
st->st_ctime = fs_dev_translate_time(stats.created);
st->st_mtime = fs_dev_translate_time(stats.modified);
OSUnlockMutex(dev->pMutex);
return 0; return 0;
} }
@ -462,7 +563,7 @@ static int fs_dev_unlink_r(struct _reent *r, const char *name) {
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
@ -492,7 +593,7 @@ static int fs_dev_chdir_r(struct _reent *r, const char *name) {
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
@ -523,7 +624,7 @@ static int fs_dev_rename_r(struct _reent *r, const char *oldName, const char *ne
} }
//! TODO //! TODO
int result = -ENOTSUP; int result = FS_ERROR_UNSUPPORTED_COMMAND;
free(real_oldpath); free(real_oldpath);
free(real_newpath); free(real_newpath);
@ -531,7 +632,7 @@ static int fs_dev_rename_r(struct _reent *r, const char *oldName, const char *ne
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
@ -554,21 +655,20 @@ static int fs_dev_mkdir_r(struct _reent *r, const char *path, int mode) {
return -1; return -1;
} }
int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode); int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, fs_dev_translate_permission_mode(mode));
free(real_path); free(real_path);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
return 0; return 0;
} }
static int fs_dev_chmod_r(struct _reent *r, const char *path, int mode) { static int fs_dev_chmod_r(struct _reent *r, const char *path, mode_t mode) {
fs_dev_private_t *dev = fs_dev_get_device_data(path); fs_dev_private_t *dev = fs_dev_get_device_data(path);
if (!dev) { if (!dev) {
r->_errno = ENODEV; r->_errno = ENODEV;
@ -584,14 +684,13 @@ static int fs_dev_chmod_r(struct _reent *r, const char *path, int mode) {
return -1; return -1;
} }
int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, mode); int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, fs_dev_translate_permission_mode(mode));
free(real_path); free(real_path);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
@ -624,7 +723,7 @@ static int fs_dev_statvfs_r(struct _reent *r, const char *path, struct statvfs *
free(real_path); free(real_path);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
return -1; return -1;
} }
@ -688,7 +787,7 @@ static DIR_ITER *fs_dev_diropen_r(struct _reent *r, DIR_ITER *dirState, const ch
OSUnlockMutex(dev->pMutex); OSUnlockMutex(dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return NULL; return NULL;
} }
@ -712,7 +811,7 @@ static int fs_dev_dirclose_r(struct _reent *r, DIR_ITER *dirState) {
OSUnlockMutex(dirIter->dev->pMutex); OSUnlockMutex(dirIter->dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
return 0; return 0;
@ -732,7 +831,7 @@ static int fs_dev_dirreset_r(struct _reent *r, DIR_ITER *dirState) {
OSUnlockMutex(dirIter->dev->pMutex); OSUnlockMutex(dirIter->dev->pMutex);
if (result < 0) { if (result < 0) {
r->_errno = result; r->_errno = fs_dev_translate_error(result);
return -1; return -1;
} }
return 0; return 0;
@ -747,12 +846,12 @@ static int fs_dev_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename
OSLockMutex(dirIter->dev->pMutex); OSLockMutex(dirIter->dev->pMutex);
directoryEntry_s *dir_entry = malloc(sizeof(directoryEntry_s)); FSDirectoryEntry *dir_entry = malloc(sizeof(FSDirectoryEntry));
int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry); int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry);
if (result < 0) { if (result < 0) {
free(dir_entry); free(dir_entry);
r->_errno = result; r->_errno = fs_dev_translate_error(result);
OSUnlockMutex(dirIter->dev->pMutex); OSUnlockMutex(dirIter->dev->pMutex);
return -1; return -1;
} }
@ -762,17 +861,21 @@ static int fs_dev_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename
if (st) { if (st) {
memset(st, 0, sizeof(struct stat)); memset(st, 0, sizeof(struct stat));
st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG;
st->st_nlink = 1; // Convert fields to posix stat
st->st_size = dir_entry->stat.size; st->st_dev = (dev_t) dirIter->dev;
st->st_blocks = (dir_entry->stat.size + 511) >> 9; st->st_ino = dir_entry->info.entryId;
st->st_dev = dir_entry->stat.id; st->st_mode = fs_dev_translate_stat_mode(dir_entry->info, false);
st->st_uid = dir_entry->stat.owner_id; st->st_nlink = 1;
st->st_gid = dir_entry->stat.group_id; st->st_uid = dir_entry->info.owner;
st->st_ino = dir_entry->stat.id; st->st_gid = dir_entry->info.group;
st->st_atime = dir_entry->stat.mtime; st->st_rdev = st->st_dev;
st->st_ctime = dir_entry->stat.ctime; st->st_size = dir_entry->info.size;
st->st_mtime = dir_entry->stat.mtime; st->st_blksize = 512;
st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
st->st_atime = fs_dev_translate_time(dir_entry->info.modified);
st->st_ctime = fs_dev_translate_time(dir_entry->info.created);
st->st_mtime = fs_dev_translate_time(dir_entry->info.modified);
} }
free(dir_entry); free(dir_entry);
@ -780,33 +883,35 @@ static int fs_dev_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename
return 0; return 0;
} }
// NTFS device driver devoptab
static const devoptab_t devops_fs = { static const devoptab_t devops_fs = {
NULL, /* Device name */ .name = NULL, /* Device name */
sizeof(fs_dev_file_state_t), .structSize = sizeof(fs_dev_file_state_t),
fs_dev_open_r, .open_r = fs_dev_open_r,
fs_dev_close_r, .close_r = fs_dev_close_r,
fs_dev_write_r, .write_r = fs_dev_write_r,
fs_dev_read_r, .read_r = fs_dev_read_r,
fs_dev_seek_r, .seek_r = fs_dev_seek_r,
fs_dev_fstat_r, .fstat_r = fs_dev_fstat_r,
fs_dev_stat_r, .stat_r = fs_dev_stat_r,
fs_dev_link_r, .link_r = fs_dev_link_r,
fs_dev_unlink_r, .unlink_r = fs_dev_unlink_r,
fs_dev_chdir_r, .chdir_r = fs_dev_chdir_r,
fs_dev_rename_r, .rename_r = fs_dev_rename_r,
fs_dev_mkdir_r, .mkdir_r = fs_dev_mkdir_r,
sizeof(fs_dev_dir_entry_t), .dirStateSize = sizeof(fs_dev_dir_entry_t),
fs_dev_diropen_r, .diropen_r = fs_dev_diropen_r,
fs_dev_dirreset_r, .dirreset_r = fs_dev_dirreset_r,
fs_dev_dirnext_r, .dirnext_r = fs_dev_dirnext_r,
fs_dev_dirclose_r, .dirclose_r = fs_dev_dirclose_r,
fs_dev_statvfs_r, .statvfs_r = fs_dev_statvfs_r,
fs_dev_ftruncate_r, .ftruncate_r = NULL, // fs_dev_ftruncate_r,
fs_dev_fsync_r, .fsync_r = NULL, // fs_dev_fsync_r,
fs_dev_chmod_r, .deviceData = NULL,
NULL, /* fs_dev_fchmod_r */ .chmod_r = fs_dev_chmod_r,
NULL /* Device data */ .fchmod_r = NULL, // fs_dev_fchmod_r,
.rmdir_r = NULL, // fs_dev_rmdir_r,
.lstat_r = fs_dev_lstat_r,
.utimes_r = NULL,
}; };
static int fs_dev_add_device(const char *name, const char *mount_path, int fsaFd, int isMounted) { static int fs_dev_add_device(const char *name, const char *mount_path, int fsaFd, int isMounted) {

View File

@ -143,16 +143,15 @@ static bool IOSUHAX_sdio_writeSectors(uint32_t sector, uint32_t numSectors, cons
return true; return true;
} }
const DISC_INTERFACE IOSUHAX_sdio_disc_interface = const DISC_INTERFACE IOSUHAX_sdio_disc_interface = {
{ DEVICE_TYPE_WII_U_SD,
DEVICE_TYPE_WII_U_SD, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD, IOSUHAX_sdio_startup,
IOSUHAX_sdio_startup, IOSUHAX_sdio_isInserted,
IOSUHAX_sdio_isInserted, IOSUHAX_sdio_readSectors,
IOSUHAX_sdio_readSectors, IOSUHAX_sdio_writeSectors,
IOSUHAX_sdio_writeSectors, IOSUHAX_sdio_clearStatus,
IOSUHAX_sdio_clearStatus, IOSUHAX_sdio_shutdown};
IOSUHAX_sdio_shutdown};
static bool IOSUHAX_usb_startup(void) { static bool IOSUHAX_usb_startup(void) {
if (!IOSUHAX_disc_io_fsa_open(FSA_REF_USB)) if (!IOSUHAX_disc_io_fsa_open(FSA_REF_USB))
@ -213,13 +212,12 @@ static bool IOSUHAX_usb_writeSectors(uint32_t sector, uint32_t numSectors, const
return true; return true;
} }
const DISC_INTERFACE IOSUHAX_usb_disc_interface = const DISC_INTERFACE IOSUHAX_usb_disc_interface = {
{ DEVICE_TYPE_WII_U_USB,
DEVICE_TYPE_WII_U_USB, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB, IOSUHAX_usb_startup,
IOSUHAX_usb_startup, IOSUHAX_usb_isInserted,
IOSUHAX_usb_isInserted, IOSUHAX_usb_readSectors,
IOSUHAX_usb_readSectors, IOSUHAX_usb_writeSectors,
IOSUHAX_usb_writeSectors, IOSUHAX_usb_clearStatus,
IOSUHAX_usb_clearStatus, IOSUHAX_usb_shutdown};
IOSUHAX_usb_shutdown};