From c77b88d868eaf1fcd93da2ab5b60e3faf7a0d7df Mon Sep 17 00:00:00 2001 From: fincs Date: Sun, 20 Oct 2019 22:21:30 +0200 Subject: [PATCH] Major cleanup and refactor of fsdev and romfsdev, see details: fsdev: - Removed fsdevGetDefaultFileSystem and default-fs handling - Refactored CWD support to have (dynamically allocated) per-device CWDs (CWD support as a whole can be turned off with __nx_fsdev_support_cwd) - Optimized calls by passing pointer to device through r->deviceData - Use the per-thread path buffer directly as the argument to FS functions - Removed redundant cross-device check in fsdev_rename - Fixed string comparison logic in fsdevFindDevice - fsdev_fixpath now accepts an input device in order to skip device lookup (extensively used along with r->deviceData) - Mounting a filesystem now automatically sets the default device if there wasn't any previous default device (or if it's stdnull) - fsdevMountSdmc no longer sets cwd to the folder containing the executable - this logic was moved to a new internal function called on startup by default (and it is now disabled for NSOs) - Other miscellaneous optimizations romfsdev: - Cleaned up romfsMount* functions, removed unused/unnecessary logic - Changed romfsMount* functions to return real result codes - Renamed romfsMount to romfsMountSelf and improved documentation - Removed romfsInitFromFile and romfsInitFromStorage (use Mount instead) - Added documentation for romfsInit and romfsExit --- nx/include/switch/runtime/devices/fs_dev.h | 5 +- nx/include/switch/runtime/devices/romfs_dev.h | 26 +- nx/source/runtime/devices/fs_dev.c | 296 ++++++++---------- nx/source/runtime/devices/romfs_dev.c | 171 ++++------ nx/source/runtime/init.c | 2 + 5 files changed, 212 insertions(+), 288 deletions(-) diff --git a/nx/include/switch/runtime/devices/fs_dev.h b/nx/include/switch/runtime/devices/fs_dev.h index 1c833432..0c154a1a 100644 --- a/nx/include/switch/runtime/devices/fs_dev.h +++ b/nx/include/switch/runtime/devices/fs_dev.h @@ -27,7 +27,7 @@ NX_CONSTEXPR FsDirectoryEntry* fsdevDirGetEntries(fsdev_dir_t *dir) return (FsDirectoryEntry*)(void*)(dir+1); } -/// Initializes and mounts the sdmc device if accessible. Also initializes current working directory to point to the folder containing the path to the executable (argv[0]), if it is provided by the environment. +/// Initializes and mounts the sdmc device if accessible. Result fsdevMountSdmc(void); /// Mounts the input fs with the specified device name. fsdev will handle closing the fs when required, including when fsdevMountDevice() fails. @@ -44,9 +44,6 @@ Result fsdevCommitDevice(const char *name); /// Returns the FsFileSystem for the specified device. Returns NULL when the specified device isn't found. FsFileSystem* fsdevGetDeviceFileSystem(const char *name); -/// Returns the FsFileSystem for the default device (SD card), if mounted. Used internally by romfs_dev. -FsFileSystem* fsdevGetDefaultFileSystem(void); - /// Writes the FS-path to outpath (which has buffer size FS_MAX_PATH), for the input path (as used in stdio). The FsFileSystem is also written to device when not NULL. int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath); diff --git a/nx/include/switch/runtime/devices/romfs_dev.h b/nx/include/switch/runtime/devices/romfs_dev.h index af08df12..6e119d4c 100644 --- a/nx/include/switch/runtime/devices/romfs_dev.h +++ b/nx/include/switch/runtime/devices/romfs_dev.h @@ -53,12 +53,11 @@ typedef struct /** * @brief Mounts the Application's RomFS. * @param name Device mount name. + * @remark This function is intended to be used to access one's own RomFS. + * If the application is running as NRO, it mounts the embedded RomFS section inside the NRO. + * If on the other hand it's an NSO, it behaves identically to \ref romfsMountFromCurrentProcess. */ -Result romfsMount(const char *name); -static inline Result romfsInit(void) -{ - return romfsMount("romfs"); -} +Result romfsMountSelf(const char *name); /** * @brief Mounts RomFS from an open file. @@ -67,10 +66,6 @@ static inline Result romfsInit(void) * @param name Device mount name. */ Result romfsMountFromFile(FsFile file, u64 offset, const char *name); -static inline Result romfsInitFromFile(FsFile file, u64 offset) -{ - return romfsMountFromFile(file, offset, "romfs"); -} /** * @brief Mounts RomFS from an open storage. @@ -79,10 +74,6 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset) * @param name Device mount name. */ Result romfsMountFromStorage(FsStorage storage, u64 offset, const char *name); -static inline Result romfsInitFromStorage(FsStorage storage, u64 offset) -{ - return romfsMountFromStorage(storage, offset, "romfs"); -} /** * @brief Mounts RomFS using the current process host title RomFS. @@ -108,8 +99,15 @@ Result romfsMountFromDataArchive(u64 dataId, FsStorageId storageId, const char * /// Unmounts the RomFS device. Result romfsUnmount(const char *name); + +/// Wrapper for \ref romfsMountSelf with the default "romfs" device name. +static inline Result romfsInit(void) +{ + return romfsMountSelf("romfs"); +} + +/// Wrapper for \ref romfsUnmount with the default "romfs" device name. static inline Result romfsExit(void) { return romfsUnmount("romfs"); } - diff --git a/nx/source/runtime/devices/fs_dev.c b/nx/source/runtime/devices/fs_dev.c index e1bac69a..60b9e76f 100644 --- a/nx/source/runtime/devices/fs_dev.c +++ b/nx/source/runtime/devices/fs_dev.c @@ -11,6 +11,7 @@ #include "runtime/devices/fs_dev.h" #include "runtime/util/utf.h" +#include "runtime/env.h" #include "services/fs.h" #include "services/time.h" @@ -62,7 +63,7 @@ typedef struct } fsdev_file_t; /*! fsdev devoptab */ -static devoptab_t +static const devoptab_t fsdev_devoptab = { .structSize = sizeof(fsdev_file_t), @@ -94,24 +95,25 @@ fsdev_devoptab = typedef struct { - bool setup; - s32 id; - devoptab_t device; - FsFileSystem fs; - char name[32]; + bool setup; + s32 id; + devoptab_t device; + FsFileSystem fs; + char *cwd; + char name[32]; } fsdev_fsdevice; static bool fsdev_initialised = false; -static s32 fsdev_fsdevice_default = -1; -static s32 fsdev_fsdevice_cwd = -1; +static s32 fsdev_fsdevice_cwd; static __thread Result fsdev_last_result = 0; static fsdev_fsdevice fsdev_fsdevices[32]; /*! @endcond */ -static char __cwd[PATH_MAX+1] = "/"; +_Static_assert((PATH_MAX+1) >= FS_MAX_PATH, "PATH_MAX is too small"); __attribute__((weak)) u32 __nx_fsdev_direntry_cache_size = 32; +__attribute__((weak)) bool __nx_fsdev_support_cwd = true; static fsdev_fsdevice *fsdevFindDevice(const char *name) { @@ -122,18 +124,6 @@ static fsdev_fsdevice *fsdevFindDevice(const char *name) if(!fsdev_initialised) return NULL; - if(name && name[0] == '/') //Return the default device. - { - if(fsdev_fsdevice_default==-1) - return NULL; - - device = &fsdev_fsdevices[fsdev_fsdevice_default]; - if(!device->setup) - device = NULL; - - return device; - } - for(i=0; isetup) //Find the device with the input name. { - if(strncmp(device->name, name, strlen(device->name))==0) + size_t devnamelen = strlen(device->name); + if(strncmp(device->name, name, devnamelen)==0 && (name[devnamelen]=='\0' || name[devnamelen]==':')) return device; } } @@ -201,13 +192,27 @@ fsdev_fixpath(struct _reent *r, p += units; } while(code != 0); + fsdev_fsdevice *dev = NULL; + if(device && *device != NULL) + dev = *device; + else if(path != device_path) + dev = fsdevFindDevice(device_path); + else if(fsdev_fsdevice_cwd != -1) + dev = &fsdev_fsdevices[fsdev_fsdevice_cwd]; + if(dev == NULL) + { + r->_errno = ENODEV; + return NULL; + } + if(path[0] == '/') strncpy(__nx_dev_path_buf, path, PATH_MAX); else { - strncpy(__nx_dev_path_buf, __cwd, PATH_MAX); + const char* cwd = dev->cwd ? dev->cwd : "/"; + strncpy(__nx_dev_path_buf, cwd, PATH_MAX); __nx_dev_path_buf[PATH_MAX] = '\0'; - strncat(__nx_dev_path_buf, path, PATH_MAX - strlen(__cwd)); + strncat(__nx_dev_path_buf, path, PATH_MAX - strlen(cwd)); } if(__nx_dev_path_buf[PATH_MAX] != 0) @@ -218,23 +223,7 @@ fsdev_fixpath(struct _reent *r, } if(device) - { - if(path[0] == '/') - { - *device = fsdevFindDevice(device_path); - } - else - { - *device = NULL; - if(fsdev_fsdevice_cwd != -1) - *device = &fsdev_fsdevices[fsdev_fsdevice_cwd]; - } - if(*device == NULL) - { - r->_errno = ENODEV; - return NULL; - } - } + *device = dev; return __nx_dev_path_buf; } @@ -248,7 +237,8 @@ fsdev_getfspath(struct _reent *r, if(fsdev_fixpath(r, path, device) == NULL) return -1; - memcpy(outpath, __nx_dev_path_buf,FS_MAX_PATH-1); + if(outpath != __nx_dev_path_buf) + memcpy(outpath, __nx_dev_path_buf, FS_MAX_PATH-1); outpath[FS_MAX_PATH-1] = '\0'; return 0; @@ -302,10 +292,11 @@ static void _fsdevInit(void) memcpy(&fsdev_fsdevices[i].device, &fsdev_devoptab, sizeof(fsdev_devoptab)); fsdev_fsdevices[i].device.name = fsdev_fsdevices[i].name; fsdev_fsdevices[i].device.dirStateSize += sizeof(FsDirectoryEntry)*__nx_fsdev_direntry_cache_size; + fsdev_fsdevices[i].device.deviceData = &fsdev_fsdevices[i]; fsdev_fsdevices[i].id = i; } - fsdev_fsdevice_default = -1; + fsdev_fsdevice_cwd = -1; fsdev_initialised = true; } } @@ -314,20 +305,14 @@ static int _fsdevMountDevice(const char *name, FsFileSystem fs, fsdev_fsdevice * { fsdev_fsdevice *device = NULL; - _fsdevInit(); //Ensure fsdev is initialized - if(fsdevFindDevice(name)) //Device is already mounted with the same name. - { - fsFsClose(&fs); - return -1; - } + goto _fail; + + _fsdevInit(); //Ensure fsdev is initialized device = fsdevFindDevice(NULL); if(device==NULL) - { - fsFsClose(&fs); - return -1; - } + goto _fail; device->fs = fs; memset(device->name, 0, sizeof(device->name)); @@ -335,17 +320,31 @@ static int _fsdevMountDevice(const char *name, FsFileSystem fs, fsdev_fsdevice * int dev = AddDevice(&device->device); if(dev==-1) - { - fsFsClose(&device->fs); - return dev; - } + goto _fail; device->setup = 1; + device->cwd = __nx_fsdev_support_cwd ? malloc(FS_MAX_PATH) : NULL; + if(device->cwd!=NULL) + { + device->cwd[0] = '/'; + device->cwd[1] = '\0'; + } + + if(fsdev_fsdevice_cwd==-1) + fsdev_fsdevice_cwd = device->id; + + const devoptab_t *default_dev = GetDeviceOpTab(""); + if(default_dev==NULL || strcmp(default_dev->name, "stdnull")==0) + setDefaultDevice(dev); if(out_device) *out_device = device; return dev; + +_fail: + fsFsClose(&fs); + return -1; } int fsdevMountDevice(const char *name, FsFileSystem fs) @@ -365,13 +364,11 @@ static int _fsdevUnmountDeviceStruct(fsdev_fsdevice *device) strncat(name, ":", sizeof(name)-strlen(name)-1); RemoveDevice(name); + free(device->cwd); fsFsClose(&device->fs); - if(device->id == fsdev_fsdevice_default) - fsdev_fsdevice_default = -1; - if(device->id == fsdev_fsdevice_cwd) - fsdev_fsdevice_cwd = fsdev_fsdevice_default; + fsdev_fsdevice_cwd = -1; device->setup = 0; memset(device->name, 0, sizeof(device->name)); @@ -402,7 +399,7 @@ Result fsdevCommitDevice(const char *name) } Result fsdevSetArchiveBit(const char *path) { - char fs_path[FS_MAX_PATH]; + char *fs_path = __nx_dev_path_buf; fsdev_fsdevice *device = NULL; if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) @@ -412,7 +409,7 @@ Result fsdevSetArchiveBit(const char *path) { } Result fsdevCreateFile(const char* path, size_t size, u32 flags) { - char fs_path[FS_MAX_PATH]; + char *fs_path = __nx_dev_path_buf; fsdev_fsdevice *device = NULL; if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) @@ -422,7 +419,7 @@ Result fsdevCreateFile(const char* path, size_t size, u32 flags) { } Result fsdevDeleteDirectoryRecursively(const char *path) { - char fs_path[FS_MAX_PATH]; + char *fs_path = __nx_dev_path_buf; fsdev_fsdevice *device = NULL; if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) @@ -434,72 +431,49 @@ Result fsdevDeleteDirectoryRecursively(const char *path) { /*! Initialize SDMC device */ Result fsdevMountSdmc(void) { - ssize_t units; - uint32_t code; - char *p; - Result rc = 0; FsFileSystem fs; - fsdev_fsdevice *device = NULL; - - if(fsdevFindDevice("sdmc")) - return 0; - - rc = fsMountSdcard(&fs); + Result rc = fsMountSdcard(&fs); if(R_SUCCEEDED(rc)) { - int dev = _fsdevMountDevice("sdmc", fs, &device); - - if(dev != -1) - { - setDefaultDevice(dev); - if(device) - { - fsdev_fsdevice_default = device->id; - fsdev_fsdevice_cwd = fsdev_fsdevice_default; - } - - if(__system_argc != 0 && __system_argv[0] != NULL) - { - if(FindDevice(__system_argv[0]) == dev) - { - strncpy(__nx_dev_path_buf,__system_argv[0],PATH_MAX); - if(__nx_dev_path_buf[PATH_MAX] != 0) - { - __nx_dev_path_buf[PATH_MAX] = 0; - } - else - { - char *last_slash = NULL; - p = __nx_dev_path_buf; - do - { - units = decode_utf8(&code, (const uint8_t*)p); - if(units < 0) - { - last_slash = NULL; - break; - } - - if(code == '/') - last_slash = p; - - p += units; - } while(code != 0); - - if(last_slash != NULL) - { - last_slash[0] = 0; - chdir(__nx_dev_path_buf); - } - } - } - } - } + int ret = fsdevMountDevice("sdmc", fs); + if(ret==-1) + rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); } return rc; } +void __libnx_init_cwd(void) +{ + if(envIsNso() || __system_argc==0 || __system_argv[0] == NULL) + return; + + char *last_slash = NULL; + char *p = __system_argv[0]; + uint32_t code; + do + { + ssize_t units = decode_utf8(&code, (const uint8_t*)p); + if(units < 0) + { + last_slash = NULL; + break; + } + + if(code == '/') + last_slash = p; + + p += units; + } while(code != 0); + + if(last_slash != NULL) + { + last_slash[0] = 0; + chdir(__system_argv[0]); + last_slash[0] = '/'; + } +} + /*! Clean up fsdev devices */ Result fsdevUnmountAll(void) { @@ -530,14 +504,6 @@ FsFileSystem* fsdevGetDeviceFileSystem(const char *name) return &device->fs; } -FsFileSystem* fsdevGetDefaultFileSystem(void) -{ - if(!fsdev_initialised) return NULL; - if(fsdev_fsdevice_default==-1) return NULL; - - return &fsdev_fsdevices[fsdev_fsdevice_default].fs; -} - int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath) { fsdev_fsdevice *tmpdev = NULL; @@ -571,8 +537,8 @@ fsdev_open(struct _reent *r, Result rc; u32 fsdev_flags = 0; u32 attributes = 0; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; if(fsdev_getfspath(r, path, &device, fs_path)==-1) return -1; @@ -1025,8 +991,8 @@ fsdev_stat(struct _reent *r, FsDir fdir; Result rc; int ret=0; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; FsTimeStampRaw timestamps = {0}; FsDirEntryType type; @@ -1111,8 +1077,8 @@ fsdev_unlink(struct _reent *r, const char *name) { Result rc; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; if(fsdev_getfspath(r, name, &device, fs_path)==-1) return -1; @@ -1139,8 +1105,14 @@ fsdev_chdir(struct _reent *r, { FsDir fd; Result rc; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; + + if(device->cwd==NULL) + { + r->_errno = ENOSYS; + return -1; + } if(fsdev_getfspath(r, name, &device, fs_path)==-1) return -1; @@ -1149,15 +1121,13 @@ fsdev_chdir(struct _reent *r, if(R_SUCCEEDED(rc)) { fsDirClose(&fd); - strncpy(__cwd, fs_path, PATH_MAX); - __cwd[PATH_MAX] = '\0'; + memcpy(device->cwd, fs_path, FS_MAX_PATH); - size_t __cwd_len = strlen(__cwd); - - if (__cwd[__cwd_len-1] != '/' && __cwd_len < PATH_MAX) + size_t cwdlen = strlen(fs_path); + if (device->cwd[cwdlen-1] != '/' && cwdlen < FS_MAX_PATH-1) { - __cwd[__cwd_len] = '/'; - __cwd[__cwd_len+1] = '\0'; + device->cwd[cwdlen] = '/'; + device->cwd[cwdlen+1] = '\0'; } fsdev_fsdevice_cwd = device->id; @@ -1184,34 +1154,28 @@ fsdev_rename(struct _reent *r, { Result rc; FsDirEntryType type; - fsdev_fsdevice *device_old = NULL, *device_new = NULL; + fsdev_fsdevice *device = r->deviceData; char fs_path_old[FS_MAX_PATH]; - char fs_path_new[FS_MAX_PATH]; + char*fs_path_new = __nx_dev_path_buf; - if(fsdev_getfspath(r, oldName, &device_old, fs_path_old)==-1) + if(fsdev_getfspath(r, oldName, &device, fs_path_old)==-1) return -1; - if(fsdev_getfspath(r, newName, &device_new, fs_path_new)==-1) + if(fsdev_getfspath(r, newName, &device, fs_path_new)==-1) return -1; - if(device_old->id != device_new->id) - { - r->_errno = EXDEV; - return -1; - } - - rc = fsFsGetEntryType(&device_old->fs, fs_path_old, &type); + rc = fsFsGetEntryType(&device->fs, fs_path_old, &type); if(R_SUCCEEDED(rc)) { if(type == FsDirEntryType_Dir) { - rc = fsFsRenameDirectory(&device_old->fs, fs_path_old, fs_path_new); + rc = fsFsRenameDirectory(&device->fs, fs_path_old, fs_path_new); if(R_SUCCEEDED(rc)) return 0; } else if(type == FsDirEntryType_File) { - rc = fsFsRenameFile(&device_old->fs, fs_path_old, fs_path_new); + rc = fsFsRenameFile(&device->fs, fs_path_old, fs_path_new); if(R_SUCCEEDED(rc)) return 0; } @@ -1241,8 +1205,8 @@ fsdev_mkdir(struct _reent *r, int mode) { Result rc; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; if(fsdev_getfspath(r, path, &device, fs_path)==-1) return -1; @@ -1271,8 +1235,8 @@ fsdev_diropen(struct _reent *r, { FsDir fd; Result rc; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; if(fsdev_getfspath(r, path, &device, fs_path)==-1) return NULL; @@ -1449,8 +1413,8 @@ fsdev_statvfs(struct _reent *r, struct statvfs *buf) { Result rc=0; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; u64 freespace = 0, total_space = 0; if(fsdev_getfspath(r, path, &device, fs_path)==-1) @@ -1591,8 +1555,8 @@ fsdev_rmdir(struct _reent *r, const char *name) { Result rc; - char fs_path[FS_MAX_PATH]; - fsdev_fsdevice *device = NULL; + char *fs_path = __nx_dev_path_buf; + fsdev_fsdevice *device = r->deviceData; if(fsdev_getfspath(r, name, &device, fs_path)==-1) return -1; diff --git a/nx/source/runtime/devices/romfs_dev.c b/nx/source/runtime/devices/romfs_dev.c index 43b74510..1ed69194 100644 --- a/nx/source/runtime/devices/romfs_dev.c +++ b/nx/source/runtime/devices/romfs_dev.c @@ -102,7 +102,7 @@ typedef struct u32 childFile; } romfs_diriter; -static devoptab_t romFS_devoptab = +static const devoptab_t romFS_devoptab = { .structSize = sizeof(romfs_fileobj), .open_r = romfs_open, @@ -201,101 +201,63 @@ static void romfs_mountclose(romfs_mount *mount) romfs_free(mount); } -Result romfsMount(const char *name) +Result romfsMountSelf(const char *name) { - romfs_mount *mount = romfs_alloc(); - if(mount == NULL) - return 99; + // Check whether we are a NSO; if so then just mount the RomFS from the current process + if (envIsNso()) + return romfsMountFromCurrentProcess(name); - if (!envIsNso()) - { - // RomFS embedded in a NRO + // Otherwise, we are a homebrew NRO and we need to use our embedded RomFS + // Retrieve the filename of our NRO + const char* filename = __romfs_path; + if (__system_argc > 0 && __system_argv[0]) + filename = __system_argv[0]; + if (!filename) + return MAKERESULT(Module_Libnx, LibnxError_NotFound); - mount->fd_type = RomfsSource_FsFile; + // Retrieve IFileSystem object + fixed path for our NRO + FsFileSystem *tmpfs = NULL; + char* path_buf = __nx_dev_path_buf; + if(fsdevTranslatePath(filename, &tmpfs, path_buf)==-1) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); - FsFileSystem *sdfs = fsdevGetDefaultFileSystem(); - if(sdfs==NULL) - { - romfs_free(mount); - return 1; - } + // Open the NRO file + FsFile nro_file; + Result rc = fsFsOpenFile(tmpfs, path_buf, FsOpenMode_Read, &nro_file); + if (R_FAILED(rc)) + return rc; - const char* filename = __romfs_path; - if (__system_argc > 0 && __system_argv[0]) - filename = __system_argv[0]; - if (!filename) - { - romfs_free(mount); - return 1; - } + // Read and parse the header + NroHeader hdr; + u64 readbytes = 0; + rc = fsFileRead(&nro_file, sizeof(NroStart), &hdr, sizeof(hdr), FsReadOption_None, &readbytes); + if (R_FAILED(rc) || readbytes != sizeof(hdr)) goto _fail_io; + if (hdr.magic != NROHEADER_MAGIC) goto _fail_io; - if (strncmp(filename, "sdmc:/", 6) == 0) - filename += 5; - else if (strncmp(filename, "nxlink:/", 8) == 0) - { - strncpy(__nx_dev_path_buf, "/switch", PATH_MAX); - strncat(__nx_dev_path_buf, filename+7, PATH_MAX); - __nx_dev_path_buf[PATH_MAX] = 0; - filename = __nx_dev_path_buf; - } - else - { - romfs_free(mount); - return 2; - } + // Read and parse the asset header + NroAssetHeader asset_header; + rc = fsFileRead(&nro_file, hdr.size, &asset_header, sizeof(asset_header), FsReadOption_None, &readbytes); + if (R_FAILED(rc) || readbytes != sizeof(asset_header)) goto _fail_io; + if (asset_header.magic != NROASSETHEADER_MAGIC + || asset_header.version > NROASSETHEADER_VERSION + || asset_header.romfs.offset == 0 + || asset_header.romfs.size == 0) + goto _fail_io; - Result rc = fsFsOpenFile(sdfs, filename, FsOpenMode_Read, &mount->fd); - if (R_FAILED(rc)) - { - romfs_free(mount); - return rc; - } + // Calculate the start offset of the embedded RomFS and mount it + u64 romfs_offset = hdr.size + asset_header.romfs.offset; + return romfsMountFromFile(nro_file, romfs_offset, name); - romfsInitMtime(mount); - - NroHeader hdr; - NroAssetHeader asset_header; - - if (!_romfs_read_chk(mount, sizeof(NroStart), &hdr, sizeof(hdr))) goto _fail0; - if (hdr.magic != NROHEADER_MAGIC) goto _fail0; - if (!_romfs_read_chk(mount, hdr.size, &asset_header, sizeof(asset_header))) goto _fail0; - - if (asset_header.magic != NROASSETHEADER_MAGIC - || asset_header.version > NROASSETHEADER_VERSION - || asset_header.romfs.offset == 0 - || asset_header.romfs.size == 0) - goto _fail0; - - mount->offset = hdr.size + asset_header.romfs.offset; - } - else - { - // Regular RomFS - - mount->fd_type = RomfsSource_FsStorage; - - Result rc = fsOpenDataStorageByCurrentProcess(&mount->fd_storage); - if (R_FAILED(rc)) - { - romfs_free(mount); - return rc; - } - - romfsInitMtime(mount); - } - - return romfsMountCommon(name, mount); - -_fail0: - romfs_mountclose(mount); - return 10; +_fail_io: + fsFileClose(&nro_file); + return MAKERESULT(Module_Libnx, LibnxError_IoError); } Result romfsMountFromFile(FsFile file, u64 offset, const char *name) { romfs_mount *mount = romfs_alloc(); if(mount == NULL) - return 99; + return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); mount->fd_type = RomfsSource_FsFile; mount->fd = file; @@ -308,7 +270,7 @@ Result romfsMountFromStorage(FsStorage storage, u64 offset, const char *name) { romfs_mount *mount = romfs_alloc(); if(mount == NULL) - return 99; + return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); mount->fd_type = RomfsSource_FsStorage; mount->fd_storage = storage; @@ -330,21 +292,17 @@ Result romfsMountFromCurrentProcess(const char *name) { Result romfsMountFromFsdev(const char *path, u64 offset, const char *name) { FsFileSystem *tmpfs = NULL; - char filepath[FS_MAX_PATH]; - - memset(filepath, 0, sizeof(filepath)); - - if(fsdevTranslatePath(path, &tmpfs, filepath)==-1) + if(fsdevTranslatePath(path, &tmpfs, __nx_dev_path_buf)==-1) return MAKERESULT(Module_Libnx, LibnxError_BadInput); romfs_mount *mount = romfs_alloc(); if(mount == NULL) - return 99; + return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); mount->fd_type = RomfsSource_FsFile; mount->offset = offset; - Result rc = fsFsOpenFile(tmpfs, filepath, FsOpenMode_Read, &mount->fd); + Result rc = fsFsOpenFile(tmpfs, __nx_dev_path_buf, FsOpenMode_Read, &mount->fd); if (R_FAILED(rc)) { romfs_free(mount); @@ -369,45 +327,50 @@ Result romfsMountCommon(const char *name, romfs_mount *mount) memset(mount->name, 0, sizeof(mount->name)); strncpy(mount->name, name, sizeof(mount->name)-1); + romfsInitMtime(mount); + if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header)) - goto fail; + goto fail_io; mount->dirHashTable = (u32*)malloc(mount->header.dirHashTableSize); if (!mount->dirHashTable) - goto fail; + goto fail_oom; if (!_romfs_read_chk(mount, mount->header.dirHashTableOff, mount->dirHashTable, mount->header.dirHashTableSize)) - goto fail; + goto fail_io; mount->dirTable = malloc(mount->header.dirTableSize); if (!mount->dirTable) - goto fail; + goto fail_oom; if (!_romfs_read_chk(mount, mount->header.dirTableOff, mount->dirTable, mount->header.dirTableSize)) - goto fail; + goto fail_io; mount->fileHashTable = (u32*)malloc(mount->header.fileHashTableSize); if (!mount->fileHashTable) - goto fail; + goto fail_oom; if (!_romfs_read_chk(mount, mount->header.fileHashTableOff, mount->fileHashTable, mount->header.fileHashTableSize)) - goto fail; + goto fail_io; mount->fileTable = malloc(mount->header.fileTableSize); if (!mount->fileTable) - goto fail; + goto fail_oom; if (!_romfs_read_chk(mount, mount->header.fileTableOff, mount->fileTable, mount->header.fileTableSize)) - goto fail; + goto fail_io; mount->cwd = romFS_root(mount); - // add device if this is the first one if(AddDevice(&mount->device) < 0) - goto fail; + goto fail_oom; mount->setup = true; return 0; -fail: +fail_oom: romfs_mountclose(mount); - return 10; + return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); + +fail_io: + romfs_mountclose(mount); + return MAKERESULT(Module_Libnx, LibnxError_IoError); } static void romfsInitMtime(romfs_mount *mount) @@ -422,7 +385,7 @@ Result romfsUnmount(const char *name) mount = romfsFindMount(name); if (mount == NULL) - return -1; + return MAKERESULT(Module_Libnx, LibnxError_NotFound); // Remove device memset(tmpname, 0, sizeof(tmpname)); diff --git a/nx/source/runtime/init.c b/nx/source/runtime/init.c index 5fda94bb..4f7bbada 100644 --- a/nx/source/runtime/init.c +++ b/nx/source/runtime/init.c @@ -17,6 +17,7 @@ void virtmemSetup(void); void newlibSetup(void); void argvSetup(void); void __libnx_init_time(void); +void __libnx_init_cwd(void); extern u32 __nx_applet_type; @@ -141,6 +142,7 @@ void __attribute__((weak)) __appInit(void) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); fsdevMountSdmc(); + __libnx_init_cwd(); if (&__nx_win_init) __nx_win_init(); if (&userAppInit) userAppInit();