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
This commit is contained in:
fincs 2019-10-20 22:21:30 +02:00
parent 0403c988ba
commit c77b88d868
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60
5 changed files with 212 additions and 288 deletions

View File

@ -27,7 +27,7 @@ NX_CONSTEXPR FsDirectoryEntry* fsdevDirGetEntries(fsdev_dir_t *dir)
return (FsDirectoryEntry*)(void*)(dir+1); 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); Result fsdevMountSdmc(void);
/// Mounts the input fs with the specified device name. fsdev will handle closing the fs when required, including when fsdevMountDevice() fails. /// 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. /// Returns the FsFileSystem for the specified device. Returns NULL when the specified device isn't found.
FsFileSystem* fsdevGetDeviceFileSystem(const char *name); 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. /// 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); int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath);

View File

@ -53,12 +53,11 @@ typedef struct
/** /**
* @brief Mounts the Application's RomFS. * @brief Mounts the Application's RomFS.
* @param name Device mount name. * @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); Result romfsMountSelf(const char *name);
static inline Result romfsInit(void)
{
return romfsMount("romfs");
}
/** /**
* @brief Mounts RomFS from an open file. * @brief Mounts RomFS from an open file.
@ -67,10 +66,6 @@ static inline Result romfsInit(void)
* @param name Device mount name. * @param name Device mount name.
*/ */
Result romfsMountFromFile(FsFile file, u64 offset, const char *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. * @brief Mounts RomFS from an open storage.
@ -79,10 +74,6 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset)
* @param name Device mount name. * @param name Device mount name.
*/ */
Result romfsMountFromStorage(FsStorage storage, u64 offset, const char *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. * @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. /// Unmounts the RomFS device.
Result romfsUnmount(const char *name); 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) static inline Result romfsExit(void)
{ {
return romfsUnmount("romfs"); return romfsUnmount("romfs");
} }

View File

