2016-11-19 09:28:01 +00:00
|
|
|
#include "filesystem/filesystem.h"
|
|
|
|
#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)) {
|
|
|
|
error("Could not initialize filesystem: %s", PHYSFS_getLastError());
|
|
|
|
}
|
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);
|
|
|
|
if (lovrFilesystemMount(state.source, NULL, 1)) {
|
|
|
|
state.isFused = 0;
|
|
|
|
strncpy(state.source, arg1, LOVR_PATH_MAX);
|
|
|
|
if (!state.source || lovrFilesystemMount(state.source, NULL, 1)) {
|
|
|
|
free(state.source);
|
|
|
|
state.source = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
#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);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrFilesystemGetSize(const char* path) {
|
|
|
|
PHYSFS_file* handle = PHYSFS_openRead(path);
|
|
|
|
if (!handle) {
|
|
|
|
return 1;
|
2016-11-07 22:30:32 +00:00
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int length = PHYSFS_fileLength(handle);
|
|
|
|
PHYSFS_close(handle);
|
|
|
|
return length;
|
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
|
|
|
|
2016-11-05 22:55:01 +00:00
|
|
|
// Open file
|
|
|
|
PHYSFS_file* handle = PHYSFS_openRead(path);
|
2016-11-02 03:27:15 +00:00
|
|
|
if (!handle) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-05 22:55:01 +00:00
|
|
|
// Get file size
|
|
|
|
int size = PHYSFS_fileLength(handle);
|
|
|
|
if (size < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate buffer
|
|
|
|
void* data = malloc(size);
|
|
|
|
if (!data) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform read
|
|
|
|
*bytesRead = PHYSFS_read(handle, data, 1, size);
|
|
|
|
PHYSFS_close(handle);
|
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:47:30 +00:00
|
|
|
const char* sep = PHYSFS_getDirSeparator();
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
lovrFilesystemGetAppdataDirectory(state.savePathFull, LOVR_PATH_MAX);
|
|
|
|
PHYSFS_setWriteDir(state.savePathFull);
|
2017-03-11 09:47:30 +00:00
|
|
|
snprintf(state.savePathRelative, LOVR_PATH_MAX, "LOVR%s%s", sep, identity);
|
|
|
|
snprintf(state.savePathFull, LOVR_PATH_MAX, "%s%s%s", state.savePathFull, sep, state.savePathRelative);
|
2017-03-11 09:37:00 +00:00
|
|
|
PHYSFS_mkdir(state.savePathRelative);
|
|
|
|
PHYSFS_setWriteDir(state.savePathRelative);
|
|
|
|
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-03-11 09:37:00 +00:00
|
|
|
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
|
|
|
|
PHYSFS_file* handle = append ? PHYSFS_openAppend(path) : PHYSFS_openWrite(path);
|
2016-11-07 22:31:02 +00:00
|
|
|
if (!handle) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bytesWritten = PHYSFS_write(handle, content, 1, size);
|
|
|
|
PHYSFS_close(handle);
|
|
|
|
return bytesWritten;
|
|
|
|
}
|