Use VFiles for all file operations

This commit is contained in:
Jeffrey Pfau 2014-07-16 02:08:54 -07:00
parent 377d8e60a7
commit f1f55cea47
13 changed files with 189 additions and 102 deletions

View File

@ -3,6 +3,7 @@
#include "gba.h" #include "gba.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/vfile.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@ -16,7 +17,7 @@ void GBASavedataInit(struct GBASavedata* savedata, const char* filename) {
savedata->data = 0; savedata->data = 0;
savedata->command = EEPROM_COMMAND_NULL; savedata->command = EEPROM_COMMAND_NULL;
savedata->flashState = FLASH_STATE_RAW; savedata->flashState = FLASH_STATE_RAW;
savedata->fd = -1; savedata->vf = 0;
savedata->filename = filename; savedata->filename = filename;
} }
@ -29,6 +30,26 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type)
} }
void GBASavedataDeinit(struct GBASavedata* savedata) { void GBASavedataDeinit(struct GBASavedata* savedata) {
if (savedata->vf) {
switch (savedata->type) {
case SAVEDATA_SRAM:
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM);
break;
case SAVEDATA_FLASH512:
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
break;
case SAVEDATA_FLASH1M:
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M);
break;
case SAVEDATA_EEPROM:
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM);
break;
case SAVEDATA_NONE:
break;
}
savedata->vf->close(savedata->vf);
savedata->vf = 0;
} else {
switch (savedata->type) { switch (savedata->type) {
case SAVEDATA_SRAM: case SAVEDATA_SRAM:
mappedMemoryFree(savedata->data, SIZE_CART_SRAM); mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
@ -42,11 +63,9 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
case SAVEDATA_EEPROM: case SAVEDATA_EEPROM:
mappedMemoryFree(savedata->data, SIZE_CART_EEPROM); mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
break; break;
default: case SAVEDATA_NONE:
break; break;
} }
if (savedata->fd >= 0) {
close(savedata->fd);
} }
savedata->type = SAVEDATA_NONE; savedata->type = SAVEDATA_NONE;
} }
@ -59,18 +78,18 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
return; return;
} }
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
off_t end; off_t end;
if (savedata->fd < 0) { if (!savedata->vf) {
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
end = 0; end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M); savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
} else { } else {
end = lseek(savedata->fd, 0, SEEK_END); end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
if (end < SIZE_CART_FLASH512) { if (end < SIZE_CART_FLASH512) {
ftruncate(savedata->fd, SIZE_CART_FLASH1M); savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
} }
savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_FLASH1M, MEMORY_WRITE); savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MEMORY_WRITE);
} }
savedata->currentBank = savedata->data; savedata->currentBank = savedata->data;
@ -86,18 +105,18 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
return; return;
} }
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
off_t end; off_t end;
if (savedata->fd < 0) { if (!savedata->vf) {
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
end = 0; end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM); savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
} else { } else {
end = lseek(savedata->fd, 0, SEEK_END); end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
if (end < SIZE_CART_EEPROM) { if (end < SIZE_CART_EEPROM) {
ftruncate(savedata->fd, SIZE_CART_EEPROM); savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
} }
savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_EEPROM, MEMORY_WRITE); savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, MEMORY_WRITE);
} }
if (end < SIZE_CART_EEPROM) { if (end < SIZE_CART_EEPROM) {
memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end); memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
@ -111,18 +130,18 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
return; return;
} }
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
off_t end; off_t end;
if (savedata->fd < 0) { if (!savedata->vf) {
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
end = 0; end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_SRAM); savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
} else { } else {
end = lseek(savedata->fd, 0, SEEK_END); end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
if (end < SIZE_CART_SRAM) { if (end < SIZE_CART_SRAM) {
ftruncate(savedata->fd, SIZE_CART_SRAM); savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
} }
savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_SRAM, MEMORY_WRITE); savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, MEMORY_WRITE);
} }
if (end < SIZE_CART_SRAM) { if (end < SIZE_CART_SRAM) {
@ -299,7 +318,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
savedata->currentBank = &savedata->data[bank << 16]; savedata->currentBank = &savedata->data[bank << 16];
if (bank > 0) { if (bank > 0) {
savedata->type = SAVEDATA_FLASH1M; savedata->type = SAVEDATA_FLASH1M;
ftruncate(savedata->fd, SIZE_CART_FLASH1M); savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
} }
} }

