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 "util/memory.h"
#include "util/vfile.h"
#include <errno.h>
#include <fcntl.h>
@ -16,7 +17,7 @@ void GBASavedataInit(struct GBASavedata* savedata, const char* filename) {
savedata->data = 0;
savedata->command = EEPROM_COMMAND_NULL;
savedata->flashState = FLASH_STATE_RAW;
savedata->fd = -1;
savedata->vf = 0;
savedata->filename = filename;
}
@ -29,6 +30,26 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type)
}
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) {
case SAVEDATA_SRAM:
mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
@ -42,11 +63,9 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
case SAVEDATA_EEPROM:
mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
break;
default:
case SAVEDATA_NONE:
break;
}
if (savedata->fd >= 0) {
close(savedata->fd);
}
savedata->type = SAVEDATA_NONE;
}
@ -59,18 +78,18 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
return;
}
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666);
savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
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);
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
} else {
end = lseek(savedata->fd, 0, SEEK_END);
end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
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;
@ -86,18 +105,18 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
return;
}
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666);
savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
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);
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
} else {
end = lseek(savedata->fd, 0, SEEK_END);
end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
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) {
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");
return;
}
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666);
savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT);
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);
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
} else {
end = lseek(savedata->fd, 0, SEEK_END);
end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
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) {
@ -299,7 +318,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
savedata->currentBank = &savedata->data[bank << 16];
if (bank > 0) {
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"
struct VFile;
enum SavedataType {
SAVEDATA_NONE = 0,
SAVEDATA_SRAM,
@ -55,7 +57,7 @@ struct GBASavedata {
uint8_t* data;
const char* filename;
enum SavedataCommand command;
int fd;
struct VFile* vf;
int readBitsRemaining;
int readAddress;

View File

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

View File

@ -225,13 +225,17 @@ struct GBASerializedState {
uint8_t wram[SIZE_WORKING_RAM];
};
struct VFile;
void GBASerialize(struct GBA* gba, struct GBASerializedState* state);
void GBADeserialize(struct GBA* gba, struct GBASerializedState* state);
bool GBASaveState(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);
void GBADeallocateState(struct GBASerializedState* state);

View File

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

View File

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

View File

@ -7,8 +7,7 @@
#include "util/memory.h"
#include "util/patch.h"
#include <sys/stat.h>
#include "util/vfile.h"
const uint32_t GBA_ARM7TDMI_FREQUENCY = 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->rumble = 0;
gba->romVf = 0;
gba->biosVf = 0;
gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
@ -143,7 +145,15 @@ void GBADestroy(struct GBA* gba) {
if (gba->pristineRom == gba->memory.rom) {
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);
GBAVideoDeinit(&gba->video);
GBAAudioDeinit(&gba->audio);
@ -363,13 +373,13 @@ void GBADetachDebugger(struct GBA* gba) {
gba->debugger = 0;
}
void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
struct stat info;
gba->pristineRom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ);
void GBALoadROM(struct GBA* gba, struct VFile* vf, const char* fname) {
gba->romVf = vf;
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->activeFile = fname;
fstat(fd, &info);
gba->pristineRomSize = info.st_size;
gba->memory.romSize = gba->pristineRomSize;
if (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
}
void GBALoadBIOS(struct GBA* gba, int fd) {
gba->memory.bios = fileMemoryMap(fd, SIZE_BIOS, MEMORY_READ);
void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
gba->biosVf = vf;
gba->memory.bios = vf->map(vf, SIZE_BIOS, MEMORY_READ);
gba->memory.fullBios = 1;
uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);

View File

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

View File

@ -5,13 +5,6 @@
void* anonymousMemoryMap(size_t size) {
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) {
munmap(memory, size);

View File

@ -8,23 +8,6 @@ void* anonymousMemoryMap(size_t 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) {
// TODO fill in
}

View File

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

View File

@ -2,9 +2,19 @@
#include <fcntl.h>
#ifndef _WIN32
#include <sys/mman.h>
#else
#include <io.h>
#include <Windows.h>
#endif
struct VFileFD {
struct VFile d;
int fd;
#ifdef _WIN32
HANDLE hMap;
#endif
};
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 _vfdReadline(struct VFile* vf, char* 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) {
int fd = open(path, flags);
int fd = open(path, flags, 0666);
return VFileFromFD(fd);
}
@ -34,6 +47,9 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.read = _vfdRead;
vfd->d.readline = _vfdReadline;
vfd->d.write = _vfdWrite;
vfd->d.map = _vfdMap;
vfd->d.unmap = _vfdUnmap;
vfd->d.truncate = _vfdTruncate;
return &vfd->d;
}
@ -74,3 +90,50 @@ size_t _vfdWrite(struct VFile* vf, 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 & 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 "memory.h"
struct VFile {
bool (*close)(struct VFile* vf);
size_t (*seek)(struct VFile* vf, off_t offset, int whence);
size_t (*read)(struct VFile* vf, void* 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);
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);