lovr/src/filesystem/filesystem.c

261 lines
6.1 KiB
C
Raw Normal View History

2016-11-19 09:28:01 +00:00
#include "filesystem/filesystem.h"
2017-10-22 00:35:50 +00:00
#include "filesystem/file.h"
2016-11-19 09:28:01 +00:00
#include "util.h"
2016-11-01 00:14:31 +00:00
#include <physfs.h>
2016-11-07 22:30:32 +00:00
#include <stdio.h>
2017-01-22 02:18:12 +00:00
#include <stdlib.h>
2016-11-07 02:39:16 +00:00
#ifdef __APPLE__
2016-11-01 00:14:31 +00:00
#include <mach-o/dyld.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
2016-11-07 22:30:32 +00:00
static FilesystemState state;
2017-03-11 09:37:00 +00:00
void lovrFilesystemInit(const char* arg0, const char* arg1) {
2016-11-01 00:14:31 +00:00
if (!PHYSFS_init(arg0)) {
lovrThrow("Could not initialize filesystem: %s", PHYSFS_getLastError());
2016-11-01 00:14:31 +00:00
}
2016-11-07 22:30:32 +00:00
2017-03-11 09:37:00 +00:00
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
2016-11-07 22:30:32 +00:00
state.identity = NULL;
2017-03-11 09:37:00 +00:00
state.isFused = 1;
// Try to mount either an archive fused to the executable or an archive from the command line
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
2017-04-02 12:55:21 +00:00
if (lovrFilesystemMount(state.source, NULL, 1)) {
2017-03-11 09:37:00 +00:00
state.isFused = 0;
2017-04-02 12:55:21 +00:00
if (arg1) {
strncpy(state.source, arg1, LOVR_PATH_MAX);
if (!lovrFilesystemMount(state.source, NULL, 1)) {
goto mounted;
}
2017-03-11 09:37:00 +00:00
}
2017-04-02 12:55:21 +00:00
free(state.source);
state.source = NULL;
2017-03-11 09:37:00 +00:00
}
2017-04-02 12:55:21 +00:00
mounted:
2017-01-22 02:18:12 +00:00
atexit(lovrFilesystemDestroy);
2016-11-01 00:14:31 +00:00
}
void lovrFilesystemDestroy() {
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();
}
2017-03-11 09:37:00 +00:00
int lovrFilesystemCreateDirectory(const char* path) {
return !PHYSFS_mkdir(path);
}
2016-11-07 22:31:11 +00:00
2017-03-11 09:37:00 +00:00
int lovrFilesystemExists(const char* path) {
return PHYSFS_exists(path);
}
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
#ifdef __APPLE__
const char* home;
if ((home = getenv("HOME")) == NULL) {
home = getpwuid(getuid())->pw_dir;
2016-11-07 22:31:11 +00:00
}
2017-03-11 09:37:00 +00:00
snprintf(dest, size, "%s/Library/Application Support", home);
return 0;
#elif _WIN32
PWSTR appData = NULL;
SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &appData);
wcstombs(dest, appData, size);
CoTaskMemFree(appData);
return 0;
#elif EMSCRIPTEN
2017-04-23 00:02:41 +00:00
strncpy(dest, "/home/web_user", size);
2017-04-16 23:56:49 +00:00
return 0;
2017-08-01 19:23:33 +00:00
#elif __linux__
const char* home;
if ((home = getenv("HOME")) == NULL) {
home = getpwuid(getuid())->pw_dir;
}
snprintf(dest, size, "%s/.config", home);
2017-03-11 09:37:00 +00:00
#else
#error "This platform is missing an implementation for lovrFilesystemGetAppdataDirectory"
#endif
return 1;
2016-11-07 22:31:11 +00:00
}
2017-03-11 09:37:00 +00:00
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata) {
PHYSFS_enumerateFilesCallback(path, callback, userdata);
2016-11-01 00:14:31 +00:00
}
2016-11-07 22:30:32 +00:00
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size) {
2016-11-07 02:39:16 +00:00
#ifdef __APPLE__
2016-11-07 22:30:32 +00:00
if (_NSGetExecutablePath(dest, &size) == 0) {
return 0;
2016-11-01 00:14:31 +00:00
}
2016-11-14 22:16:16 +00:00
#elif _WIN32
2016-11-12 09:19:47 +00:00
return !GetModuleFileName(NULL, dest, size);
#elif EMSCRIPTEN
2017-04-16 23:56:49 +00:00
return 1;
2017-08-01 19:23:33 +00:00
#elif __linux__
memset(dest, 0, size);
if (readlink("/proc/self/exe", dest, size) == -1) {
return 1;
2017-08-01 19:23:33 +00:00
}
2016-11-14 22:16:16 +00:00
#else
#error "This platform is missing an implementation for lovrFilesystemGetExecutablePath"
2016-11-01 00:14:31 +00:00
#endif
2016-11-07 22:30:32 +00:00
return 1;
}
const char* lovrFilesystemGetIdentity() {
return state.identity;
}
2017-03-11 09:37:00 +00:00
long lovrFilesystemGetLastModified(const char* path) {
return PHYSFS_getLastModTime(path);
}
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);
}
const char* lovrFilesystemGetSaveDirectory() {
return state.savePathFull;
}
2017-10-22 00:35:50 +00:00
size_t lovrFilesystemGetSize(const char* path) {
File* file = lovrFileCreate(path);
lovrFileOpen(file, OPEN_READ);
size_t size = lovrFileGetSize(file);
lovrFileClose(file);
lovrRelease(&file->ref);
return size;
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() {
return PHYSFS_getUserDir();
2016-11-01 00:14:31 +00:00
}
2016-11-01 01:35:00 +00:00
int lovrFilesystemIsDirectory(const char* path) {
return PHYSFS_isDirectory(path);
}
int lovrFilesystemIsFile(const char* path) {
return lovrFilesystemExists(path) && !lovrFilesystemIsDirectory(path);
}
2017-03-11 09:37:00 +00:00
int lovrFilesystemIsFused() {
return state.isFused;
}
int lovrFilesystemMount(const char* path, const char* mountpoint, int append) {
return !PHYSFS_mount(path, mountpoint, append);
}
void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
2016-11-02 03:27:15 +00:00
2017-10-22 00:35:50 +00:00
// Create file
File* file = lovrFileCreate(path);
2017-10-21 07:19:05 +00:00
if (!file) {
2016-11-02 03:27:15 +00:00
return NULL;
}
2017-10-22 00:35:50 +00:00
// Open it
2017-10-22 03:23:29 +00:00
if (lovrFileOpen(file, OPEN_READ)) {
return NULL;
}
2017-10-22 00:35:50 +00:00
2016-11-05 22:55:01 +00:00
// Get file size
2017-10-22 00:35:50 +00:00
size_t size = lovrFileGetSize(file);
if (size == (unsigned int) -1) {
2016-11-05 22:55:01 +00:00
return NULL;
}
// Allocate buffer
void* data = malloc(size);
if (!data) {
return NULL;
}
// Perform read
2017-10-22 00:35:50 +00:00
*bytesRead = lovrFileRead(file, data, 1, size);
lovrFileClose(file);
2016-11-02 03:27:15 +00:00
2016-11-05 22:55:01 +00:00
// Make sure we got everything
2017-03-11 09:37:00 +00:00
if (*bytesRead != (size_t) size) {
2016-11-05 22:55:01 +00:00
free(data);
2016-11-02 03:27:15 +00:00
return NULL;
}
return data;
}
2017-03-11 09:37:00 +00:00
int lovrFilesystemRemove(const char* path) {
return !PHYSFS_delete(path);
}
2016-11-07 22:30:32 +00:00
int lovrFilesystemSetIdentity(const char* identity) {
state.identity = identity;
// Unmount old write directory
if (state.savePathFull && state.savePathRelative) {
PHYSFS_removeFromSearchPath(state.savePathRelative);
} else {
state.savePathRelative = malloc(LOVR_PATH_MAX);
state.savePathFull = malloc(LOVR_PATH_MAX);
2017-03-11 09:37:00 +00:00
if (!state.savePathRelative || !state.savePathFull) {
return 1;
}
2016-11-07 22:30:32 +00:00
}
2017-03-11 09:37:00 +00:00
lovrFilesystemGetAppdataDirectory(state.savePathFull, LOVR_PATH_MAX);
PHYSFS_setWriteDir(state.savePathFull);
snprintf(state.savePathRelative, LOVR_PATH_MAX, "LOVR/%s", identity ? identity : "default");
2017-08-01 19:23:33 +00:00
char fullPathBuffer[LOVR_PATH_MAX];
snprintf(fullPathBuffer, LOVR_PATH_MAX, "%s/%s", state.savePathFull, state.savePathRelative);
strncpy(state.savePathFull, fullPathBuffer, LOVR_PATH_MAX);
2017-03-11 09:37:00 +00:00
PHYSFS_mkdir(state.savePathRelative);
if (!PHYSFS_setWriteDir(state.savePathFull)) {
lovrThrow("Could not set write directory: %s (%s)", PHYSFS_getLastError(), state.savePathRelative);
}
2017-03-11 09:37:00 +00:00
PHYSFS_mount(state.savePathFull, NULL, 0);
2016-11-07 22:30:32 +00:00
2017-03-11 09:37:00 +00:00
return 0;
2016-11-07 22:30:32 +00:00
}
2017-03-11 09:37:00 +00:00
int lovrFilesystemUnmount(const char* path) {
return !PHYSFS_removeFromSearchPath(path);
2016-11-01 00:14:31 +00:00
}
2016-11-07 22:31:02 +00:00
2017-10-22 00:35:50 +00:00
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
File* file = lovrFileCreate(path);
2017-10-21 07:19:05 +00:00
if (!file) {
2016-11-07 22:31:02 +00:00
return 0;
}
2017-10-22 00:35:50 +00:00
lovrFileOpen(file, append ? OPEN_APPEND : OPEN_WRITE);
size_t bytesWritten = lovrFileWrite(file, (void*) content, 1, size);
lovrFileClose(file);
lovrRelease(&file->ref);
2016-11-07 22:31:02 +00:00
return bytesWritten;
}