View File

@ -3,6 +3,8 @@
#include "common.h" #include "common.h"
struct VFile;
enum SavedataType { enum SavedataType {
SAVEDATA_NONE = 0, SAVEDATA_NONE = 0,
SAVEDATA_SRAM, SAVEDATA_SRAM,
@ -55,7 +57,7 @@ struct GBASavedata {
uint8_t* data; uint8_t* data;
const char* filename; const char* filename;
enum SavedataCommand command; enum SavedataCommand command;
int fd; struct VFile* vf;
int readBitsRemaining; int readBitsRemaining;
int readAddress; int readAddress;

View File

@ -5,6 +5,7 @@
#include "gba-thread.h" #include "gba-thread.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/vfile.h"
#include <fcntl.h> #include <fcntl.h>
@ -62,43 +63,47 @@ void GBADeserialize(struct GBA* gba, struct GBASerializedState* state) {
GBAAudioDeserialize(&gba->audio, state); GBAAudioDeserialize(&gba->audio, state);
} }
static int _getStateFd(struct GBA* gba, int slot) { static struct VFile* _getStateVf(struct GBA* gba, int slot) {
char path[PATH_MAX]; char path[PATH_MAX];
path[PATH_MAX - 1] = '\0'; path[PATH_MAX - 1] = '\0';
snprintf(path, PATH_MAX - 1, "%s.ss%d", gba->activeFile, slot); snprintf(path, PATH_MAX - 1, "%s.ss%d", gba->activeFile, slot);
int fd = open(path, O_CREAT | O_RDWR, 0777); struct VFile* vf = VFileOpen(path, O_CREAT | O_RDWR);
if (fd >= 0) { if (vf) {
ftruncate(fd, sizeof(struct GBASerializedState)); vf->truncate(vf, sizeof(struct GBASerializedState));
} }
return fd; return vf;
} }
bool GBASaveState(struct GBA* gba, int slot) { bool GBASaveState(struct GBA* gba, int slot) {
int fd = _getStateFd(gba, slot); struct VFile* vf = _getStateVf(gba, slot);
if (fd < 0) { if (!vf) {
return false; return false;
} }
struct GBASerializedState* state = GBAMapState(fd); struct GBASerializedState* state = GBAMapState(vf);
GBASerialize(gba, state); GBASerialize(gba, state);
GBADeallocateState(state); GBAUnmapState(vf, state);
close(fd); vf->close(vf);
return true; return true;
} }
bool GBALoadState(struct GBA* gba, int slot) { bool GBALoadState(struct GBA* gba, int slot) {
int fd = _getStateFd(gba, slot); struct VFile* vf = _getStateVf(gba, slot);
if (fd < 0) { if (!vf) {
return false; return false;
} }
struct GBASerializedState* state = GBAMapState(fd); struct GBASerializedState* state = GBAMapState(vf);
GBADeserialize(gba, state); GBADeserialize(gba, state);
GBADeallocateState(state); GBAUnmapState(vf, state);
close(fd); vf->close(vf);
return true; return true;
} }
struct GBASerializedState* GBAMapState(int fd) { struct GBASerializedState* GBAMapState(struct VFile* vf) {
return fileMemoryMap(fd, sizeof(struct GBASerializedState), MEMORY_WRITE); return vf->map(vf, sizeof(struct GBASerializedState), MEMORY_WRITE);
}
void GBAUnmapState(struct VFile* vf, struct GBASerializedState* state) {
vf->unmap(vf, state, sizeof(struct GBASerializedState));
} }
struct GBASerializedState* GBAAllocateState(void) { struct GBASerializedState* GBAAllocateState(void) {

View File

@ -225,13 +225,17 @@ struct GBASerializedState {
uint8_t wram[SIZE_WORKING_RAM]; uint8_t wram[SIZE_WORKING_RAM];
}; };
struct VFile;
void GBASerialize(struct GBA* gba, struct GBASerializedState* state); void GBASerialize(struct GBA* gba, struct GBASerializedState* state);
void GBADeserialize(struct GBA* gba, struct GBASerializedState* state); void GBADeserialize(struct GBA* gba, struct GBASerializedState* state);
bool GBASaveState(struct GBA* gba, int slot); bool GBASaveState(struct GBA* gba, int slot);
bool GBALoadState(struct GBA* gba, int slot); bool GBALoadState(struct GBA* gba, int slot);
struct GBASerializedState* GBAMapState(int fd); struct GBASerializedState* GBAMapState(struct VFile* vf);
void GBAUnmapState(struct VFile* vf, struct GBASerializedState* state);
struct GBASerializedState* GBAAllocateState(void); struct GBASerializedState* GBAAllocateState(void);
void GBADeallocateState(struct GBASerializedState* state); void GBADeallocateState(struct GBASerializedState* state);

View File

@ -89,7 +89,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); GBAVideoAssociateRenderer(&gba.video, threadContext->renderer);
} }
if (threadContext->fd >= 0) { if (threadContext->fd) {
if (threadContext->fname) { if (threadContext->fname) {
char* dotPoint = strrchr(threadContext->fname, '.'); char* dotPoint = strrchr(threadContext->fname, '.');
if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) { if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) {
@ -111,11 +111,11 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
} }
gba.savefile = savedata; gba.savefile = savedata;
GBALoadROM(&gba, threadContext->fd, threadContext->fname); GBALoadROM(&gba, threadContext->fd, threadContext->fname);
if (threadContext->biosFd >= 0) { if (threadContext->biosFd) {
GBALoadBIOS(&gba, threadContext->biosFd); GBALoadBIOS(&gba, threadContext->biosFd);
} }
if (threadContext->patchFd >= 0 && loadPatch(VFileFromFD(threadContext->patchFd), &patch)) { if (threadContext->patchFd && loadPatch(threadContext->patchFd, &patch)) {
GBAApplyPatch(&gba, &patch); GBAApplyPatch(&gba, &patch);
} }
} }
@ -191,10 +191,10 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
} }
void GBAMapOptionsToContext(struct StartupOptions* opts, struct GBAThread* threadContext) { void GBAMapOptionsToContext(struct StartupOptions* opts, struct GBAThread* threadContext) {
threadContext->fd = opts->fd; threadContext->fd = VFileFromFD(opts->fd);
threadContext->fname = opts->fname; threadContext->fname = opts->fname;
threadContext->biosFd = opts->biosFd; threadContext->biosFd = VFileFromFD(opts->biosFd);
threadContext->patchFd = opts->patchFd; threadContext->patchFd = VFileFromFD(opts->patchFd);
threadContext->frameskip = opts->frameskip; threadContext->frameskip = opts->frameskip;
threadContext->logLevel = opts->logLevel; threadContext->logLevel = opts->logLevel;
threadContext->rewindBufferCapacity = opts->rewindBufferCapacity; threadContext->rewindBufferCapacity = opts->rewindBufferCapacity;

View File

@ -47,9 +47,9 @@ struct GBAThread {
struct GBAVideoRenderer* renderer; struct GBAVideoRenderer* renderer;
struct GBASIODriverSet sioDrivers; struct GBASIODriverSet sioDrivers;
struct ARMDebugger* debugger; struct ARMDebugger* debugger;
int fd; struct VFile* fd;
int biosFd; struct VFile* biosFd;
int patchFd; struct VFile* patchFd;
const char* fname; const char* fname;
int activeKeys; int activeKeys;
int frameskip; int frameskip;

View File

@ -7,8 +7,7 @@
#include "util/memory.h" #include "util/memory.h"
#include "util/patch.h" #include "util/patch.h"
#include "util/vfile.h"
#include <sys/stat.h>
const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
@ -134,6 +133,9 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) {
gba->rotationSource = 0; gba->rotationSource = 0;
gba->rumble = 0; gba->rumble = 0;
gba->romVf = 0;
gba->biosVf = 0;
gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL; gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
@ -143,7 +145,15 @@ void GBADestroy(struct GBA* gba) {
if (gba->pristineRom == gba->memory.rom) { if (gba->pristineRom == gba->memory.rom) {
gba->memory.rom = 0; gba->memory.rom = 0;
} }
mappedMemoryFree(gba->pristineRom, gba->pristineRomSize);
if (gba->romVf) {
gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize);
}
if (gba->biosVf) {
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
}
GBAMemoryDeinit(gba); GBAMemoryDeinit(gba);
GBAVideoDeinit(&gba->video); GBAVideoDeinit(&gba->video);
GBAAudioDeinit(&gba->audio); GBAAudioDeinit(&gba->audio);
@ -363,13 +373,13 @@ void GBADetachDebugger(struct GBA* gba) {
gba->debugger = 0; gba->debugger = 0;
} }
void GBALoadROM(struct GBA* gba, int fd, const char* fname) { void GBALoadROM(struct GBA* gba, struct VFile* vf, const char* fname) {
struct stat info; gba->romVf = vf;
gba->pristineRom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ); gba->pristineRomSize = vf->seek(vf, 0, SEEK_END);
vf->seek(vf, 0, SEEK_SET);
gba->pristineRom = vf->map(vf, SIZE_CART0, MEMORY_READ);
gba->memory.rom = gba->pristineRom; gba->memory.rom = gba->pristineRom;
gba->activeFile = fname; gba->activeFile = fname;
fstat(fd, &info);
gba->pristineRomSize = info.st_size;
gba->memory.romSize = gba->pristineRomSize; gba->memory.romSize = gba->pristineRomSize;
if (gba->savefile) { if (gba->savefile) {
GBASavedataInit(&gba->memory.savedata, gba->savefile); GBASavedataInit(&gba->memory.savedata, gba->savefile);
@ -379,8 +389,9 @@ void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
// TODO: error check // TODO: error check
} }
void GBALoadBIOS(struct GBA* gba, int fd) { void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
gba->memory.bios = fileMemoryMap(fd, SIZE_BIOS, MEMORY_READ); gba->biosVf = vf;
gba->memory.bios = vf->map(vf, SIZE_BIOS, MEMORY_READ);
gba->memory.fullBios = 1; gba->memory.fullBios = 1;
uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum); GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);

View File

@ -60,9 +60,10 @@ enum GBAKey {
GBA_KEY_NONE = -1 GBA_KEY_NONE = -1
}; };
struct GBARotationSource;
struct GBA; struct GBA;
struct GBARotationSource;
struct Patch; struct Patch;
struct VFile;
typedef void (*GBALogHandler)(struct GBA*, enum GBALogLevel, const char* format, va_list args); typedef void (*GBALogHandler)(struct GBA*, enum GBALogLevel, const char* format, va_list args);
@ -99,6 +100,8 @@ struct GBA {
struct GBARumble* rumble; struct GBARumble* rumble;
void* pristineRom; void* pristineRom;
size_t pristineRomSize; size_t pristineRomSize;
struct VFile* romVf;
struct VFile* biosVf;
const char* activeFile; const char* activeFile;
const char* savefile; const char* savefile;
@ -141,8 +144,8 @@ void GBAHalt(struct GBA* gba);
void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger); void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger);
void GBADetachDebugger(struct GBA* gba); void GBADetachDebugger(struct GBA* gba);
void GBALoadROM(struct GBA* gba, int fd, const char* fname); void GBALoadROM(struct GBA* gba, struct VFile* vf, const char* fname);
void GBALoadBIOS(struct GBA* gba, int fd); void GBALoadBIOS(struct GBA* gba, struct VFile* vf);
void GBAApplyPatch(struct GBA* gba, struct Patch* patch); void GBAApplyPatch(struct GBA* gba, struct Patch* patch);
__attribute__((format (printf, 3, 4))) __attribute__((format (printf, 3, 4)))

