mirror of https://github.com/mgba-emu/mgba.git
Util: Split vfs.c into vfs.c, vfs-fd.c and vfs-dirent.c
This commit is contained in:
parent
f2559ad169
commit
7bb17bc99d
|
@ -21,15 +21,15 @@ file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
|
||||||
file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c)
|
file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c)
|
||||||
file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)
|
file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)
|
||||||
file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs])
|
file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs])
|
||||||
file(GLOB VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/*.c)
|
|
||||||
file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/video-software.c)
|
file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/video-software.c)
|
||||||
file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c)
|
file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c)
|
||||||
file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c)
|
file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c)
|
||||||
list(APPEND UTIL_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
|
list(APPEND UTIL_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
|
||||||
|
set(VFS_SRC)
|
||||||
source_group("ARM core" FILES ${ARM_SRC})
|
source_group("ARM core" FILES ${ARM_SRC})
|
||||||
source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC})
|
source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC})
|
||||||
source_group("GBA supervisor" FILES ${GBA_SV_SRC} ${GBA_RR_SRC})
|
source_group("GBA supervisor" FILES ${GBA_SV_SRC} ${GBA_RR_SRC})
|
||||||
source_group("Utilities" FILES ${UTIL_SRC} ${VFS_SRC}})
|
source_group("Utilities" FILES ${UTIL_SRC})
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src/arm)
|
include_directories(${CMAKE_SOURCE_DIR}/src/arm)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ if(WIN32)
|
||||||
set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}")
|
set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}")
|
||||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||||
list(APPEND OS_LIB ws2_32)
|
list(APPEND OS_LIB ws2_32)
|
||||||
|
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c)
|
||||||
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/windows/*.c)
|
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/windows/*.c)
|
||||||
source_group("Windows-specific code" FILES ${OS_SRC})
|
source_group("Windows-specific code" FILES ${OS_SRC})
|
||||||
else()
|
else()
|
||||||
|
@ -129,6 +130,7 @@ else()
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c)
|
||||||
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c)
|
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c)
|
||||||
source_group("POSIX-specific code" FILES ${OS_SRC})
|
source_group("POSIX-specific code" FILES ${OS_SRC})
|
||||||
endif()
|
endif()
|
||||||
|
@ -262,12 +264,14 @@ if(USE_LIBZIP)
|
||||||
link_directories(${LIBZIP_LIBRARY_DIRS})
|
link_directories(${LIBZIP_LIBRARY_DIRS})
|
||||||
list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES})
|
list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES})
|
||||||
list(APPEND FEATURES LIBZIP)
|
list(APPEND FEATURES LIBZIP)
|
||||||
|
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2")
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (USE_LZMA)
|
if (USE_LZMA)
|
||||||
include_directories(AFTER ${CMAKE_SOURCE_DIR}/third-party/lzma)
|
include_directories(AFTER ${CMAKE_SOURCE_DIR}/third-party/lzma)
|
||||||
add_definitions(-D_7ZIP_PPMD_SUPPPORT)
|
add_definitions(-D_7ZIP_PPMD_SUPPPORT)
|
||||||
|
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-lzma.c)
|
||||||
set(LZMA_SRC
|
set(LZMA_SRC
|
||||||
${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zAlloc.c
|
${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zAlloc.c
|
||||||
${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zArcIn.c
|
${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zArcIn.c
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "util/formatting.h"
|
#include "util/formatting.h"
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
@ -13,9 +14,6 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#define PATH_SEP "\\"
|
|
||||||
#else
|
|
||||||
#define PATH_SEP "/"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SECTION_NAME_MAX 128
|
#define SECTION_NAME_MAX 128
|
||||||
|
|
378
src/util/vfs.c
378
src/util/vfs.c
|
@ -1,383 +1,9 @@
|
||||||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include "util/vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
#include "util/string.h"
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#define PATH_SEP '/'
|
|
||||||
#else
|
|
||||||
#include <io.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#define PATH_SEP '\\'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct VFileFD {
|
|
||||||
struct VFile d;
|
|
||||||
int fd;
|
|
||||||
#ifdef _WIN32
|
|
||||||
HANDLE hMap;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool _vfdClose(struct VFile* vf);
|
|
||||||
static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
|
|
||||||
static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
|
|
||||||
static ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
|
|
||||||
static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size);
|
|
||||||
static void* _vfdMap(struct VFile* vf, size_t size, int flags);
|
|
||||||
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
|
|
||||||
static void _vfdTruncate(struct VFile* vf, size_t size);
|
|
||||||
static ssize_t _vfdSize(struct VFile* vf);
|
|
||||||
|
|
||||||
static bool _vdClose(struct VDir* vd);
|
|
||||||
static void _vdRewind(struct VDir* vd);
|
|
||||||
static struct VDirEntry* _vdListNext(struct VDir* vd);
|
|
||||||
static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode);
|
|
||||||
|
|
||||||
static const char* _vdeName(struct VDirEntry* vde);
|
|
||||||
|
|
||||||
struct VFile* VFileOpen(const char* path, int flags) {
|
|
||||||
if (!path) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
|
||||||
flags |= O_BINARY;
|
|
||||||
#endif
|
|
||||||
int fd = open(path, flags, 0666);
|
|
||||||
return VFileFromFD(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VFile* VFileFromFD(int fd) {
|
|
||||||
if (fd < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
|
|
||||||
if (!vfd) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfd->fd = fd;
|
|
||||||
vfd->d.close = _vfdClose;
|
|
||||||
vfd->d.seek = _vfdSeek;
|
|
||||||
vfd->d.read = _vfdRead;
|
|
||||||
vfd->d.readline = _vfdReadline;
|
|
||||||
vfd->d.write = _vfdWrite;
|
|
||||||
vfd->d.map = _vfdMap;
|
|
||||||
vfd->d.unmap = _vfdUnmap;
|
|
||||||
vfd->d.truncate = _vfdTruncate;
|
|
||||||
vfd->d.size = _vfdSize;
|
|
||||||
|
|
||||||
return &vfd->d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _vfdClose(struct VFile* vf) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
if (close(vfd->fd) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
free(vfd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
return lseek(vfd->fd, offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
return read(vfd->fd, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
size_t bytesRead = 0;
|
|
||||||
while (bytesRead < size - 1) {
|
|
||||||
size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
|
|
||||||
if (!newRead || buffer[bytesRead] == '\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bytesRead += newRead;
|
|
||||||
}
|
|
||||||
buffer[bytesRead] = '\0';
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
return write(vfd->fd, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
int mmapFlags = MAP_PRIVATE;
|
|
||||||
if (flags & MAP_WRITE) {
|
|
||||||
mmapFlags = MAP_SHARED;
|
|
||||||
}
|
|
||||||
return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
|
|
||||||
UNUSED(vf);
|
|
||||||
munmap(memory, size);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
int createFlags = PAGE_WRITECOPY;
|
|
||||||
int mapFiles = FILE_MAP_COPY;
|
|
||||||
if (flags & MAP_WRITE) {
|
|
||||||
createFlags = PAGE_READWRITE;
|
|
||||||
mapFiles = FILE_MAP_WRITE;
|
|
||||||
}
|
|
||||||
size_t fileSize;
|
|
||||||
struct stat stat;
|
|
||||||
if (fstat(vfd->fd, &stat) < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
fileSize = stat.st_size;
|
|
||||||
if (size > fileSize) {
|
|
||||||
size = fileSize;
|
|
||||||
}
|
|
||||||
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
|
|
||||||
return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
|
|
||||||
UNUSED(size);
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
UnmapViewOfFile(memory);
|
|
||||||
CloseHandle(vfd->hMap);
|
|
||||||
vfd->hMap = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void _vfdTruncate(struct VFile* vf, size_t size) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
ftruncate(vfd->fd, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t _vfdSize(struct VFile* vf) {
|
|
||||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
|
||||||
struct stat stat;
|
|
||||||
if (fstat(vfd->fd, &stat) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return stat.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VDirEntryDE {
|
|
||||||
struct VDirEntry d;
|
|
||||||
struct dirent* ent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VDirDE {
|
|
||||||
struct VDir d;
|
|
||||||
DIR* de;
|
|
||||||
struct VDirEntryDE vde;
|
|
||||||
char* path;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VDir* VDirOpen(const char* path) {
|
|
||||||
DIR* de = opendir(path);
|
|
||||||
if (!de) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VDirDE* vd = malloc(sizeof(struct VDirDE));
|
|
||||||
if (!vd) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vd->d.close = _vdClose;
|
|
||||||
vd->d.rewind = _vdRewind;
|
|
||||||
vd->d.listNext = _vdListNext;
|
|
||||||
vd->d.openFile = _vdOpenFile;
|
|
||||||
vd->path = strdup(path);
|
|
||||||
vd->de = de;
|
|
||||||
|
|
||||||
vd->vde.d.name = _vdeName;
|
|
||||||
|
|
||||||
return &vd->d;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) {
|
|
||||||
char path[PATH_MAX];
|
|
||||||
path[PATH_MAX - 1] = '\0';
|
|
||||||
struct VFile* vf;
|
|
||||||
if (!dir) {
|
|
||||||
if (!realPath) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* dotPoint = strrchr(realPath, '.');
|
|
||||||
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (dotPoint > strrchr(realPath, '/')) {
|
|
||||||
int len = dotPoint - realPath;
|
|
||||||
strncpy(path, realPath, len);
|
|
||||||
path[len] = 0;
|
|
||||||
strncat(path + len, suffix, PATH_MAX - len - 1);
|
|
||||||
} else {
|
|
||||||
snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix);
|
|
||||||
}
|
|
||||||
vf = VFileOpen(path, mode);
|
|
||||||
} else {
|
|
||||||
snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix);
|
|
||||||
vf = dir->openFile(dir, path, mode);
|
|
||||||
}
|
|
||||||
return vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) {
|
|
||||||
char path[PATH_MAX];
|
|
||||||
path[PATH_MAX - 1] = '\0';
|
|
||||||
char realPrefix[PATH_MAX];
|
|
||||||
realPrefix[PATH_MAX - 1] = '\0';
|
|
||||||
if (!dir) {
|
|
||||||
if (!realPath) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const char* separatorPoint = strrchr(realPath, '/');
|
|
||||||
const char* dotPoint;
|
|
||||||
size_t len;
|
|
||||||
if (!separatorPoint) {
|
|
||||||
strcpy(path, "./");
|
|
||||||
separatorPoint = realPath;
|
|
||||||
dotPoint = strrchr(realPath, '.');
|
|
||||||
} else {
|
|
||||||
path[0] = '\0';
|
|
||||||
dotPoint = strrchr(separatorPoint, '.');
|
|
||||||
|
|
||||||
if (separatorPoint - realPath + 1 >= PATH_MAX - 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = separatorPoint - realPath;
|
|
||||||
strncat(path, realPath, len);
|
|
||||||
path[len] = '\0';
|
|
||||||
++separatorPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dotPoint >= separatorPoint) {
|
|
||||||
len = dotPoint - separatorPoint;
|
|
||||||
} else {
|
|
||||||
len = PATH_MAX - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(realPrefix, separatorPoint, len);
|
|
||||||
realPrefix[len] = '\0';
|
|
||||||
|
|
||||||
prefix = realPrefix;
|
|
||||||
dir = VDirOpen(path);
|
|
||||||
}
|
|
||||||
if (!dir) {
|
|
||||||
// This shouldn't be possible
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dir->rewind(dir);
|
|
||||||
struct VDirEntry* dirent;
|
|
||||||
size_t prefixLen = strlen(prefix);
|
|
||||||
size_t infixLen = strlen(infix);
|
|
||||||
unsigned next = 0;
|
|
||||||
while ((dirent = dir->listNext(dir))) {
|
|
||||||
const char* filename = dirent->name(dirent);
|
|
||||||
char* dotPoint = strrchr(filename, '.');
|
|
||||||
size_t len = strlen(filename);
|
|
||||||
if (dotPoint) {
|
|
||||||
len = (dotPoint - filename);
|
|
||||||
}
|
|
||||||
const char* separator = strnrstr(filename, infix, len);
|
|
||||||
if (!separator) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
len = separator - filename;
|
|
||||||
if (len != prefixLen) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strncmp(filename, prefix, prefixLen) == 0) {
|
|
||||||
int nlen;
|
|
||||||
separator += infixLen;
|
|
||||||
snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
|
|
||||||
unsigned increment;
|
|
||||||
if (sscanf(separator, path, &increment, &nlen) < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
len = strlen(separator);
|
|
||||||
if (nlen < (ssize_t) len) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (next <= increment) {
|
|
||||||
next = increment + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix);
|
|
||||||
path[PATH_MAX - 1] = '\0';
|
|
||||||
return dir->openFile(dir, path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _vdClose(struct VDir* vd) {
|
|
||||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
|
||||||
if (closedir(vdde->de) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
free(vdde->path);
|
|
||||||
free(vdde);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _vdRewind(struct VDir* vd) {
|
|
||||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
|
||||||
rewinddir(vdde->de);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VDirEntry* _vdListNext(struct VDir* vd) {
|
|
||||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
|
||||||
vdde->vde.ent = readdir(vdde->de);
|
|
||||||
if (vdde->vde.ent) {
|
|
||||||
return &vdde->vde.d;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode) {
|
|
||||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
|
||||||
if (!path) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const char* dir = vdde->path;
|
|
||||||
char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
|
|
||||||
sprintf(combined, "%s%c%s", dir, PATH_SEP, path);
|
|
||||||
|
|
||||||
struct VFile* file = VFileOpen(combined, mode);
|
|
||||||
free(combined);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* _vdeName(struct VDirEntry* vde) {
|
|
||||||
struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
|
|
||||||
if (vdede->ent) {
|
|
||||||
return vdede->ent->d_name;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size) {
|
ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size) {
|
||||||
size_t bytesRead = 0;
|
size_t bytesRead = 0;
|
||||||
|
|
|
@ -8,6 +8,23 @@
|
||||||
|
|
||||||
#include "util/common.h"
|
#include "util/common.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#define PATH_SEP "/"
|
||||||
|
#else
|
||||||
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#define PATH_SEP "\\"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#ifdef MAX_PATH
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#else
|
||||||
|
#define PATH_MAX 128
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MAP_READ = 1,
|
MAP_READ = 1,
|
||||||
MAP_WRITE = 2
|
MAP_WRITE = 2
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
static bool _vdClose(struct VDir* vd);
|
||||||
|
static void _vdRewind(struct VDir* vd);
|
||||||
|
static struct VDirEntry* _vdListNext(struct VDir* vd);
|
||||||
|
static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode);
|
||||||
|
|
||||||
|
static const char* _vdeName(struct VDirEntry* vde);
|
||||||
|
|
||||||
|
struct VDirEntryDE {
|
||||||
|
struct VDirEntry d;
|
||||||
|
struct dirent* ent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VDirDE {
|
||||||
|
struct VDir d;
|
||||||
|
DIR* de;
|
||||||
|
struct VDirEntryDE vde;
|
||||||
|
char* path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VDir* VDirOpen(const char* path) {
|
||||||
|
DIR* de = opendir(path);
|
||||||
|
if (!de) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VDirDE* vd = malloc(sizeof(struct VDirDE));
|
||||||
|
if (!vd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vd->d.close = _vdClose;
|
||||||
|
vd->d.rewind = _vdRewind;
|
||||||
|
vd->d.listNext = _vdListNext;
|
||||||
|
vd->d.openFile = _vdOpenFile;
|
||||||
|
vd->path = strdup(path);
|
||||||
|
vd->de = de;
|
||||||
|
|
||||||
|
vd->vde.d.name = _vdeName;
|
||||||
|
|
||||||
|
return &vd->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
struct VFile* vf;
|
||||||
|
if (!dir) {
|
||||||
|
if (!realPath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char* dotPoint = strrchr(realPath, '.');
|
||||||
|
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (dotPoint > strrchr(realPath, '/')) {
|
||||||
|
int len = dotPoint - realPath;
|
||||||
|
strncpy(path, realPath, len);
|
||||||
|
path[len] = 0;
|
||||||
|
strncat(path + len, suffix, PATH_MAX - len - 1);
|
||||||
|
} else {
|
||||||
|
snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix);
|
||||||
|
}
|
||||||
|
vf = VFileOpen(path, mode);
|
||||||
|
} else {
|
||||||
|
snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix);
|
||||||
|
vf = dir->openFile(dir, path, mode);
|
||||||
|
}
|
||||||
|
return vf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
char realPrefix[PATH_MAX];
|
||||||
|
realPrefix[PATH_MAX - 1] = '\0';
|
||||||
|
if (!dir) {
|
||||||
|
if (!realPath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char* separatorPoint = strrchr(realPath, '/');
|
||||||
|
const char* dotPoint;
|
||||||
|
size_t len;
|
||||||
|
if (!separatorPoint) {
|
||||||
|
strcpy(path, "./");
|
||||||
|
separatorPoint = realPath;
|
||||||
|
dotPoint = strrchr(realPath, '.');
|
||||||
|
} else {
|
||||||
|
path[0] = '\0';
|
||||||
|
dotPoint = strrchr(separatorPoint, '.');
|
||||||
|
|
||||||
|
if (separatorPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = separatorPoint - realPath;
|
||||||
|
strncat(path, realPath, len);
|
||||||
|
path[len] = '\0';
|
||||||
|
++separatorPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dotPoint >= separatorPoint) {
|
||||||
|
len = dotPoint - separatorPoint;
|
||||||
|
} else {
|
||||||
|
len = PATH_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(realPrefix, separatorPoint, len);
|
||||||
|
realPrefix[len] = '\0';
|
||||||
|
|
||||||
|
prefix = realPrefix;
|
||||||
|
dir = VDirOpen(path);
|
||||||
|
}
|
||||||
|
if (!dir) {
|
||||||
|
// This shouldn't be possible
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dir->rewind(dir);
|
||||||
|
struct VDirEntry* dirent;
|
||||||
|
size_t prefixLen = strlen(prefix);
|
||||||
|
size_t infixLen = strlen(infix);
|
||||||
|
unsigned next = 0;
|
||||||
|
while ((dirent = dir->listNext(dir))) {
|
||||||
|
const char* filename = dirent->name(dirent);
|
||||||
|
char* dotPoint = strrchr(filename, '.');
|
||||||
|
size_t len = strlen(filename);
|
||||||
|
if (dotPoint) {
|
||||||
|
len = (dotPoint - filename);
|
||||||
|
}
|
||||||
|
const char* separator = strnrstr(filename, infix, len);
|
||||||
|
if (!separator) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = separator - filename;
|
||||||
|
if (len != prefixLen) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(filename, prefix, prefixLen) == 0) {
|
||||||
|
int nlen;
|
||||||
|
separator += infixLen;
|
||||||
|
snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
|
||||||
|
unsigned increment;
|
||||||
|
if (sscanf(separator, path, &increment, &nlen) < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = strlen(separator);
|
||||||
|
if (nlen < (ssize_t) len) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (next <= increment) {
|
||||||
|
next = increment + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix);
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
return dir->openFile(dir, path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _vdClose(struct VDir* vd) {
|
||||||
|
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||||
|
if (closedir(vdde->de) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(vdde->path);
|
||||||
|
free(vdde);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vdRewind(struct VDir* vd) {
|
||||||
|
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||||
|
rewinddir(vdde->de);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VDirEntry* _vdListNext(struct VDir* vd) {
|
||||||
|
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||||
|
vdde->vde.ent = readdir(vdde->de);
|
||||||
|
if (vdde->vde.ent) {
|
||||||
|
return &vdde->vde.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode) {
|
||||||
|
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||||
|
if (!path) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char* dir = vdde->path;
|
||||||
|
char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
|
||||||
|
sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
|
||||||
|
|
||||||
|
struct VFile* file = VFileOpen(combined, mode);
|
||||||
|
free(combined);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _vdeName(struct VDirEntry* vde) {
|
||||||
|
struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
|
||||||
|
if (vdede->ent) {
|
||||||
|
return vdede->ent->d_name;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
struct VFileFD {
|
||||||
|
struct VFile d;
|
||||||
|
int fd;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE hMap;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool _vfdClose(struct VFile* vf);
|
||||||
|
static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
|
||||||
|
static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
static ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
|
||||||
|
static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
static void* _vfdMap(struct VFile* vf, size_t size, int flags);
|
||||||
|
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
|
static void _vfdTruncate(struct VFile* vf, size_t size);
|
||||||
|
static ssize_t _vfdSize(struct VFile* vf);
|
||||||
|
|
||||||
|
struct VFile* VFileOpen(const char* path, int flags) {
|
||||||
|
if (!path) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
flags |= O_BINARY;
|
||||||
|
#endif
|
||||||
|
int fd = open(path, flags, 0666);
|
||||||
|
return VFileFromFD(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* VFileFromFD(int fd) {
|
||||||
|
if (fd < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
|
||||||
|
if (!vfd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd->fd = fd;
|
||||||
|
vfd->d.close = _vfdClose;
|
||||||
|
vfd->d.seek = _vfdSeek;
|
||||||
|
vfd->d.read = _vfdRead;
|
||||||
|
vfd->d.readline = _vfdReadline;
|
||||||
|
vfd->d.write = _vfdWrite;
|
||||||
|
vfd->d.map = _vfdMap;
|
||||||
|
vfd->d.unmap = _vfdUnmap;
|
||||||
|
vfd->d.truncate = _vfdTruncate;
|
||||||
|
vfd->d.size = _vfdSize;
|
||||||
|
|
||||||
|
return &vfd->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _vfdClose(struct VFile* vf) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
if (close(vfd->fd) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(vfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return lseek(vfd->fd, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return read(vfd->fd, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
while (bytesRead < size - 1) {
|
||||||
|
size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
|
||||||
|
if (!newRead || buffer[bytesRead] == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytesRead += newRead;
|
||||||
|
}
|
||||||
|
buffer[bytesRead] = '\0';
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return write(vfd->fd, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
int mmapFlags = MAP_PRIVATE;
|
||||||
|
if (flags & MAP_WRITE) {
|
||||||
|
mmapFlags = MAP_SHARED;
|
||||||
|
}
|
||||||
|
return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
|
||||||
|
UNUSED(vf);
|
||||||
|
munmap(memory, size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
int createFlags = PAGE_WRITECOPY;
|
||||||
|
int mapFiles = FILE_MAP_COPY;
|
||||||
|
if (flags & MAP_WRITE) {
|
||||||
|
createFlags = PAGE_READWRITE;
|
||||||
|
mapFiles = FILE_MAP_WRITE;
|
||||||
|
}
|
||||||
|
size_t fileSize;
|
||||||
|
struct stat stat;
|
||||||
|
if (fstat(vfd->fd, &stat) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fileSize = stat.st_size;
|
||||||
|
if (size > fileSize) {
|
||||||
|
size = fileSize;
|
||||||
|
}
|
||||||
|
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
|
||||||
|
return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
|
||||||
|
UNUSED(size);
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
UnmapViewOfFile(memory);
|
||||||
|
CloseHandle(vfd->hMap);
|
||||||
|
vfd->hMap = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void _vfdTruncate(struct VFile* vf, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
ftruncate(vfd->fd, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _vfdSize(struct VFile* vf) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
struct stat stat;
|
||||||
|
if (fstat(vfd->fd, &stat) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return stat.st_size;
|
||||||
|
}
|
Loading…
Reference in New Issue