create a single fetchfs backend instead of 1 per file

symlinking manifest entries and using a baseurl gives us a way to
create just a single fetchfs backend (and a single thread) since
emscripten upstream is not willing to integrate manifest support to
fetchfs directly.

Retroarch embedders could use this to get assets or other resources
lazily or chunk-by-chunk for large files.
This commit is contained in:
Joseph C. Osborn 2025-03-10 14:55:54 -07:00
parent 9e64cce10f
commit 809e5d78be
1 changed files with 59 additions and 33 deletions

View File

@ -491,6 +491,7 @@ void platform_emscripten_mount_filesystems(void)
{ {
char *opfs_mount = getenv("OPFS_MOUNT"); char *opfs_mount = getenv("OPFS_MOUNT");
char *fetch_manifest = getenv("FETCH_MANIFEST"); char *fetch_manifest = getenv("FETCH_MANIFEST");
char *fetch_base_dir = getenv("FETCH_BASE_DIR");
if (opfs_mount) if (opfs_mount)
{ {
int res; int res;
@ -518,20 +519,23 @@ void platform_emscripten_mount_filesystems(void)
abort(); abort();
} }
} }
if (fetch_manifest || fetch_base_dir)
if (fetch_manifest)
{ {
/* fetch_manifest should be a path to a manifest file. /* fetch_manifest should be a path to a manifest file.
manifest files have this format: manifest files have this format:
BASEURL
URL PATH URL PATH
URL PATH URL PATH
URL PATH URL PATH
... ...
Where URL may not contain spaces, but PATH may. Where URL may not contain spaces, but PATH may.
URL segments are relative to BASEURL.
*/ */
int max_line_len = 1024; int max_line_len = 1024;
if (!(fetch_manifest && fetch_base_dir))
printf("[FetchFS] must specify both FETCH_MANIFEST and FETCH_BASE_DIR\n");
printf("[FetchFS] read fetch manifest from %s\n", fetch_manifest); printf("[FetchFS] read fetch manifest from %s\n", fetch_manifest);
FILE *file = fopen(fetch_manifest, "r"); FILE *file = fopen(fetch_manifest, "r");
if (!file) if (!file)
@ -541,44 +545,66 @@ void platform_emscripten_mount_filesystems(void)
} }
char *line = calloc(sizeof(char), max_line_len); char *line = calloc(sizeof(char), max_line_len);
size_t len = max_line_len; size_t len = max_line_len;
while (getline(&line, &len, file) != -1) if (getline(&line, &len, file) == -1 || len == 0)
printf("[FetchFS] missing base URL, skipping fetch initialization\n");
else
{ {
char *path = strstr(line, " "); char *base_url = strdup(line);
backend_t fetch; backend_t fetch;
int fd; // Don't create fetch backend unless manifest actually has entries
if (len <= 2 || !path) while (getline(&line, &len, file) != -1)
{ {
printf("[FetchFS] Manifest file has invalid line %s\n", line); if (!fetch)
continue;
}
*path = '\0';
path += 1;
path[strcspn(path, "\r\n")] = '\0';
printf("[FetchFS] Fetch %s from %s\n", path, line);
{
char *parent = strdup(path);
path_parent_dir(parent, strlen(parent));
if (!path_mkdir(parent))
{ {
printf("[FetchFS] mkdir error %d\n", errno); fetch = wasmfs_create_fetch_backend(base_url, 16*1024*1024);
wasmfs_create_directory(fetch_base_dir, 0777, fetch);
}
char *realfs_path = strstr(line, " "), *url = line;
int fd;
if(len <= 2 || !realfs_path)
{
printf("[FetchFS] Manifest file has invalid line %s\n",line);
continue;
}
*realfs_path = '\0';
realfs_path += 1;
realfs_path[strcspn(realfs_path, "\r\n")] = '\0';
printf("[FetchFS] Fetch %s from URL %s / %s, fetched path %s / %s\n", realfs_path, base_url, url, fetch_base_dir, url);
char fetchfs_path[PATH_MAX];
fill_pathname_join(fetchfs_path, fetch_base_dir, url, sizeof(fetchfs_path));
/* Make the directories for link path */
{
char *parent = strdup(realfs_path);
path_parent_dir(parent, strlen(parent));
if(!path_mkdir(parent)) {
printf("[FetchFS] mkdir error %s %d\n", realfs_path, errno);
abort();
}
free(parent);
}
/* Make the directories for URL path */
{
char *parent = strdup(fetchfs_path);
path_parent_dir(parent, strlen(parent));
if(!path_mkdir(parent)) {
printf("[FetchFS] mkdir error %s %d\n", fetchfs_path, errno);
abort();
}
free(parent);
}
fd = open(fetchfs_path, O_CREAT);
if(!fd) {
printf("[FetchFS] couldn't create fetch file %s\n", fetchfs_path);
abort(); abort();
} }
free(parent); close(fd);
if(symlink(fetchfs_path, realfs_path) != 0) {
printf("[FetchFS] couldn't create link %s to fetch file %s (errno %d)\n", realfs_path, fetchfs_path, errno);
abort();
}
len = max_line_len;
} }
fetch = wasmfs_create_fetch_backend(line, 16*1024*1024); free(base_url);
if (!fetch)
{
printf("[FetchFS] couldn't create fetch backend\n");
abort();
}
fd = wasmfs_create_file(path, 0777, fetch);
if (!fd)
{
printf("[FetchFS] couldn't create fetch file\n");
abort();
}
close(fd);
len = max_line_len;
} }
fclose(file); fclose(file);
free(line); free(line);