2016-11-19 09:28:01 +00:00
|
|
|
#include "filesystem/filesystem.h"
|
2017-10-22 00:35:50 +00:00
|
|
|
#include "filesystem/file.h"
|
2018-10-29 19:01:20 +00:00
|
|
|
#include "platform.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "util.h"
|
2016-11-01 00:14:31 +00:00
|
|
|
#include <physfs.h>
|
2017-01-22 02:18:12 +00:00
|
|
|
#include <stdlib.h>
|
2018-07-04 20:51:35 +00:00
|
|
|
#include <string.h>
|
2019-04-05 11:34:21 +00:00
|
|
|
#include <stdio.h>
|
2016-11-07 02:39:16 +00:00
|
|
|
#ifdef __APPLE__
|
2016-11-01 00:14:31 +00:00
|
|
|
#include <mach-o/dyld.h>
|
2019-09-25 04:37:44 +00:00
|
|
|
#include <objc/objc-runtime.h>
|
2017-03-11 09:37:00 +00:00
|
|
|
#endif
|
|
|
|
#if _WIN32
|
2016-11-12 09:19:47 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <initguid.h>
|
|
|
|
#include <KnownFolders.h>
|
|
|
|
#include <ShlObj.h>
|
|
|
|
#include <wchar.h>
|
2017-03-11 09:37:00 +00:00
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <pwd.h>
|
2016-11-01 00:14:31 +00:00
|
|
|
#endif
|
2018-10-25 03:40:11 +00:00
|
|
|
#if LOVR_USE_OCULUS_MOBILE
|
2018-11-07 15:24:44 +00:00
|
|
|
#include "headset/oculus_mobile.h"
|
2018-10-20 19:22:24 +00:00
|
|
|
#endif
|
2016-11-01 00:14:31 +00:00
|
|
|
|
2018-07-19 00:09:47 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
const char lovrDirSep = '\\';
|
|
|
|
#else
|
|
|
|
const char lovrDirSep = '/';
|
|
|
|
#endif
|
2016-11-07 22:30:32 +00:00
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
static struct {
|
|
|
|
bool initialized;
|
2019-06-08 10:45:03 +00:00
|
|
|
bool fused;
|
2019-05-20 10:51:22 +00:00
|
|
|
char* source;
|
|
|
|
const char* identity;
|
|
|
|
char* savePathRelative;
|
|
|
|
char* savePathFull;
|
2019-06-08 10:45:03 +00:00
|
|
|
char requirePath[2][1024];
|
2019-05-20 10:51:22 +00:00
|
|
|
} state;
|
2018-01-26 02:32:16 +00:00
|
|
|
|
2019-09-27 03:19:50 +00:00
|
|
|
// Return the path to a LÖVR archive bundled to the executable.
|
|
|
|
// On most platforms, the zip is appended to the executable file itself.
|
|
|
|
// On macOS, we have to use Objective C to find it inside the .app folder.
|
|
|
|
static bool getBundlePath(char* buffer, size_t size) {
|
|
|
|
#ifdef __APPLE__
|
2019-10-15 20:00:15 +00:00
|
|
|
id extension = ((id(*)(Class, SEL, char*))objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "lovr");
|
|
|
|
id bundle = ((id(*)(Class, SEL))objc_msgSend)(objc_getClass("NSBundle"), sel_registerName("mainBundle"));
|
|
|
|
id path = ((id(*)(id, SEL, char*, id))objc_msgSend)(bundle, sel_registerName("pathForResource:ofType:"), nil, extension);
|
2019-09-27 03:19:50 +00:00
|
|
|
if (path == nil) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-15 20:00:15 +00:00
|
|
|
const char* cpath = ((const char*(*)(id, SEL))objc_msgSend)(path, sel_registerName("UTF8String"));
|
2019-10-14 22:24:02 +00:00
|
|
|
if (!cpath) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-09-27 03:19:50 +00:00
|
|
|
|
2019-10-14 22:24:02 +00:00
|
|
|
size_t length = strlen(cpath);
|
2019-09-27 03:19:50 +00:00
|
|
|
if (length >= size) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buffer, cpath, length);
|
|
|
|
buffer[length] = '\0';
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return lovrFilesystemGetExecutablePath(buffer, size) == 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-11-19 16:08:56 +00:00
|
|
|
bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) {
|
|
|
|
if (state.initialized) return false;
|
2018-02-23 03:18:36 +00:00
|
|
|
state.initialized = true;
|
2018-01-26 02:32:16 +00:00
|
|
|
|
2018-11-13 21:28:56 +00:00
|
|
|
if (!PHYSFS_init(argExe)) {
|
2017-10-22 08:37:06 +00:00
|
|
|
lovrThrow("Could not initialize filesystem: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
2016-11-07 22:30:32 +00:00
|
|
|
|
2019-05-25 02:16:43 +00:00
|
|
|
PHYSFS_permitSymbolicLinks(1);
|
2017-03-11 09:37:00 +00:00
|
|
|
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
|
2019-01-29 10:49:09 +00:00
|
|
|
lovrAssert(state.source, "Out of memory");
|
2016-11-07 22:30:32 +00:00
|
|
|
state.identity = NULL;
|
2019-06-08 10:45:03 +00:00
|
|
|
state.fused = true;
|
2018-10-05 07:40:50 +00:00
|
|
|
lovrFilesystemSetRequirePath("?.lua;?/init.lua;lua_modules/?.lua;lua_modules/?/init.lua;deps/?.lua;deps/?/init.lua");
|
2018-10-05 07:41:22 +00:00
|
|
|
lovrFilesystemSetCRequirePath("??;lua_modules/??;deps/??");
|
2017-03-11 09:37:00 +00:00
|
|
|
|
2019-10-14 23:10:34 +00:00
|
|
|
// Try to mount an archive fused to the executable
|
2019-09-27 03:19:50 +00:00
|
|
|
if (!getBundlePath(state.source, LOVR_PATH_MAX) || !lovrFilesystemMount(state.source, NULL, 1, argRoot)) {
|
2019-06-08 10:45:03 +00:00
|
|
|
state.fused = false;
|
2017-04-02 12:55:21 +00:00
|
|
|
|
2019-09-27 03:19:50 +00:00
|
|
|
// If that didn't work, try loading an archive from the command line
|
2018-11-13 21:28:56 +00:00
|
|
|
if (argGame) {
|
|
|
|
strncpy(state.source, argGame, LOVR_PATH_MAX);
|
2019-09-27 03:19:50 +00:00
|
|
|
if (lovrFilesystemMount(state.source, NULL, 1, argRoot)) {
|
2018-11-19 16:08:56 +00:00
|
|
|
return true;
|
2017-04-02 12:55:21 +00:00
|
|
|
}
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
2017-04-02 12:55:21 +00:00
|
|
|
|
2019-09-27 03:19:50 +00:00
|
|
|
// Otherwise, give up
|
|
|
|
free(state.source);
|
2017-04-02 12:55:21 +00:00
|
|
|
state.source = NULL;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
2018-11-19 16:08:56 +00:00
|
|
|
|
|
|
|
return true;
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFilesystemDestroy() {
|
2018-02-23 03:18:36 +00:00
|
|
|
if (!state.initialized) return;
|
2017-03-11 09:37:00 +00:00
|
|
|
free(state.source);
|
2016-11-08 06:23:13 +00:00
|
|
|
free(state.savePathFull);
|
|
|
|
free(state.savePathRelative);
|
2016-11-01 00:14:31 +00:00
|
|
|
PHYSFS_deinit();
|
2019-05-20 10:51:22 +00:00
|
|
|
memset(&state, 0, sizeof(state));
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemCreateDirectory(const char* path) {
|
|
|
|
return PHYSFS_mkdir(path);
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
2016-11-07 22:31:11 +00:00
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
|
2017-03-11 09:37:00 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
const char* home;
|
|
|
|
if ((home = getenv("HOME")) == NULL) {
|
|
|
|
home = getpwuid(getuid())->pw_dir;
|
2016-11-07 22:31:11 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 01:39:27 +00:00
|
|
|
snprintf(dest, size, "%s/Library/Application Support", home);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2017-03-11 09:37:00 +00:00
|
|
|
#elif _WIN32
|
|
|
|
PWSTR appData = NULL;
|
|
|
|
SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &appData);
|
2017-11-03 02:01:31 +00:00
|
|
|
PHYSFS_utf8FromUtf16(appData, dest, size);
|
2017-03-11 09:37:00 +00:00
|
|
|
CoTaskMemFree(appData);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2017-08-01 19:16:09 +00:00
|
|
|
#elif EMSCRIPTEN
|
2017-04-23 00:02:41 +00:00
|
|
|
strncpy(dest, "/home/web_user", size);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2018-10-25 03:40:11 +00:00
|
|
|
#elif LOVR_USE_OCULUS_MOBILE
|
2018-11-07 15:24:44 +00:00
|
|
|
strncpy(dest, lovrOculusMobileWritablePath, size);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2017-08-01 19:23:33 +00:00
|
|
|
#elif __linux__
|
|
|
|
const char* home;
|
|
|
|
if ((home = getenv("HOME")) == NULL) {
|
|
|
|
home = getpwuid(getuid())->pw_dir;
|
|
|
|
}
|
|
|
|
|
2019-01-25 01:39:27 +00:00
|
|
|
snprintf(dest, size, "%s/.config", home);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2017-03-11 09:37:00 +00:00
|
|
|
#else
|
|
|
|
#error "This platform is missing an implementation for lovrFilesystemGetAppdataDirectory"
|
|
|
|
#endif
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
return false;
|
2016-11-07 22:31:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 23:30:20 +00:00
|
|
|
bool lovrFilesystemGetApplicationId(char* dest, size_t size) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
pid_t pid = getpid();
|
|
|
|
char path[32];
|
|
|
|
snprintf(path, LOVR_PATH_MAX, "/proc/%i/cmdline", (int) pid);
|
|
|
|
FILE* file = fopen(path, "r");
|
|
|
|
if (file) {
|
|
|
|
size_t read = fread(dest, 1, size, file);
|
|
|
|
fclose(file);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata) {
|
2019-03-17 07:58:01 +00:00
|
|
|
PHYSFS_enumerate(path, (PHYSFS_EnumerateCallback) callback, userdata);
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 19:01:20 +00:00
|
|
|
int lovrFilesystemGetExecutablePath(char* path, uint32_t size) {
|
2019-05-20 11:02:25 +00:00
|
|
|
return lovrPlatformGetExecutablePath(path, size);
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
const char* lovrFilesystemGetIdentity() {
|
|
|
|
return state.identity;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
long lovrFilesystemGetLastModified(const char* path) {
|
2017-10-22 08:37:06 +00:00
|
|
|
PHYSFS_Stat stat;
|
|
|
|
return PHYSFS_stat(path, &stat) ? stat.modtime : -1;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
const char* lovrFilesystemGetRealDirectory(const char* path) {
|
2017-03-11 09:37:00 +00:00
|
|
|
return PHYSFS_getRealDir(path);
|
|
|
|
}
|
|
|
|
|
2019-06-08 10:45:03 +00:00
|
|
|
const char* lovrFilesystemGetRequirePath() {
|
|
|
|
return state.requirePath[0];
|
2018-07-07 04:21:07 +00:00
|
|
|
}
|
|
|
|
|
2019-06-08 10:45:03 +00:00
|
|
|
const char* lovrFilesystemGetCRequirePath() {
|
|
|
|
return state.requirePath[1];
|
2018-03-11 23:25:21 +00:00
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
const char* lovrFilesystemGetSaveDirectory() {
|
|
|
|
return state.savePathFull;
|
|
|
|
}
|
|
|
|
|
2017-10-22 00:35:50 +00:00
|
|
|
size_t lovrFilesystemGetSize(const char* path) {
|
2017-10-22 08:37:06 +00:00
|
|
|
PHYSFS_Stat stat;
|
|
|
|
return PHYSFS_stat(path, &stat) ? stat.filesize : -1;
|
2016-11-07 22:30:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* lovrFilesystemGetSource() {
|
2017-03-11 09:37:00 +00:00
|
|
|
return state.source;
|
2016-11-07 22:30:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* lovrFilesystemGetUserDirectory() {
|
2017-10-22 08:37:06 +00:00
|
|
|
#if defined(__APPLE__) || defined(__linux__)
|
|
|
|
const char* home;
|
|
|
|
if ((home = getenv("HOME")) == NULL) {
|
|
|
|
home = getpwuid(getuid())->pw_dir;
|
|
|
|
}
|
|
|
|
return home;
|
|
|
|
#elif _WIN32
|
|
|
|
return getenv("USERPROFILE");
|
|
|
|
#elif EMSCRIPTEN
|
|
|
|
return "/home/web_user";
|
|
|
|
#else
|
|
|
|
#error "This platform is missing an implementation for lovrFilesystemGetUserDirectory"
|
|
|
|
#endif
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemGetWorkingDirectory(char* dest, unsigned int size) {
|
2018-03-19 23:52:17 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
WCHAR w_cwd[LOVR_PATH_MAX];
|
|
|
|
_wgetcwd(w_cwd, LOVR_PATH_MAX);
|
|
|
|
PHYSFS_utf8FromUtf16(w_cwd, dest, size);
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2018-03-19 23:52:17 +00:00
|
|
|
#else
|
|
|
|
if (getcwd(dest, size)) {
|
2019-05-20 10:51:22 +00:00
|
|
|
return true;
|
2018-03-19 23:52:17 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-05-20 10:51:22 +00:00
|
|
|
return false;
|
2018-03-19 23:52:17 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrFilesystemIsDirectory(const char* path) {
|
2017-10-22 08:37:06 +00:00
|
|
|
PHYSFS_Stat stat;
|
2017-10-31 08:14:09 +00:00
|
|
|
return PHYSFS_stat(path, &stat) ? stat.filetype == PHYSFS_FILETYPE_DIRECTORY : false;
|
2016-11-01 01:35:00 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrFilesystemIsFile(const char* path) {
|
2017-10-22 08:37:06 +00:00
|
|
|
PHYSFS_Stat stat;
|
2017-10-31 08:14:09 +00:00
|
|
|
return PHYSFS_stat(path, &stat) ? stat.filetype == PHYSFS_FILETYPE_REGULAR : false;
|
2016-11-01 01:35:00 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrFilesystemIsFused() {
|
2019-06-08 10:45:03 +00:00
|
|
|
return state.fused;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 20:20:04 +00:00
|
|
|
// Returns zero on success, nonzero on failure
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append, const char* root) {
|
2018-11-13 20:20:04 +00:00
|
|
|
bool success = PHYSFS_mount(path, mountpoint, append);
|
2018-11-14 02:55:33 +00:00
|
|
|
if (success && root) {
|
|
|
|
success = PHYSFS_setRoot(path, root);
|
2018-11-13 20:20:04 +00:00
|
|
|
}
|
2019-05-20 10:51:22 +00:00
|
|
|
return success;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 09:58:43 +00:00
|
|
|
void* lovrFilesystemRead(const char* path, size_t bytes, size_t* bytesRead) {
|
2018-12-19 09:49:15 +00:00
|
|
|
File file;
|
2019-06-08 10:45:03 +00:00
|
|
|
lovrFileInit(&file, path);
|
2016-11-02 03:27:15 +00:00
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
if (!lovrFileOpen(&file, OPEN_READ)) {
|
2017-10-22 03:23:29 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-10-22 00:35:50 +00:00
|
|
|
|
2019-03-05 09:58:43 +00:00
|
|
|
// Get file size if no size was specified
|
|
|
|
if (bytes == (size_t) -1) {
|
|
|
|
bytes = lovrFileGetSize(&file);
|
|
|
|
if (bytes == (size_t) -1) {
|
|
|
|
lovrFileDestroy(&file);
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-11-05 22:55:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate buffer
|
2019-03-05 09:58:43 +00:00
|
|
|
void* data = malloc(bytes);
|
2016-11-05 22:55:01 +00:00
|
|
|
if (!data) {
|
2018-12-19 09:49:15 +00:00
|
|
|
lovrFileDestroy(&file);
|
2016-11-05 22:55:01 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform read
|
2019-03-05 09:58:43 +00:00
|
|
|
*bytesRead = lovrFileRead(&file, data, bytes);
|
2018-12-19 09:49:15 +00:00
|
|
|
lovrFileDestroy(&file);
|
2016-11-02 03:27:15 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemRemove(const char* path) {
|
|
|
|
return PHYSFS_delete(path);
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemSetIdentity(const char* identity) {
|
2016-11-07 22:30:32 +00:00
|
|
|
state.identity = identity;
|
|
|
|
|
|
|
|
// Unmount old write directory
|
|
|
|
if (state.savePathFull && state.savePathRelative) {
|
2017-10-22 08:37:06 +00:00
|
|
|
PHYSFS_unmount(state.savePathRelative);
|
2016-11-07 22:30:32 +00:00
|
|
|
} else {
|
|
|
|
state.savePathRelative = malloc(LOVR_PATH_MAX);
|
|
|
|
state.savePathFull = malloc(LOVR_PATH_MAX);
|
2019-01-29 10:49:09 +00:00
|
|
|
lovrAssert(state.savePathRelative && state.savePathFull, "Out of memory");
|
2017-03-11 09:37:00 +00:00
|
|
|
if (!state.savePathRelative || !state.savePathFull) {
|
2019-05-20 10:51:22 +00:00
|
|
|
return false;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
2016-11-07 22:30:32 +00:00
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
lovrFilesystemGetAppdataDirectory(state.savePathFull, LOVR_PATH_MAX);
|
2017-11-03 02:01:31 +00:00
|
|
|
if (!PHYSFS_setWriteDir(state.savePathFull)) {
|
|
|
|
const char* error = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
|
|
|
|
lovrThrow("Could not set write directory: %s (%s)", error, state.savePathFull);
|
|
|
|
}
|
|
|
|
|
2019-01-25 01:39:27 +00:00
|
|
|
snprintf(state.savePathRelative, LOVR_PATH_MAX, "LOVR/%s", identity ? identity : "default");
|
2017-08-01 19:23:33 +00:00
|
|
|
char fullPathBuffer[LOVR_PATH_MAX];
|
2019-01-25 01:39:27 +00:00
|
|
|
snprintf(fullPathBuffer, LOVR_PATH_MAX, "%s/%s", state.savePathFull, state.savePathRelative);
|
2017-08-01 19:23:33 +00:00
|
|
|
strncpy(state.savePathFull, fullPathBuffer, LOVR_PATH_MAX);
|
2017-03-11 09:37:00 +00:00
|
|
|
PHYSFS_mkdir(state.savePathRelative);
|
2017-03-11 09:58:11 +00:00
|
|
|
if (!PHYSFS_setWriteDir(state.savePathFull)) {
|
2017-10-22 08:37:06 +00:00
|
|
|
const char* error = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
|
|
|
|
lovrThrow("Could not set write directory: %s (%s)", error, state.savePathRelative);
|
2017-03-11 09:58:11 +00:00
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
return PHYSFS_mount(state.savePathFull, NULL, 0);
|
2016-11-07 22:30:32 +00:00
|
|
|
}
|
|
|
|
|
2018-07-07 04:21:07 +00:00
|
|
|
void lovrFilesystemSetRequirePath(const char* requirePath) {
|
2019-06-08 10:45:03 +00:00
|
|
|
strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1);
|
2018-07-07 04:21:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFilesystemSetCRequirePath(const char* requirePath) {
|
2019-06-08 10:45:03 +00:00
|
|
|
strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1);
|
2018-07-07 04:21:07 +00:00
|
|
|
}
|
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
bool lovrFilesystemUnmount(const char* path) {
|
|
|
|
return PHYSFS_unmount(path);
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
2016-11-07 22:31:02 +00:00
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, bool append) {
|
2018-12-19 09:49:15 +00:00
|
|
|
File file;
|
|
|
|
lovrFileInit(memset(&file, 0, sizeof(File)), path);
|
2016-11-07 22:31:02 +00:00
|
|
|
|
2019-05-20 10:51:22 +00:00
|
|
|
if (!lovrFileOpen(&file, append ? OPEN_APPEND : OPEN_WRITE)) {
|
2018-10-29 02:46:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-19 09:49:15 +00:00
|
|
|
size_t bytesWritten = lovrFileWrite(&file, (void*) content, size);
|
2019-07-11 01:45:36 +00:00
|
|
|
lovrFileDestroy(&file);
|
|
|
|
return bytesWritten;
|
2016-11-07 22:31:02 +00:00
|
|
|
}
|