From c5674b312621ce985babf31da89119841d046aa8 Mon Sep 17 00:00:00 2001 From: Michael Theall Date: Tue, 12 Jan 2016 16:22:30 -0600 Subject: [PATCH] Add sdmcWriteSafe --- libctru/include/3ds/sdmc.h | 3 ++ libctru/source/sdmc_dev.c | 78 +++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/libctru/include/3ds/sdmc.h b/libctru/include/3ds/sdmc.h index d86acde..2b17e53 100644 --- a/libctru/include/3ds/sdmc.h +++ b/libctru/include/3ds/sdmc.h @@ -9,5 +9,8 @@ /// Initializes the SDMC driver. Result sdmcInit(void); +/// Enable/disable copy in sdmc_write +void sdmcWriteSafe(bool enable); + /// Exits the SDMC driver. Result sdmcExit(void); diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index 5836270..45de57f 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -27,6 +27,7 @@ static int sdmc_translate_error(Result error); static int sdmc_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); static int sdmc_close(struct _reent *r, int fd); static ssize_t sdmc_write(struct _reent *r, int fd, const char *ptr, size_t len); +static ssize_t sdmc_write_safe(struct _reent *r, int fd, const char *ptr, size_t len); static ssize_t sdmc_read(struct _reent *r, int fd, char *ptr, size_t len); static off_t sdmc_seek(struct _reent *r, int fd, off_t pos, int dir); static int sdmc_fstat(struct _reent *r, int fd, struct stat *st); @@ -72,7 +73,7 @@ sdmc_devoptab = .structSize = sizeof(sdmc_file_t), .open_r = sdmc_open, .close_r = sdmc_close, - .write_r = sdmc_write, + .write_r = sdmc_write_safe, .read_r = sdmc_read, .seek_r = sdmc_seek, .fstat_r = sdmc_fstat, @@ -280,6 +281,21 @@ Result sdmcInit(void) return rc; } +/*! Enable/disable safe sdmc_write + * + * Safe sdmc_write is enabled by default. If it is disabled, you will be + * unable to write from read-only buffers. + * + * @param[in] enable Whether to enable + */ +void sdmcWriteSafe(bool enable) +{ + if(enable) + sdmc_devoptab.write_r = sdmc_write_safe; + else + sdmc_devoptab.write_r = sdmc_write; +} + /*! Clean up SDMC device */ Result sdmcExit(void) { @@ -442,6 +458,64 @@ sdmc_write(struct _reent *r, int fd, const char *ptr, size_t len) +{ + Result rc; + u32 bytes; + u32 sync = 0; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + /* check that the file was opened with write access */ + if((file->flags & O_ACCMODE) == O_RDONLY) + { + r->_errno = EBADF; + return -1; + } + + /* check if this is synchronous or not */ + if(file->flags & O_SYNC) + sync = FS_WRITE_FLUSH | FS_WRITE_UPDATE_TIME; + + if(file->flags & O_APPEND) + { + /* append means write from the end of the file */ + rc = FSFILE_GetSize(file->fd, &file->offset); + if(R_FAILED(rc)) + { + r->_errno = sdmc_translate_error(rc); + return -1; + } + } + + rc = FSFILE_Write(file->fd, &bytes, file->offset, + (u32*)ptr, len, sync); + if(R_FAILED(rc)) + { + r->_errno = sdmc_translate_error(rc); + return -1; + } + + file->offset += bytes; + + return bytes; +} + +/*! Write to an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in,out] fd Pointer to sdmc_file_t + * @param[in] ptr Pointer to data to write + * @param[in] len Length of data to write + * + * @returns number of bytes written + * @returns -1 for error + */ +static ssize_t +sdmc_write_safe(struct _reent *r, + int fd, + const char *ptr, + size_t len) { Result rc; u32 bytes, bytesWritten = 0; @@ -459,7 +533,7 @@ sdmc_write(struct _reent *r, /* check if this is synchronous or not */ if(file->flags & O_SYNC) - sync = FS_WRITE_FLUSH; + sync = FS_WRITE_FLUSH | FS_WRITE_UPDATE_TIME; if(file->flags & O_APPEND) {