View File

@ -5,13 +5,6 @@
void* anonymousMemoryMap(size_t size) { void* anonymousMemoryMap(size_t size) {
return mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); return mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
} }
void* fileMemoryMap(int fd, size_t size, int flags) {
int mmapFlags = MAP_PRIVATE;
if (flags & MEMORY_WRITE) {
mmapFlags = MAP_SHARED;
}
return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, fd, 0);
}
void mappedMemoryFree(void* memory, size_t size) { void mappedMemoryFree(void* memory, size_t size) {
munmap(memory, size); munmap(memory, size);

View File

@ -8,23 +8,6 @@ void* anonymousMemoryMap(size_t size) {
return MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, size); return MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, size);
} }
void* fileMemoryMap(int fd, size_t size, int flags) {
int createFlags = PAGE_READONLY;
int mapFiles = FILE_MAP_READ;
if (flags & MEMORY_WRITE) {
createFlags = PAGE_READWRITE;
mapFiles = FILE_MAP_WRITE;
}
size_t location = lseek(fd, 0, SEEK_CUR);
size_t fileSize = lseek(fd, 0, SEEK_END);
lseek(fd, location, SEEK_SET);
if (size > fileSize) {
size = fileSize;
}
HANDLE hMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
return MapViewOfFile(hMap, mapFiles, 0, 0, size);
}
void mappedMemoryFree(void* memory, size_t size) { void mappedMemoryFree(void* memory, size_t size) {
// TODO fill in // TODO fill in
} }