@ -11,6 +11,7 @@
#include "runtime/devices/fs_dev.h" #include "runtime/devices/fs_dev.h"
#include "runtime/util/utf.h" #include "runtime/util/utf.h"
#include "runtime/env.h"
#include "services/fs.h" #include "services/fs.h"
#include "services/time.h" #include "services/time.h"
@ -62,7 +63,7 @@ typedef struct
} fsdev_file_t; } fsdev_file_t;
/*! fsdev devoptab */ /*! fsdev devoptab */
static devoptab_t static const devoptab_t
fsdev_devoptab = fsdev_devoptab =
{ {
.structSize = sizeof(fsdev_file_t), .structSize = sizeof(fsdev_file_t),
@ -94,24 +95,25 @@ fsdev_devoptab =
typedef struct typedef struct
{ {
bool setup; bool setup;
s32 id; s32 id;
devoptab_t device; devoptab_t device;
FsFileSystem fs; FsFileSystem fs;
char name[32]; char *cwd;
char name[32];
} fsdev_fsdevice; } fsdev_fsdevice;
static bool fsdev_initialised = false; static bool fsdev_initialised = false;
static s32 fsdev_fsdevice_default = -1; static s32 fsdev_fsdevice_cwd;
static s32 fsdev_fsdevice_cwd = -1;
static __thread Result fsdev_last_result = 0; static __thread Result fsdev_last_result = 0;
static fsdev_fsdevice fsdev_fsdevices[32]; static fsdev_fsdevice fsdev_fsdevices[32];
/*! @endcond */ /*! @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)) u32 __nx_fsdev_direntry_cache_size = 32;
__attribute__((weak)) bool __nx_fsdev_support_cwd = true;
static fsdev_fsdevice *fsdevFindDevice(const char *name) static fsdev_fsdevice *fsdevFindDevice(const char *name)
{ {
@ -122,18 +124,6 @@ static fsdev_fsdevice *fsdevFindDevice(const char *name)
if(!fsdev_initialised) if(!fsdev_initialised)
return NULL; 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; i<total; i++) for(i=0; i<total; i++)
{ {
device = &fsdev_fsdevices[i]; device = &fsdev_fsdevices[i];
@ -145,7 +135,8 @@ static fsdev_fsdevice *fsdevFindDevice(const char *name)
} }
else if(device->setup) //Find the device with the input name. else if(device->setup) //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; return device;
} }
} }
@ -201,13 +192,27 @@ fsdev_fixpath(struct _reent *r,
p += units; p += units;
} while(code != 0); } 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] == '/') if(path[0] == '/')
strncpy(__nx_dev_path_buf, path, PATH_MAX); strncpy(__nx_dev_path_buf, path, PATH_MAX);
else 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'; __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) if(__nx_dev_path_buf[PATH_MAX] != 0)
@ -218,23 +223,7 @@ fsdev_fixpath(struct _reent *r,
} }
if(device) if(device)
{ *device = dev;
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;
}
}
return __nx_dev_path_buf; return __nx_dev_path_buf;
} }
@ -248,7 +237,8 @@ fsdev_getfspath(struct _reent *r,
if(fsdev_fixpath(r, path, device) == NULL) if(fsdev_fixpath(r, path, device) == NULL)
return -1; 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'; outpath[FS_MAX_PATH-1] = '\0';
return 0; return 0;
@ -302,10 +292,11 @@ static void _fsdevInit(void)
memcpy(&fsdev_fsdevices[i].device, &fsdev_devoptab, sizeof(fsdev_devoptab)); memcpy(&fsdev_fsdevices[i].device, &fsdev_devoptab, sizeof(fsdev_devoptab));
fsdev_fsdevices[i].device.name = fsdev_fsdevices[i].name; 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.dirStateSize += sizeof(FsDirectoryEntry)*__nx_fsdev_direntry_cache_size;
fsdev_fsdevices[i].device.deviceData = &fsdev_fsdevices[i];
fsdev_fsdevices[i].id = i; fsdev_fsdevices[i].id = i;
} }
fsdev_fsdevice_default = -1; fsdev_fsdevice_cwd = -1;
fsdev_initialised = true; fsdev_initialised = true;
} }
} }
@ -314,20 +305,14 @@ static int _fsdevMountDevice(const char *name, FsFileSystem fs, fsdev_fsdevice *
{ {
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = NULL;
_fsdevInit(); //Ensure fsdev is initialized
if(fsdevFindDevice(name)) //Device is already mounted with the same name. if(fsdevFindDevice(name)) //Device is already mounted with the same name.
{ goto _fail;
fsFsClose(&fs);
return -1; _fsdevInit(); //Ensure fsdev is initialized
}
device = fsdevFindDevice(NULL); device = fsdevFindDevice(NULL);
if(device==NULL) if(device==NULL)
{ goto _fail;
fsFsClose(&fs);
return -1;
}
device->fs = fs; device->fs = fs;
memset(device->name, 0, sizeof(device->name)); 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); int dev = AddDevice(&device->device);
if(dev==-1) if(dev==-1)
{ goto _fail;
fsFsClose(&device->fs);
return dev;
}
device->setup = 1; 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) if(out_device)
*out_device = device; *out_device = device;
return dev; return dev;
_fail:
fsFsClose(&fs);
return -1;
} }
int fsdevMountDevice(const char *name, FsFileSystem fs) int fsdevMountDevice(const char *name, FsFileSystem fs)
@ -365,13 +364,11 @@ static int _fsdevUnmountDeviceStruct(fsdev_fsdevice *device)
strncat(name, ":", sizeof(name)-strlen(name)-1); strncat(name, ":", sizeof(name)-strlen(name)-1);
RemoveDevice(name); RemoveDevice(name);
free(device->cwd);
fsFsClose(&device->fs); fsFsClose(&device->fs);
if(device->id == fsdev_fsdevice_default)
fsdev_fsdevice_default = -1;
if(device->id == fsdev_fsdevice_cwd) if(device->id == fsdev_fsdevice_cwd)
fsdev_fsdevice_cwd = fsdev_fsdevice_default; fsdev_fsdevice_cwd = -1;
device->setup = 0; device->setup = 0;
memset(device->name, 0, sizeof(device->name)); memset(device->name, 0, sizeof(device->name));
@ -402,7 +399,7 @@ Result fsdevCommitDevice(const char *name)
} }
Result fsdevSetArchiveBit(const char *path) { Result fsdevSetArchiveBit(const char *path) {
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = NULL;
if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) 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) { 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; fsdev_fsdevice *device = NULL;
if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) 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) { Result fsdevDeleteDirectoryRecursively(const char *path) {
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = NULL;
if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1)
@ -434,72 +431,49 @@ Result fsdevDeleteDirectoryRecursively(const char *path) {
/*! Initialize SDMC device */ /*! Initialize SDMC device */
Result fsdevMountSdmc(void) Result fsdevMountSdmc(void)
{ {
ssize_t units;
uint32_t code;
char *p;
Result rc = 0;
FsFileSystem fs; FsFileSystem fs;
fsdev_fsdevice *device = NULL; Result rc = fsMountSdcard(&fs);
if(fsdevFindDevice("sdmc"))
return 0;
rc = fsMountSdcard(&fs);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
int dev = _fsdevMountDevice("sdmc", fs, &device); int ret = fsdevMountDevice("sdmc", fs);
if(ret==-1)
if(dev != -1) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
{
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);
}
}
}
}
}
} }
return rc; 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 */ /*! Clean up fsdev devices */
Result fsdevUnmountAll(void) Result fsdevUnmountAll(void)
{ {
@ -530,14 +504,6 @@ FsFileSystem* fsdevGetDeviceFileSystem(const char *name)
return &device->fs; 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) int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath)
{ {
fsdev_fsdevice *tmpdev = NULL; fsdev_fsdevice *tmpdev = NULL;
@ -571,8 +537,8 @@ fsdev_open(struct _reent *r,
Result rc; Result rc;
u32 fsdev_flags = 0; u32 fsdev_flags = 0;
u32 attributes = 0; u32 attributes = 0;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(fsdev_getfspath(r, path, &device, fs_path)==-1) if(fsdev_getfspath(r, path, &device, fs_path)==-1)
return -1; return -1;
@ -1025,8 +991,8 @@ fsdev_stat(struct _reent *r,
FsDir fdir; FsDir fdir;
Result rc; Result rc;
int ret=0; int ret=0;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
FsTimeStampRaw timestamps = {0}; FsTimeStampRaw timestamps = {0};
FsDirEntryType type; FsDirEntryType type;
@ -1111,8 +1077,8 @@ fsdev_unlink(struct _reent *r,
const char *name) const char *name)
{ {
Result rc; Result rc;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(fsdev_getfspath(r, name, &device, fs_path)==-1) if(fsdev_getfspath(r, name, &device, fs_path)==-1)
return -1; return -1;
@ -1139,8 +1105,14 @@ fsdev_chdir(struct _reent *r,
{ {
FsDir fd; FsDir fd;
Result rc; Result rc;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(device->cwd==NULL)
{
r->_errno = ENOSYS;
return -1;
}
if(fsdev_getfspath(r, name, &device, fs_path)==-1) if(fsdev_getfspath(r, name, &device, fs_path)==-1)
return -1; return -1;
@ -1149,15 +1121,13 @@ fsdev_chdir(struct _reent *r,
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
fsDirClose(&fd); fsDirClose(&fd);
strncpy(__cwd, fs_path, PATH_MAX); memcpy(device->cwd, fs_path, FS_MAX_PATH);
__cwd[PATH_MAX] = '\0';
size_t __cwd_len = strlen(__cwd); size_t cwdlen = strlen(fs_path);
if (device->cwd[cwdlen-1] != '/' && cwdlen < FS_MAX_PATH-1)
if (__cwd[__cwd_len-1] != '/' && __cwd_len < PATH_MAX)
{ {
__cwd[__cwd_len] = '/'; device->cwd[cwdlen] = '/';
__cwd[__cwd_len+1] = '\0'; device->cwd[cwdlen+1] = '\0';
} }
fsdev_fsdevice_cwd = device->id; fsdev_fsdevice_cwd = device->id;
@ -1184,34 +1154,28 @@ fsdev_rename(struct _reent *r,
{ {
Result rc; Result rc;
FsDirEntryType type; 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_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; 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; return -1;
if(device_old->id != device_new->id) rc = fsFsGetEntryType(&device->fs, fs_path_old, &type);
{
r->_errno = EXDEV;
return -1;
}
rc = fsFsGetEntryType(&device_old->fs, fs_path_old, &type);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
if(type == FsDirEntryType_Dir) 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)) if(R_SUCCEEDED(rc))
return 0; return 0;
} }
else if(type == FsDirEntryType_File) 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)) if(R_SUCCEEDED(rc))
return 0; return 0;
} }
@ -1241,8 +1205,8 @@ fsdev_mkdir(struct _reent *r,
int mode) int mode)
{ {
Result rc; Result rc;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(fsdev_getfspath(r, path, &device, fs_path)==-1) if(fsdev_getfspath(r, path, &device, fs_path)==-1)
return -1; return -1;
@ -1271,8 +1235,8 @@ fsdev_diropen(struct _reent *r,
{ {
FsDir fd; FsDir fd;
Result rc; Result rc;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(fsdev_getfspath(r, path, &device, fs_path)==-1) if(fsdev_getfspath(r, path, &device, fs_path)==-1)
return NULL; return NULL;
@ -1449,8 +1413,8 @@ fsdev_statvfs(struct _reent *r,
struct statvfs *buf) struct statvfs *buf)
{ {
Result rc=0; Result rc=0;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
u64 freespace = 0, total_space = 0; u64 freespace = 0, total_space = 0;
if(fsdev_getfspath(r, path, &device, fs_path)==-1) if(fsdev_getfspath(r, path, &device, fs_path)==-1)
@ -1591,8 +1555,8 @@ fsdev_rmdir(struct _reent *r,
const char *name) const char *name)
{ {
Result rc; Result rc;
char fs_path[FS_MAX_PATH]; char *fs_path = __nx_dev_path_buf;
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = r->deviceData;
if(fsdev_getfspath(r, name, &device, fs_path)==-1) if(fsdev_getfspath(r, name, &device, fs_path)==-1)
return -1; return -1;

View File

@ -102,7 +102,7 @@ typedef struct
u32 childFile; u32 childFile;
} romfs_diriter; } romfs_diriter;
static devoptab_t romFS_devoptab = static const devoptab_t romFS_devoptab =
{ {
.structSize = sizeof(romfs_fileobj), .structSize = sizeof(romfs_fileobj),
.open_r = romfs_open, .open_r = romfs_open,
@ -201,101 +201,63 @@ static void romfs_mountclose(romfs_mount *mount)
romfs_free(mount); romfs_free(mount);
} }
Result romfsMount(const char *name) Result romfsMountSelf(const char *name)
{ {
romfs_mount *mount = romfs_alloc(); // Check whether we are a NSO; if so then just mount the RomFS from the current process
if(mount == NULL) if (envIsNso())
return 99; return romfsMountFromCurrentProcess(name);
if (!envIsNso()) // Otherwise, we are a homebrew NRO and we need to use our embedded RomFS
{ // Retrieve the filename of our NRO
// RomFS embedded in a 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(); // Open the NRO file
if(sdfs==NULL) FsFile nro_file;
{ Result rc = fsFsOpenFile(tmpfs, path_buf, FsOpenMode_Read, &nro_file);
romfs_free(mount); if (R_FAILED(rc))
return 1; return rc;
}
const char* filename = __romfs_path; // Read and parse the header
if (__system_argc > 0 && __system_argv[0]) NroHeader hdr;
filename = __system_argv[0]; u64 readbytes = 0;
if (!filename) rc = fsFileRead(&nro_file, sizeof(NroStart), &hdr, sizeof(hdr), FsReadOption_None, &readbytes);
{ if (R_FAILED(rc) || readbytes != sizeof(hdr)) goto _fail_io;
romfs_free(mount); if (hdr.magic != NROHEADER_MAGIC) goto _fail_io;
return 1;
}
if (strncmp(filename, "sdmc:/", 6) == 0) // Read and parse the asset header
filename += 5; NroAssetHeader asset_header;
else if (strncmp(filename, "nxlink:/", 8) == 0) 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;
strncpy(__nx_dev_path_buf, "/switch", PATH_MAX); if (asset_header.magic != NROASSETHEADER_MAGIC
strncat(__nx_dev_path_buf, filename+7, PATH_MAX); || asset_header.version > NROASSETHEADER_VERSION
__nx_dev_path_buf[PATH_MAX] = 0; || asset_header.romfs.offset == 0
filename = __nx_dev_path_buf; || asset_header.romfs.size == 0)
} goto _fail_io;
else
{
romfs_free(mount);
return 2;
}
Result rc = fsFsOpenFile(sdfs, filename, FsOpenMode_Read, &mount->fd); // Calculate the start offset of the embedded RomFS and mount it
if (R_FAILED(rc)) u64 romfs_offset = hdr.size + asset_header.romfs.offset;
{ return romfsMountFromFile(nro_file, romfs_offset, name);
romfs_free(mount);
return rc;
}
romfsInitMtime(mount); _fail_io:
fsFileClose(&nro_file);
NroHeader hdr; return MAKERESULT(Module_Libnx, LibnxError_IoError);
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;
} }
Result romfsMountFromFile(FsFile file, u64 offset, const char *name) Result romfsMountFromFile(FsFile file, u64 offset, const char *name)
{ {
romfs_mount *mount = romfs_alloc(); romfs_mount *mount = romfs_alloc();
if(mount == NULL) if(mount == NULL)
return 99; return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
mount->fd_type = RomfsSource_FsFile; mount->fd_type = RomfsSource_FsFile;
mount->fd = file; mount->fd = file;
@ -308,7 +270,7 @@ Result romfsMountFromStorage(FsStorage storage, u64 offset, const char *name)
{ {
romfs_mount *mount = romfs_alloc(); romfs_mount *mount = romfs_alloc();
if(mount == NULL) if(mount == NULL)
return 99; return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
mount->fd_type = RomfsSource_FsStorage; mount->fd_type = RomfsSource_FsStorage;
mount->fd_storage = storage; mount->fd_storage = storage;
@ -330,21 +292,17 @@ Result romfsMountFromCurrentProcess(const char *name) {
Result romfsMountFromFsdev(const char *path, u64 offset, const char *name) Result romfsMountFromFsdev(const char *path, u64 offset, const char *name)
{ {
FsFileSystem *tmpfs = NULL; FsFileSystem *tmpfs = NULL;
char filepath[FS_MAX_PATH]; if(fsdevTranslatePath(path, &tmpfs, __nx_dev_path_buf)==-1)
memset(filepath, 0, sizeof(filepath));
if(fsdevTranslatePath(path, &tmpfs, filepath)==-1)
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
romfs_mount *mount = romfs_alloc(); romfs_mount *mount = romfs_alloc();
if(mount == NULL) if(mount == NULL)
return 99; return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
mount->fd_type = RomfsSource_FsFile; mount->fd_type = RomfsSource_FsFile;
mount->offset = offset; 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)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
@ -369,45 +327,50 @@ Result romfsMountCommon(const char *name, romfs_mount *mount)
memset(mount->name, 0, sizeof(mount->name)); memset(mount->name, 0, sizeof(mount->name));
strncpy(mount->name, name, sizeof(mount->name)-1); strncpy(mount->name, name, sizeof(mount->name)-1);
romfsInitMtime(mount);
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header)) 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); mount->dirHashTable = (u32*)malloc(mount->header.dirHashTableSize);
if (!mount->dirHashTable) if (!mount->dirHashTable)
goto fail; goto fail_oom;
if (!_romfs_read_chk(mount, mount->header.dirHashTableOff, mount->dirHashTable, mount->header.dirHashTableSize)) if (!_romfs_read_chk(mount, mount->header.dirHashTableOff, mount->dirHashTable, mount->header.dirHashTableSize))
goto fail; goto fail_io;
mount->dirTable = malloc(mount->header.dirTableSize); mount->dirTable = malloc(mount->header.dirTableSize);
if (!mount->dirTable) if (!mount->dirTable)
goto fail; goto fail_oom;
if (!_romfs_read_chk(mount, mount->header.dirTableOff, mount->dirTable, mount->header.dirTableSize)) 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); mount->fileHashTable = (u32*)malloc(mount->header.fileHashTableSize);
if (!mount->fileHashTable) if (!mount->fileHashTable)
goto fail; goto fail_oom;
if (!_romfs_read_chk(mount, mount->header.fileHashTableOff, mount->fileHashTable, mount->header.fileHashTableSize)) if (!_romfs_read_chk(mount, mount->header.fileHashTableOff, mount->fileHashTable, mount->header.fileHashTableSize))
goto fail; goto fail_io;
mount->fileTable = malloc(mount->header.fileTableSize); mount->fileTable = malloc(mount->header.fileTableSize);
if (!mount->fileTable) if (!mount->fileTable)
goto fail; goto fail_oom;
if (!_romfs_read_chk(mount, mount->header.fileTableOff, mount->fileTable, mount->header.fileTableSize)) if (!_romfs_read_chk(mount, mount->header.fileTableOff, mount->fileTable, mount->header.fileTableSize))
goto fail; goto fail_io;
mount->cwd = romFS_root(mount); mount->cwd = romFS_root(mount);
// add device if this is the first one
if(AddDevice(&mount->device) < 0) if(AddDevice(&mount->device) < 0)
goto fail; goto fail_oom;
mount->setup = true; mount->setup = true;
return 0; return 0;
fail: fail_oom:
romfs_mountclose(mount); 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) static void romfsInitMtime(romfs_mount *mount)
@ -422,7 +385,7 @@ Result romfsUnmount(const char *name)
mount = romfsFindMount(name); mount = romfsFindMount(name);
if (mount == NULL) if (mount == NULL)
return -1; return MAKERESULT(Module_Libnx, LibnxError_NotFound);
// Remove device // Remove device
memset(tmpname, 0, sizeof(tmpname)); memset(tmpname, 0, sizeof(tmpname));

View File

@ -17,6 +17,7 @@ void virtmemSetup(void);
void newlibSetup(void); void newlibSetup(void);
void argvSetup(void); void argvSetup(void);
void __libnx_init_time(void); void __libnx_init_time(void);
void __libnx_init_cwd(void);
extern u32 __nx_applet_type; extern u32 __nx_applet_type;
@ -141,6 +142,7 @@ void __attribute__((weak)) __appInit(void)
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
fsdevMountSdmc(); fsdevMountSdmc();
__libnx_init_cwd();
if (&__nx_win_init) __nx_win_init(); if (&__nx_win_init) __nx_win_init();
if (&userAppInit) userAppInit(); if (&userAppInit) userAppInit();