diff --git a/nx/include/switch/devices/fs_dev.h b/nx/include/switch/devices/fs_dev.h index 8ae40b9d..e6b6edcd 100644 --- a/nx/include/switch/devices/fs_dev.h +++ b/nx/include/switch/devices/fs_dev.h @@ -6,20 +6,27 @@ //NOTE: This is currently not usable. +#define FSDEV_DIRITER_MAGIC 0x66736476 /* "fsdv" */ + +/*! Open directory struct */ +typedef struct +{ + u32 magic; /*! "fsdv" */ + FsDir fd; + ssize_t index; /*! Current entry index */ + size_t size; /*! Current batch size */ + FsDirectoryEntry entry_data[32]; /*! Temporary storage for reading entries */ +} fsdev_dir_t; + /// Initializes the FS driver. Result fsdevInit(void); -/// Enable/disable copy in fsdev_write. This is disabled by default. -/// If it is disabled, you will be unable to write from the following memory-regions(http://switchbrew.org/index.php?title=SVC#MemoryState): -/// MemoryType_Io -/// MemoryType_Normal -/// MemoryType_*SharedMemory -/// MemoryType_ThreadLocal -/// MemoryType_IpcBuffer3 -/// MemoryType_KernelStack (This is not mapped in userland anyway) -/// This same restriction applies with reading into the above memory, a file-read version of fsdevWriteSafe() is not available. -void fsdevWriteSafe(bool enable); - /// Exits the FS driver. Result fsdevExit(void); +/// Mounts the input fs with the specified device name. fsdev will handle closing the fs when required, including when fsdevMountDevice() fails. +int fsdevMountDevice(const char *name, FsFileSystem fs); + +/// Unmounts the specified device. +int fsdevUnmountDevice(const char *name); + diff --git a/nx/source/devices/fs_dev.c b/nx/source/devices/fs_dev.c index d9dd7e4d..3de70048 100644 --- a/nx/source/devices/fs_dev.c +++ b/nx/source/devices/fs_dev.c @@ -25,6 +25,7 @@ static int fsdev_close(struct _reent *r, void *fd); static ssize_t fsdev_write(struct _reent *r, void *fd, const char *ptr, size_t len); static ssize_t fsdev_write_safe(struct _reent *r, void *fd, const char *ptr, size_t len); static ssize_t fsdev_read(struct _reent *r, void *fd, char *ptr, size_t len); +static ssize_t fsdev_read_safe(struct _reent *r, void *fd, char *ptr, size_t len); static off_t fsdev_seek(struct _reent *r, void *fd, off_t pos, int dir); static int fsdev_fstat(struct _reent *r, void *fd, struct stat *st); static int fsdev_stat(struct _reent *r, const char *file, struct stat *st); @@ -54,18 +55,6 @@ typedef struct u64 offset; /*! Current file offset */ } fsdev_file_t; -#define FSDEV_DIRITER_MAGIC 0x66736476 /* "fsdv" */ - -/*! Open directory struct */ -typedef struct -{ - u32 magic; /*! "fsdv" */ - FsDir fd; - ssize_t index; /*! Current entry index */ - size_t size; /*! Current batch size */ - FsDirectoryEntry entry_data[32]; /*! Temporary storage for reading entries */ -} fsdev_dir_t; - /*! fsdev devoptab */ static devoptab_t fsdev_devoptab = @@ -284,20 +273,7 @@ extern char** __system_argv; static bool fsdevInitialised = false; -static void fsdevUpdateDevices(void) -{ - u32 i; - u32 total = sizeof(fsdev_fsdevices) / sizeof(fsdev_fsdevice); - - for(i=0; ifd, file->offset, ptr, len); + if(rc == 0xD401) + return fsdev_write_safe(r, fd, ptr, len); if(R_FAILED(rc)) { r->_errno = fsdev_translate_error(rc); @@ -690,26 +659,8 @@ fsdev_write_safe(struct _reent *r, /* get pointer to our data */ fsdev_file_t *file = (fsdev_file_t*)fd; - /* check that the file was opened with write access */ - if((file->flags & O_ACCMODE) == O_RDONLY) - { - r->_errno = EBADF; - return -1; - } - - if(file->flags & O_APPEND) - { - /* append means write from the end of the file */ - rc = fsFileGetSize(&file->fd, &file->offset); - if(R_FAILED(rc)) - { - r->_errno = fsdev_translate_error(rc); - return -1; - } - } - - /* Copy to internal buffer and write in chunks. - * You cannot write from read-only memory. + /* Copy to internal buffer and transfer in chunks. + * You cannot use FS read/write with certain memory. */ static __thread char tmp_buffer[8192]; while(len > 0) @@ -778,6 +729,8 @@ fsdev_read(struct _reent *r, /* read the data */ rc = fsFileRead(&file->fd, file->offset, ptr, len, &bytes); + if(rc == 0xD401) + return fsdev_read_safe(r, fd, ptr, len); if(R_SUCCEEDED(rc)) { /* update current file offset */ @@ -789,6 +742,66 @@ fsdev_read(struct _reent *r, return -1; } +/*! Read from an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in,out] fd Pointer to fsdev_file_t + * @param[out] ptr Pointer to buffer to read into + * @param[in] len Length of data to read + * + * @returns number of bytes written + * @returns -1 for error + */ +static ssize_t +fsdev_read_safe(struct _reent *r, + void *fd, + char *ptr, + size_t len) +{ + Result rc; + size_t bytesRead = 0, bytes = 0; + + /* get pointer to our data */ + fsdev_file_t *file = (fsdev_file_t*)fd; + + /* Transfer in chunks with internal buffer. + * You cannot use FS read/write with certain memory. + */ + static __thread char tmp_buffer[8192]; + while(len > 0) + { + size_t toRead = len; + if(toRead > sizeof(tmp_buffer)) + toRead = sizeof(tmp_buffer); + + /* read the data */ + rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, &bytes); + + if(bytes > toRead) + bytes = toRead; + + /* copy from internal buffer */ + memcpy(ptr, tmp_buffer, bytes); + + if(R_FAILED(rc)) + { + /* return partial transfer */ + if(bytesRead > 0) + return bytesRead; + + r->_errno = fsdev_translate_error(rc); + return -1; + } + + file->offset += bytes; + bytesRead += bytes; + ptr += bytes; + len -= bytes; + } + + return bytesRead; +} + /*! Update an open file's current offset * * @param[in,out] r newlib reentrancy struct