all repos — mgba @ 8eb4f3ca4d1210e654248605a5fa48546b1d4ee5

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#else
 13#include <windows.h>
 14#endif
 15
 16struct VFileFD {
 17	struct VFile d;
 18	int fd;
 19#ifdef _WIN32
 20	HANDLE hMap;
 21#endif
 22};
 23
 24static bool _vfdClose(struct VFile* vf);
 25static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
 26static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
 27static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size);
 28static void* _vfdMap(struct VFile* vf, size_t size, int flags);
 29static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
 30static void _vfdTruncate(struct VFile* vf, size_t size);
 31static ssize_t _vfdSize(struct VFile* vf);
 32static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size);
 33
 34struct VFile* VFileOpenFD(const char* path, int flags) {
 35	if (!path) {
 36		return 0;
 37	}
 38#ifdef _WIN32
 39	flags |= O_BINARY;
 40	wchar_t wpath[PATH_MAX];
 41	MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath) / sizeof(*wpath));
 42	int fd = _wopen(wpath, flags, 0666);
 43#else
 44	int fd = open(path, flags, 0666);
 45#endif
 46	return VFileFromFD(fd);
 47}
 48
 49struct VFile* VFileFromFD(int fd) {
 50	if (fd < 0) {
 51		return 0;
 52	}
 53
 54	struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
 55	if (!vfd) {
 56		return 0;
 57	}
 58
 59	vfd->fd = fd;
 60	vfd->d.close = _vfdClose;
 61	vfd->d.seek = _vfdSeek;
 62	vfd->d.read = _vfdRead;
 63	vfd->d.readline = VFileReadline;
 64	vfd->d.write = _vfdWrite;
 65	vfd->d.map = _vfdMap;
 66	vfd->d.unmap = _vfdUnmap;
 67	vfd->d.truncate = _vfdTruncate;
 68	vfd->d.size = _vfdSize;
 69	vfd->d.sync = _vfdSync;
 70
 71	return &vfd->d;
 72}
 73
 74bool _vfdClose(struct VFile* vf) {
 75	struct VFileFD* vfd = (struct VFileFD*) vf;
 76	if (close(vfd->fd) < 0) {
 77		return false;
 78	}
 79	free(vfd);
 80	return true;
 81}
 82
 83off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
 84	struct VFileFD* vfd = (struct VFileFD*) vf;
 85	return lseek(vfd->fd, offset, whence);
 86}
 87
 88ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
 89	struct VFileFD* vfd = (struct VFileFD*) vf;
 90	return read(vfd->fd, buffer, size);
 91}
 92
 93ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) {
 94	struct VFileFD* vfd = (struct VFileFD*) vf;
 95	return write(vfd->fd, buffer, size);
 96}
 97
 98#ifndef _WIN32
 99static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
100	struct VFileFD* vfd = (struct VFileFD*) vf;
101	int mmapFlags = MAP_PRIVATE;
102	if (flags & MAP_WRITE) {
103		mmapFlags = MAP_SHARED;
104	}
105	return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
106}
107
108static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
109	UNUSED(vf);
110	munmap(memory, size);
111}
112#else
113static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
114	struct VFileFD* vfd = (struct VFileFD*) vf;
115	int createFlags = PAGE_WRITECOPY;
116	int mapFiles = FILE_MAP_COPY;
117	if (flags & MAP_WRITE) {
118		createFlags = PAGE_READWRITE;
119		mapFiles = FILE_MAP_WRITE;
120	}
121	size_t fileSize;
122	struct stat stat;
123	if (fstat(vfd->fd, &stat) < 0) {
124		return 0;
125	}
126	fileSize = stat.st_size;
127	if (size > fileSize) {
128		size = fileSize;
129	}
130	vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
131	return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
132}
133
134static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
135	UNUSED(size);
136	struct VFileFD* vfd = (struct VFileFD*) vf;
137	UnmapViewOfFile(memory);
138	CloseHandle(vfd->hMap);
139	vfd->hMap = 0;
140}
141#endif
142
143static void _vfdTruncate(struct VFile* vf, size_t size) {
144	struct VFileFD* vfd = (struct VFileFD*) vf;
145	ftruncate(vfd->fd, size);
146}
147
148static ssize_t _vfdSize(struct VFile* vf) {
149	struct VFileFD* vfd = (struct VFileFD*) vf;
150	struct stat stat;
151	if (fstat(vfd->fd, &stat) < 0) {
152		return -1;
153	}
154	return stat.st_size;
155}
156
157static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size) {
158	UNUSED(buffer);
159	UNUSED(size);
160	struct VFileFD* vfd = (struct VFileFD*) vf;
161#ifndef _WIN32
162	return fsync(vfd->fd) == 0;
163#else
164	return FlushFileBuffers((HANDLE) _get_osfhandle(vfd->fd));
165#endif
166}