all repos — mgba @ 6d898542c765f4efc4a094c5ebd3f3465c36f417

mGBA Game Boy Advance Emulator

src/util/vfs/vfs-fd.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "util/vfs.h"
  7
  8#include <fcntl.h>
  9#include <sys/stat.h>
 10#ifndef _WIN32
 11#include <sys/mman.h>
 12#include <sys/time.h>
 13#else
 14#include <windows.h>
 15#endif
 16
 17struct VFileFD {
 18	struct VFile d;
 19	int fd;
 20#ifdef _WIN32
 21	HANDLE hMap;
 22#endif
 23};
 24
 25static bool _vfdClose(struct VFile* vf);
 26static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
 27static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
 28static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size);
 29static void* _vfdMap(struct VFile* vf, size_t size, int flags);
 30static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
 31static void _vfdTruncate(struct VFile* vf, size_t size);
 32static ssize_t _vfdSize(struct VFile* vf);
 33static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size);
 34
 35struct VFile* VFileOpenFD(const char* path, int flags) {
 36	if (!path) {
 37		return 0;
 38	}
 39#ifdef _WIN32
 40	flags |= O_BINARY;
 41	wchar_t wpath[PATH_MAX];
 42	MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath) / sizeof(*wpath));
 43	int fd = _wopen(wpath, flags, 0666);
 44#else
 45	int fd = open(path, flags, 0666);
 46#endif
 47	return VFileFromFD(fd);
 48}
 49
 50struct VFile* VFileFromFD(int fd) {
 51	if (fd < 0) {
 52		return 0;
 53	}
 54
 55	struct stat stat;
 56	if (fstat(fd, &stat) < 0 || S_ISDIR(stat.st_mode)) {
 57		close(fd);
 58		return 0;
 59	}
 60
 61	struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
 62	if (!vfd) {
 63		return 0;
 64	}
 65
 66	vfd->fd = fd;
 67	vfd->d.close = _vfdClose;
 68	vfd->d.seek = _vfdSeek;
 69	vfd->d.read = _vfdRead;
 70	vfd->d.readline = VFileReadline;
 71	vfd->d.write = _vfdWrite;
 72	vfd->d.map = _vfdMap;
 73	vfd->d.unmap = _vfdUnmap;
 74	vfd->d.truncate = _vfdTruncate;
 75	vfd->d.size = _vfdSize;
 76	vfd->d.sync = _vfdSync;
 77
 78	return &vfd->d;
 79}
 80
 81bool _vfdClose(struct VFile* vf) {
 82	struct VFileFD* vfd = (struct VFileFD*) vf;
 83	if (close(vfd->fd) < 0) {
 84		return false;
 85	}
 86	free(vfd);
 87	return true;
 88}
 89
 90off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
 91	struct VFileFD* vfd = (struct VFileFD*) vf;
 92	return lseek(vfd->fd, offset, whence);
 93}
 94
 95ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
 96	struct VFileFD* vfd = (struct VFileFD*) vf;
 97	return read(vfd->fd, buffer, size);
 98}
 99
100ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) {
101	struct VFileFD* vfd = (struct VFileFD*) vf;
102	return write(vfd->fd, buffer, size);
103}
104
105#ifndef _WIN32
106static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
107	struct VFileFD* vfd = (struct VFileFD*) vf;
108	int mmapFlags = MAP_PRIVATE;
109	if (flags & MAP_WRITE) {
110		mmapFlags = MAP_SHARED;
111	}
112	return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
113}
114
115static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
116	UNUSED(vf);
117	munmap(memory, size);
118}
119#else
120static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
121	struct VFileFD* vfd = (struct VFileFD*) vf;
122	int createFlags = PAGE_WRITECOPY;
123	int mapFiles = FILE_MAP_COPY;
124	if (flags & MAP_WRITE) {
125		createFlags = PAGE_READWRITE;
126		mapFiles = FILE_MAP_WRITE;
127	}
128	size_t fileSize;
129	struct stat stat;
130	if (fstat(vfd->fd, &stat) < 0) {
131		return 0;
132	}
133	fileSize = stat.st_size;
134	if (size > fileSize) {
135		size = fileSize;
136	}
137	vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
138	return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
139}
140
141static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
142	UNUSED(size);
143	struct VFileFD* vfd = (struct VFileFD*) vf;
144	UnmapViewOfFile(memory);
145	CloseHandle(vfd->hMap);
146	vfd->hMap = 0;
147}
148#endif
149
150static void _vfdTruncate(struct VFile* vf, size_t size) {
151	struct VFileFD* vfd = (struct VFileFD*) vf;
152	ftruncate(vfd->fd, size);
153}
154
155static ssize_t _vfdSize(struct VFile* vf) {
156	struct VFileFD* vfd = (struct VFileFD*) vf;
157	struct stat stat;
158	if (fstat(vfd->fd, &stat) < 0) {
159		return -1;
160	}
161	return stat.st_size;
162}
163
164static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size) {
165	UNUSED(buffer);
166	UNUSED(size);
167	struct VFileFD* vfd = (struct VFileFD*) vf;
168#ifndef _WIN32
169	futimes(vfd->fd, NULL);
170	if (buffer && size) {
171		return msync(buffer, size, MS_SYNC) == 0;
172	}
173	return fsync(vfd->fd) == 0;
174#else
175	HANDLE h = (HANDLE) _get_osfhandle(vfd->fd);
176	FILETIME ft;
177	SYSTEMTIME st;
178	GetSystemTime(&st);
179	SystemTimeToFileTime(&st, &ft);
180	SetFileTime(h, NULL, &ft, &ft);
181	return FlushFileBuffers(h);
182#endif
183}