View File

@ -7,7 +7,6 @@
#define MEMORY_WRITE 2 #define MEMORY_WRITE 2
void* anonymousMemoryMap(size_t size); void* anonymousMemoryMap(size_t size);
void* fileMemoryMap(int fd, size_t size, int flags);
void mappedMemoryFree(void* memory, size_t size); void mappedMemoryFree(void* memory, size_t size);
#endif #endif

View File

@ -2,9 +2,19 @@
#include <fcntl.h> #include <fcntl.h>
#ifndef _WIN32
#include <sys/mman.h>
#else
#include <io.h>
#include <Windows.h>
#endif
struct VFileFD { struct VFileFD {
struct VFile d; struct VFile d;
int fd; int fd;
#ifdef _WIN32
HANDLE hMap;
#endif
}; };
static bool _vfdClose(struct VFile* vf); static bool _vfdClose(struct VFile* vf);
@ -12,9 +22,12 @@ static size_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size); static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size); static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
static size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size); static size_t _vfdWrite(struct VFile* vf, 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);
struct VFile* VFileOpen(const char* path, int flags) { struct VFile* VFileOpen(const char* path, int flags) {
int fd = open(path, flags); int fd = open(path, flags, 0666);
return VFileFromFD(fd); return VFileFromFD(fd);
} }
@ -34,6 +47,9 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.read = _vfdRead; vfd->d.read = _vfdRead;
vfd->d.readline = _vfdReadline; vfd->d.readline = _vfdReadline;
vfd->d.write = _vfdWrite; vfd->d.write = _vfdWrite;
vfd->d.map = _vfdMap;
vfd->d.unmap = _vfdUnmap;
vfd->d.truncate = _vfdTruncate;
return &vfd->d; return &vfd->d;
} }
@ -74,3 +90,50 @@ size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size) {
struct VFileFD* vfd = (struct VFileFD*) vf; struct VFileFD* vfd = (struct VFileFD*) vf;
return write(vfd->fd, buffer, size); 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 & MEMORY_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_READONLY;
int mapFiles = FILE_MAP_READ;
if (flags & MEMORY_WRITE) {
createFlags = PAGE_READWRITE;
mapFiles = FILE_MAP_WRITE;
}
size_t location = lseek(vfd->fd, 0, SEEK_CUR);
size_t fileSize = lseek(vfd->fd, 0, SEEK_END);
lseek(vfd->fd, location, SEEK_SET);
if (size > fileSize) {
size = fileSize;
}
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
return MapViewOfFile(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);
}

View File

@ -3,12 +3,17 @@
#include "common.h" #include "common.h"
#include "memory.h"
struct VFile { struct VFile {
bool (*close)(struct VFile* vf); bool (*close)(struct VFile* vf);
size_t (*seek)(struct VFile* vf, off_t offset, int whence); size_t (*seek)(struct VFile* vf, off_t offset, int whence);
size_t (*read)(struct VFile* vf, void* buffer, size_t size); size_t (*read)(struct VFile* vf, void* buffer, size_t size);
size_t (*readline)(struct VFile* vf, char* buffer, size_t size); size_t (*readline)(struct VFile* vf, char* buffer, size_t size);
size_t (*write)(struct VFile* vf, void* buffer, size_t size); size_t (*write)(struct VFile* vf, void* buffer, size_t size);
void* (*map)(struct VFile* vf, size_t size, int flags);
void (*unmap)(struct VFile* vf, void* memory, size_t size);
void (*truncate)(struct VFile* vf, size_t size);
}; };
struct VFile* VFileOpen(const char* path, int flags); struct VFile* VFileOpen(const char* path, int flags);