mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 17:24:03 +02:00
Update fs.
This commit is contained in:
Vendored
+100
-77
@@ -2105,8 +2105,15 @@ FS_API fs_result fs_mkdir(fs* pFS, const char* pPath)
|
|||||||
char* pRunningPath = pRunningPathStack;
|
char* pRunningPath = pRunningPathStack;
|
||||||
size_t runningPathLen = 0;
|
size_t runningPathLen = 0;
|
||||||
fs_path_iterator iSegment;
|
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;
|
return FS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2144,7 +2151,7 @@ FS_API fs_result fs_mkdir(fs* pFS, const char* pPath)
|
|||||||
runningPathLen += iSegment.segmentLength;
|
runningPathLen += iSegment.segmentLength;
|
||||||
pRunningPath[runningPathLen] = '\0';
|
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. */
|
/* We just pretend to be successful if the directory already exists. */
|
||||||
if (result == FS_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
|
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.
|
prefix that matches the start of the file path.
|
||||||
*/
|
*/
|
||||||
fs_mount_list_iterator iMountPoint;
|
if (pFS != NULL) {
|
||||||
fs_mount_point* pBestMountPoint = NULL;
|
fs_mount_list_iterator iMountPoint;
|
||||||
const char* pBestMountPointPath = NULL;
|
fs_mount_point* pBestMountPoint = NULL;
|
||||||
const char* pBestMountPointFileSubPath = 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)) {
|
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);
|
const char* pFileSubPath = fs_path_trim_base(pFilePath, FS_NULL_TERMINATED, iMountPoint.pMountPointPath, FS_NULL_TERMINATED);
|
||||||
if (pFileSubPath == NULL) {
|
if (pFileSubPath == NULL) {
|
||||||
continue; /* The file path doesn't start with this mount point so skip. */
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_path_append(pActualPathHeap, actualPathLen + 1, pBestMountPointPath, pBestMountPoint->pathLen, pBestMountPointFileSubPath, FS_NULL_TERMINATED); /* <-- This should never fail. */
|
if (pBestMountPointFileSubPath == NULL || strlen(pFileSubPath) < strlen(pBestMountPointFileSubPath)) {
|
||||||
pActualPath = pActualPathHeap;
|
pBestMountPoint = iMountPoint.internal.pMountPoint;
|
||||||
} else {
|
pBestMountPointPath = iMountPoint.pPath;
|
||||||
pActualPath = pActualPathStack;
|
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. */
|
/* If the mount point starts with a root segment, i.e. "/", we cannot allow navigation above that. */
|
||||||
actualPathCleanLen = fs_path_normalize(pActualPathCleanStack, sizeof(pActualPathCleanStack), pActualPath, FS_NULL_TERMINATED, cleanOptions);
|
if (pBestMountPointPath[0] == '/' || pBestMountPointPath[0] == '\\') {
|
||||||
if (actualPathCleanLen < 0) {
|
cleanOptions |= FS_NO_ABOVE_ROOT_NAVIGATION;
|
||||||
fs_free(pActualPathHeap, fs_get_allocation_callbacks(pFS));
|
}
|
||||||
return FS_INVALID_OPERATION; /* Most likely violating FS_NO_ABOVE_ROOT_NAVIGATION. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actualPathCleanLen >= (int)sizeof(pActualPathCleanStack)) {
|
|
||||||
pActualPathCleanHeap = (char*)fs_malloc(actualPathCleanLen + 1, fs_get_allocation_callbacks(pFS));
|
/* Here is where we append the cleaned sub-path to the mount points actual path. */
|
||||||
if (pActualPathCleanHeap == NULL) {
|
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));
|
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. */
|
if (actualPathCleanLen >= (int)sizeof(pActualPathCleanStack)) {
|
||||||
pActualPathClean = pActualPathCleanHeap;
|
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 {
|
} else {
|
||||||
pActualPathClean = pActualPathCleanStack;
|
return FS_DOES_NOT_EXIST; /* Couldn't find an appropriate mount point. */
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
} 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 {
|
} else {
|
||||||
/* Opening in read mode. */
|
/* Opening in read mode. */
|
||||||
|
|||||||
Vendored
+6
-1
@@ -267,9 +267,14 @@ be saved:
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
fs_file_open(pFS, "config/game.cfg", FS_WRITE, &pFile); // Prefixed with "config", so will use the "config" mount point.
|
fs_file_open(pFS, "config/game.cfg", FS_WRITE, &pFile); // Prefixed with "config", so will use the "config" mount point.
|
||||||
fs_file_open(pFs, "saves/save0.sav", FS_WRITE, &pFile); // Prefixed with "saves", so will use the "saves" mount point.
|
fs_file_open(pFS, "saves/save0.sav", FS_WRITE, &pFile); // Prefixed with "saves", so will use the "saves" mount point.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When opening a file for writing, if you pass in NULL for the `pFS` parameter it will open the file
|
||||||
|
like normal using the standard file system. That is it'll work exactly as if you were using stdio
|
||||||
|
`fopen()` and you will not be able use mount points. Keep in mind that there is no notion of a
|
||||||
|
"current directory" in this library so you'll be stuck with the initial working directory.
|
||||||
|
|
||||||
By default, you can move outside the mount point with ".." segments. If you want to disable this
|
By default, you can move outside the mount point with ".." segments. If you want to disable this
|
||||||
functionality, you can use the `FS_NO_ABOVE_ROOT_NAVIGATION` flag:
|
functionality, you can use the `FS_NO_ABOVE_ROOT_NAVIGATION` flag:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user