Update fs.

This commit is contained in:
David Reid
2025-02-23 18:14:04 +10:00
parent 1a83b0baa4
commit e272f56750
2 changed files with 107 additions and 79 deletions
+101 -78
View File
@@ -2105,8 +2105,15 @@ FS_API fs_result fs_mkdir(fs* pFS, const char* pPath)
char* pRunningPath = pRunningPathStack;
size_t runningPathLen = 0;
fs_path_iterator iSegment;
const fs_backend* pBackend;
if (pFS == NULL || pPath == NULL) {
pBackend = fs_get_backend_or_default(pFS);
if (pBackend == NULL) {
return FS_INVALID_ARGS;
}
if (pPath == NULL) {
return FS_INVALID_ARGS;
}
@@ -2144,7 +2151,7 @@ FS_API fs_result fs_mkdir(fs* pFS, const char* pPath)
runningPathLen += iSegment.segmentLength;
pRunningPath[runningPathLen] = '\0';
result = fs_backend_mkdir(pFS->pBackend, pFS, pRunningPath);
result = fs_backend_mkdir(pBackend, pFS, pRunningPath);
/* We just pretend to be successful if the directory already exists. */
if (result == FS_ALREADY_EXISTS) {
@@ -3040,94 +3047,110 @@ FS_API fs_result fs_file_open_or_info(fs* pFS, const char* pFilePath, int openMo
We'll need to iterate over every mount point and keep track of the mount point with the longest
prefix that matches the start of the file path.
*/
fs_mount_list_iterator iMountPoint;
fs_mount_point* pBestMountPoint = NULL;
const char* pBestMountPointPath = NULL;
const char* pBestMountPointFileSubPath = NULL;
for (mountPointIerationResult = fs_mount_list_first(pFS->pWriteMountPoints, &iMountPoint); mountPointIerationResult == FS_SUCCESS; mountPointIerationResult = fs_mount_list_next(&iMountPoint)) {
const char* pFileSubPath = fs_path_trim_base(pFilePath, FS_NULL_TERMINATED, iMountPoint.pMountPointPath, FS_NULL_TERMINATED);
if (pFileSubPath == NULL) {
continue; /* The file path doesn't start with this mount point so skip. */
}
if (pBestMountPointFileSubPath == NULL || strlen(pFileSubPath) < strlen(pBestMountPointFileSubPath)) {
pBestMountPoint = iMountPoint.internal.pMountPoint;
pBestMountPointPath = iMountPoint.pPath;
pBestMountPointFileSubPath = pFileSubPath;
}
}
if (pBestMountPoint != NULL) {
char pActualPathStack[1024];
char* pActualPathHeap = NULL;
char* pActualPath;
int actualPathLen;
char pActualPathCleanStack[1024];
char* pActualPathCleanHeap = NULL;
char* pActualPathClean;
int actualPathCleanLen;
unsigned int cleanOptions = (openMode & FS_NO_ABOVE_ROOT_NAVIGATION);
/* If the mount point starts with a root segment, i.e. "/", we cannot allow navigation above that. */
if (pBestMountPointPath[0] == '/' || pBestMountPointPath[0] == '\\') {
cleanOptions |= FS_NO_ABOVE_ROOT_NAVIGATION;
}
/* Here is where we append the cleaned sub-path to the mount points actual path. */
actualPathLen = fs_path_append(pActualPathStack, sizeof(pActualPathStack), pBestMountPointPath, pBestMountPoint->pathLen, pBestMountPointFileSubPath, FS_NULL_TERMINATED);
if (actualPathLen > 0 && (size_t)actualPathLen >= sizeof(pActualPathStack)) {
/* Not enough room on the stack. Allocate on the heap. */
pActualPathHeap = (char*)fs_malloc(actualPathLen + 1, fs_get_allocation_callbacks(pFS));
if (pActualPathHeap == NULL) {
return FS_OUT_OF_MEMORY;
if (pFS != NULL) {
fs_mount_list_iterator iMountPoint;
fs_mount_point* pBestMountPoint = NULL;
const char* pBestMountPointPath = NULL;
const char* pBestMountPointFileSubPath = NULL;
for (mountPointIerationResult = fs_mount_list_first(pFS->pWriteMountPoints, &iMountPoint); mountPointIerationResult == FS_SUCCESS; mountPointIerationResult = fs_mount_list_next(&iMountPoint)) {
const char* pFileSubPath = fs_path_trim_base(pFilePath, FS_NULL_TERMINATED, iMountPoint.pMountPointPath, FS_NULL_TERMINATED);
if (pFileSubPath == NULL) {
continue; /* The file path doesn't start with this mount point so skip. */
}
fs_path_append(pActualPathHeap, actualPathLen + 1, pBestMountPointPath, pBestMountPoint->pathLen, pBestMountPointFileSubPath, FS_NULL_TERMINATED); /* <-- This should never fail. */
pActualPath = pActualPathHeap;
} else {
pActualPath = pActualPathStack;
if (pBestMountPointFileSubPath == NULL || strlen(pFileSubPath) < strlen(pBestMountPointFileSubPath)) {
pBestMountPoint = iMountPoint.internal.pMountPoint;
pBestMountPointPath = iMountPoint.pPath;
pBestMountPointFileSubPath = pFileSubPath;
}
}
if (pBestMountPoint != NULL) {
char pActualPathStack[1024];
char* pActualPathHeap = NULL;
char* pActualPath;
int actualPathLen;
char pActualPathCleanStack[1024];
char* pActualPathCleanHeap = NULL;
char* pActualPathClean;
int actualPathCleanLen;
unsigned int cleanOptions = (openMode & FS_NO_ABOVE_ROOT_NAVIGATION);
/* Now we need to clean the path. */
actualPathCleanLen = fs_path_normalize(pActualPathCleanStack, sizeof(pActualPathCleanStack), pActualPath, FS_NULL_TERMINATED, cleanOptions);
if (actualPathCleanLen < 0) {
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
return FS_INVALID_OPERATION; /* Most likely violating FS_NO_ABOVE_ROOT_NAVIGATION. */
}
/* If the mount point starts with a root segment, i.e. "/", we cannot allow navigation above that. */
if (pBestMountPointPath[0] == '/' || pBestMountPointPath[0] == '\\') {
cleanOptions |= FS_NO_ABOVE_ROOT_NAVIGATION;
}
if (actualPathCleanLen >= (int)sizeof(pActualPathCleanStack)) {
pActualPathCleanHeap = (char*)fs_malloc(actualPathCleanLen + 1, fs_get_allocation_callbacks(pFS));
if (pActualPathCleanHeap == NULL) {
/* Here is where we append the cleaned sub-path to the mount points actual path. */
actualPathLen = fs_path_append(pActualPathStack, sizeof(pActualPathStack), pBestMountPointPath, pBestMountPoint->pathLen, pBestMountPointFileSubPath, FS_NULL_TERMINATED);
if (actualPathLen > 0 && (size_t)actualPathLen >= sizeof(pActualPathStack)) {
/* Not enough room on the stack. Allocate on the heap. */
pActualPathHeap = (char*)fs_malloc(actualPathLen + 1, fs_get_allocation_callbacks(pFS));
if (pActualPathHeap == NULL) {
return FS_OUT_OF_MEMORY;
}
fs_path_append(pActualPathHeap, actualPathLen + 1, pBestMountPointPath, pBestMountPoint->pathLen, pBestMountPointFileSubPath, FS_NULL_TERMINATED); /* <-- This should never fail. */
pActualPath = pActualPathHeap;
} else {
pActualPath = pActualPathStack;
}
/* Now we need to clean the path. */
actualPathCleanLen = fs_path_normalize(pActualPathCleanStack, sizeof(pActualPathCleanStack), pActualPath, FS_NULL_TERMINATED, cleanOptions);
if (actualPathCleanLen < 0) {
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
return FS_OUT_OF_MEMORY;
return FS_INVALID_OPERATION; /* Most likely violating FS_NO_ABOVE_ROOT_NAVIGATION. */
}
fs_path_normalize(pActualPathCleanHeap, actualPathCleanLen + 1, pActualPath, FS_NULL_TERMINATED, cleanOptions); /* <-- This should never fail. */
pActualPathClean = pActualPathCleanHeap;
if (actualPathCleanLen >= (int)sizeof(pActualPathCleanStack)) {
pActualPathCleanHeap = (char*)fs_malloc(actualPathCleanLen + 1, fs_get_allocation_callbacks(pFS));
if (pActualPathCleanHeap == NULL) {
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
return FS_OUT_OF_MEMORY;
}
fs_path_normalize(pActualPathCleanHeap, actualPathCleanLen + 1, pActualPath, FS_NULL_TERMINATED, cleanOptions); /* <-- This should never fail. */
pActualPathClean = pActualPathCleanHeap;
} else {
pActualPathClean = pActualPathCleanStack;
}
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
pActualPathHeap = NULL;
/* We now have enough information to open the file. */
result = fs_file_alloc_if_necessary_and_open_or_info(pFS, pActualPathClean, openMode, ppFile, pInfo);
fs_free(pActualPathCleanHeap, fs_get_allocation_callbacks(pFS));
pActualPathCleanHeap = NULL;
if (result == FS_SUCCESS) {
return FS_SUCCESS;
} else {
return FS_DOES_NOT_EXIST; /* Couldn't find the file from the best mount point. */
}
} else {
pActualPathClean = pActualPathCleanStack;
}
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
pActualPathHeap = NULL;
/* We now have enough information to open the file. */
result = fs_file_alloc_if_necessary_and_open_or_info(pFS, pActualPathClean, openMode, ppFile, pInfo);
fs_free(pActualPathCleanHeap, fs_get_allocation_callbacks(pFS));
pActualPathCleanHeap = NULL;
if (result == FS_SUCCESS) {
return FS_SUCCESS;
} else {
return FS_DOES_NOT_EXIST; /* Couldn't find the file from the best mount point. */
return FS_DOES_NOT_EXIST; /* Couldn't find an appropriate mount point. */
}
} else {
return FS_DOES_NOT_EXIST; /* Couldn't find an appropriate mount point. */
/*
No "fs" object was supplied. Open using the default backend without using mount points. This is as if you were
opening a file using `fopen()`.
*/
if ((openMode & FS_ONLY_MOUNTS) == 0) {
return fs_file_alloc_if_necessary_and_open_or_info(pFS, pFilePath, openMode, ppFile, pInfo);
} else {
/*
Getting here means only the mount points can be used to open the file (cannot open straight from
the file system natively).
*/
return FS_DOES_NOT_EXIST;
}
}
} else {
/* Opening in read mode. */