mirror of
https://github.com/hax4dazy/TinWoo.git
synced 2025-02-09 19:25:05 +01:00
594 lines
16 KiB
C
594 lines
16 KiB
C
|
/*
|
||
|
* usbfs_dev.c
|
||
|
*
|
||
|
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||
|
* Copyright (c) 2018, Team Xecuter.
|
||
|
*
|
||
|
* This file is part of libusbhsfs (https://github.com/DarkMatterCore/libusbhsfs).
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to deal
|
||
|
* in the Software without restriction, including without limitation the rights
|
||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in all
|
||
|
* copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
|
* SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include <sys/iosupport.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
#include "../usbhsfs_utils.h"
|
||
|
#include "usbfs_dev.h"
|
||
|
|
||
|
/* Helper macros. */
|
||
|
|
||
|
#define usbfs_end goto end
|
||
|
#define usbfs_ended_with_error (_errno != 0)
|
||
|
#define usbfs_set_error(x) r->_errno = _errno = (x)
|
||
|
#define usbfs_set_error_and_exit(x) \
|
||
|
do { \
|
||
|
usbfs_set_error((x)); \
|
||
|
usbfs_end; \
|
||
|
} while(0)
|
||
|
|
||
|
#define usbfs_declare_error_state int _errno = 0
|
||
|
#define usbfs_declare_file_state usbfsdev_file *file = (usbfsdev_file*)fd
|
||
|
#define usbfs_declare_dir_state usbfsdev_dir *dir = (usbfsdev_dir*)dirState->dirStruct
|
||
|
|
||
|
#define usbfs_return(x) return (usbfs_ended_with_error ? -1 : (x))
|
||
|
#define usbfs_return_ptr(x) return (usbfs_ended_with_error ? NULL : (x))
|
||
|
|
||
|
/* Type definitions. */
|
||
|
|
||
|
/// usbfs file state.
|
||
|
typedef struct {
|
||
|
uint64_t fileid;
|
||
|
int flags;
|
||
|
} usbfsdev_file;
|
||
|
|
||
|
/// usbfs directory state.
|
||
|
typedef struct
|
||
|
{
|
||
|
uint64_t dirid;
|
||
|
} usbfsdev_dir;
|
||
|
|
||
|
/* Function prototypes. */
|
||
|
|
||
|
static int usbfsdev_open(struct _reent *r, void *fd, const char *path, int flags, int mode);
|
||
|
static int usbfsdev_close(struct _reent *r, void *fd);
|
||
|
static ssize_t usbfsdev_write(struct _reent *r, void *fd, const char *ptr, size_t len);
|
||
|
static ssize_t usbfsdev_read(struct _reent *r, void *fd, char *ptr, size_t len);
|
||
|
static off_t usbfsdev_seek(struct _reent *r, void *fd, off_t pos, int dir);
|
||
|
static int usbfsdev_fstat(struct _reent *r, void *fd, struct stat *st);
|
||
|
static int usbfsdev_stat(struct _reent *r, const char *file, struct stat *st);
|
||
|
static int usbfsdev_link(struct _reent *r, const char *existing, const char *newLink);
|
||
|
static int usbfsdev_unlink(struct _reent *r, const char *name);
|
||
|
static int usbfsdev_chdir(struct _reent *r, const char *name);
|
||
|
static int usbfsdev_rename(struct _reent *r, const char *oldName, const char *newName);
|
||
|
static int usbfsdev_mkdir(struct _reent *r, const char *path, int mode);
|
||
|
static DIR_ITER* usbfsdev_diropen(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||
|
static int usbfsdev_dirreset(struct _reent *r, DIR_ITER *dirState);
|
||
|
static int usbfsdev_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||
|
static int usbfsdev_dirclose(struct _reent *r, DIR_ITER *dirState);
|
||
|
static int usbfsdev_statvfs(struct _reent *r, const char *path, struct statvfs *buf);
|
||
|
static int usbfsdev_ftruncate(struct _reent *r, void *fd, off_t len);
|
||
|
static int usbfsdev_fsync(struct _reent *r, void *fd);
|
||
|
static int usbfsdev_chmod(struct _reent *r, const char *path, mode_t mode);
|
||
|
static int usbfsdev_fchmod(struct _reent *r, void *fd, mode_t mode);
|
||
|
static int usbfsdev_rmdir(struct _reent *r, const char *name);
|
||
|
static int usbfsdev_utimes(struct _reent *r, const char *filename, const struct timeval times[2]);
|
||
|
|
||
|
/* Global variables. */
|
||
|
|
||
|
static const devoptab_t usbfsdev_devoptab = {
|
||
|
.name = USBFS_MOUNT_NAME,
|
||
|
.structSize = sizeof(usbfsdev_file),
|
||
|
.open_r = usbfsdev_open,
|
||
|
.close_r = usbfsdev_close,
|
||
|
.write_r = usbfsdev_write,
|
||
|
.read_r = usbfsdev_read,
|
||
|
.seek_r = usbfsdev_seek,
|
||
|
.fstat_r = usbfsdev_fstat,
|
||
|
.stat_r = usbfsdev_stat,
|
||
|
.link_r = usbfsdev_link, ///< Not supported by usbfs.
|
||
|
.unlink_r = usbfsdev_unlink,
|
||
|
.chdir_r = usbfsdev_chdir, ///< Not supported by usbfs.
|
||
|
.rename_r = usbfsdev_rename, ///< Not supported by usbfs.
|
||
|
.mkdir_r = usbfsdev_mkdir,
|
||
|
.dirStateSize = sizeof(usbfsdev_dir),
|
||
|
.diropen_r = usbfsdev_diropen,
|
||
|
.dirreset_r = usbfsdev_dirreset, ///< Not supported by usbfs.
|
||
|
.dirnext_r = usbfsdev_dirnext,
|
||
|
.dirclose_r = usbfsdev_dirclose,
|
||
|
.statvfs_r = usbfsdev_statvfs,
|
||
|
.ftruncate_r = usbfsdev_ftruncate,
|
||
|
.fsync_r = usbfsdev_fsync,
|
||
|
.deviceData = NULL,
|
||
|
.chmod_r = usbfsdev_chmod, ///< Not supported by usbfs.
|
||
|
.fchmod_r = usbfsdev_fchmod, ///< Not supported by usbfs.
|
||
|
.rmdir_r = usbfsdev_rmdir,
|
||
|
.lstat_r = usbfsdev_stat, ///< Symlinks aren't supported, so we'll just alias lstat() to stat().
|
||
|
.utimes_r = usbfsdev_utimes ///< Not supported by usbfs.
|
||
|
};
|
||
|
|
||
|
bool usbfsdev_register(void)
|
||
|
{
|
||
|
int device_idx = -1;
|
||
|
bool ret = false;
|
||
|
|
||
|
/* Get devoptab device index for our filesystem. */
|
||
|
device_idx = FindDevice(USBFS_MOUNT_NAME ":");
|
||
|
if (device_idx < 0)
|
||
|
{
|
||
|
/* Device not available. Let's add it. */
|
||
|
device_idx = AddDevice(&usbfsdev_devoptab);
|
||
|
if (device_idx < 0)
|
||
|
{
|
||
|
USBHSFS_LOG_MSG("Failed to add devoptab device for \"" USBFS_MOUNT_NAME "\"!");
|
||
|
goto end;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Update return value. */
|
||
|
ret = true;
|
||
|
|
||
|
end:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void usbfsdev_unregister(void)
|
||
|
{
|
||
|
RemoveDevice(USBFS_MOUNT_NAME ":");
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_open(struct _reent *r, void *fd, const char *path, int flags, int mode)
|
||
|
{
|
||
|
(void)mode;
|
||
|
|
||
|
Result rc = 0;
|
||
|
char *path_start = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || !path || !*path || !(path_start = strchr(path, ':')) || !*(++path_start)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Reset file state. */
|
||
|
memset(file, 0, sizeof(usbfsdev_file));
|
||
|
file->flags = flags;
|
||
|
|
||
|
/* Open file. */
|
||
|
rc = usbFsOpenFile(&(file->fileid), path_start, (u64)flags);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(ENOENT);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_close(struct _reent *r, void *fd)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Close file. */
|
||
|
rc = usbFsCloseFile(file->fileid);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Invalidate file ID. */
|
||
|
file->fileid = 0xFFFFFFFF;
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static ssize_t usbfsdev_write(struct _reent *r, void *fd, const char *ptr, size_t len)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
u64 pos = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || !ptr || !len) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Check if the file was opened with write access. */
|
||
|
if ((file->flags & O_ACCMODE) == O_RDONLY) usbfs_set_error_and_exit(EBADF);
|
||
|
|
||
|
/* Check if the append flag is enabled. */
|
||
|
if (file->flags & O_APPEND)
|
||
|
{
|
||
|
/* Seek to EOF. */
|
||
|
rc = usbFsSeekFile(file->fileid, 0, SEEK_END, &pos);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
}
|
||
|
|
||
|
/* Write file data. */
|
||
|
rc = usbFsWriteFile(file->fileid, ptr, len, (size_t*)&pos);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return((ssize_t)pos);
|
||
|
}
|
||
|
|
||
|
static ssize_t usbfsdev_read(struct _reent *r, void *fd, char *ptr, size_t len)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
size_t rd_sz = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || !ptr || !len) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Check if the file was opened with read access. */
|
||
|
if ((file->flags & O_ACCMODE) == O_WRONLY) usbfs_set_error_and_exit(EBADF);
|
||
|
|
||
|
/* Read file data. */
|
||
|
rc = usbFsReadFile(file->fileid, ptr, len, &rd_sz);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return((ssize_t)rd_sz);
|
||
|
}
|
||
|
|
||
|
static off_t usbfsdev_seek(struct _reent *r, void *fd, off_t pos, int dir)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
u64 outpos = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Perform file seek. */
|
||
|
rc = usbFsSeekFile(file->fileid, (u64)pos, (u64)dir, &outpos);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return((off_t)outpos);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_fstat(struct _reent *r, void *fd, struct stat *st)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
u64 size = 0, mode = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || !st) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Get file stats. */
|
||
|
rc = usbFsStatFile(file->fileid, &size, &mode);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Fill stat info. */
|
||
|
memset(st, 0, sizeof(struct stat));
|
||
|
st->st_nlink = 1;
|
||
|
st->st_size = (off_t)size;
|
||
|
st->st_mode = (mode_t)mode;
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_stat(struct _reent *r, const char *file, struct stat *st)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
u64 size = 0, mode = 0;
|
||
|
char *path_start = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || !*file || !(path_start = strchr(file, ':')) || !*(++path_start) || !st) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Get file stats. */
|
||
|
rc = usbFsStatPath(path_start, &size, &mode);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Fill stat info. */
|
||
|
memset(st, 0, sizeof(struct stat));
|
||
|
st->st_nlink = 1;
|
||
|
st->st_size = (off_t)size;
|
||
|
st->st_mode = (mode_t)mode;
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_link(struct _reent *r, const char *existing, const char *newLink)
|
||
|
{
|
||
|
(void)existing;
|
||
|
(void)newLink;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_unlink(struct _reent *r, const char *name)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
char *path_start = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!name || !*name || !(path_start = strchr(name, ':')) || !*(++path_start)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Delete file. */
|
||
|
rc = usbFsDeleteFile(path_start);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_chdir(struct _reent *r, const char *name)
|
||
|
{
|
||
|
(void)name;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_rename(struct _reent *r, const char *oldName, const char *newName)
|
||
|
{
|
||
|
(void)oldName;
|
||
|
(void)newName;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_mkdir(struct _reent *r, const char *path, int mode)
|
||
|
{
|
||
|
(void)mode;
|
||
|
|
||
|
Result rc = 0;
|
||
|
char *path_start = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!path || !*path || !(path_start = strchr(path, ':')) || !*(++path_start)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Create directory. */
|
||
|
rc = usbFsCreateDir(path_start);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static DIR_ITER *usbfsdev_diropen(struct _reent *r, DIR_ITER *dirState, const char *path)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
char *path_start = NULL;
|
||
|
DIR_ITER *ret = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!dirState || !path || !*path || !(path_start = strchr(path, ':')) || !*(++path_start)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
usbfs_declare_dir_state;
|
||
|
|
||
|
/* Reset directory state. */
|
||
|
memset(dir, 0, sizeof(usbfsdev_dir));
|
||
|
|
||
|
/* Open directory. */
|
||
|
rc = usbFsOpenDir(&(dir->dirid), path_start);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Update return value. */
|
||
|
ret = dirState;
|
||
|
|
||
|
end:
|
||
|
usbfs_return_ptr(ret);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_dirreset(struct _reent *r, DIR_ITER *dirState)
|
||
|
{
|
||
|
(void)dirState;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
u64 type = 0, size = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!dirState || !filename || !filestat) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
usbfs_declare_dir_state;
|
||
|
|
||
|
/* Clear filename buffer. */
|
||
|
memset(filename, 0, NAME_MAX);
|
||
|
|
||
|
/* Read directory. */
|
||
|
rc = usbFsReadDir(dir->dirid, &type, &size, filename, NAME_MAX);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(rc == 0x68A ? ENOENT : EINVAL); /* ENOENT signals EOD. */
|
||
|
|
||
|
/* Fill stat info. */
|
||
|
filestat->st_ino = 0;
|
||
|
filestat->st_mode = (mode_t)type;
|
||
|
filestat->st_size = (off_t)size;
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_dirclose(struct _reent *r, DIR_ITER *dirState)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!dirState) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
usbfs_declare_dir_state;
|
||
|
|
||
|
/* Close directory. */
|
||
|
rc = usbFsCloseDir(dir->dirid);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_statvfs(struct _reent *r, const char *path, struct statvfs *buf)
|
||
|
{
|
||
|
(void)path;
|
||
|
|
||
|
Result rc = 0;
|
||
|
u64 freespace = 0, totalspace = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!buf) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Get volume information. */
|
||
|
rc = usbFsStatFilesystem(&totalspace, &freespace);
|
||
|
if (R_FAILED(rc)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Fill filesystem stats. */
|
||
|
memset(buf, 0, sizeof(struct statvfs));
|
||
|
|
||
|
buf->f_bsize = 1;
|
||
|
buf->f_frsize = 1;
|
||
|
buf->f_blocks = totalspace;
|
||
|
buf->f_bfree = freespace;
|
||
|
buf->f_bavail = freespace;
|
||
|
buf->f_files = 0;
|
||
|
buf->f_ffree = 0;
|
||
|
buf->f_favail = 0;
|
||
|
buf->f_fsid = 0;
|
||
|
buf->f_flag = ST_NOSUID;
|
||
|
buf->f_namemax = 0;
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_ftruncate(struct _reent *r, void *fd, off_t len)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file || len < 0) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Check if the file was opened with write access. */
|
||
|
if ((file->flags & O_ACCMODE) == O_RDONLY) usbfs_set_error_and_exit(EBADF);
|
||
|
|
||
|
/* Truncate file. */
|
||
|
rc = usbFsTruncateFile(file->fileid, (u64)len);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_fsync(struct _reent *r, void *fd)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
usbfs_declare_file_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!file) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Synchronize file. */
|
||
|
rc = usbFsSyncFile(file->fileid);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_chmod(struct _reent *r, const char *path, mode_t mode)
|
||
|
{
|
||
|
(void)path;
|
||
|
(void)mode;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_fchmod(struct _reent *r, void *fd, mode_t mode)
|
||
|
{
|
||
|
(void)fd;
|
||
|
(void)mode;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_rmdir(struct _reent *r, const char *name)
|
||
|
{
|
||
|
Result rc = 0;
|
||
|
char *path_start = NULL;
|
||
|
|
||
|
usbfs_declare_error_state;
|
||
|
|
||
|
/* Sanity check. */
|
||
|
if (!name || !*name || !(path_start = strchr(name, ':')) || !*(++path_start)) usbfs_set_error_and_exit(EINVAL);
|
||
|
|
||
|
/* Delete directory. */
|
||
|
rc = usbFsDeleteDir(path_start);
|
||
|
if (R_FAILED(rc)) usbfs_set_error(EINVAL);
|
||
|
|
||
|
end:
|
||
|
usbfs_return(0);
|
||
|
}
|
||
|
|
||
|
static int usbfsdev_utimes(struct _reent *r, const char *filename, const struct timeval times[2])
|
||
|
{
|
||
|
(void)filename;
|
||
|
(void)times;
|
||
|
|
||
|
/* Not supported by usbfs. */
|
||
|
r->_errno = ENOSYS;
|
||
|
return -1;
|
||
|
}
|