all repos — mgba @ 68e70b61f19b1e2b34e39be0c4dff35a84f2d313

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 _vfdReadline(struct VFile* vf, char* 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 VFileFD* vfd = malloc(sizeof(struct VFileFD));
 56	if (!vfd) {
 57		return 0;
 58	}
 59
 60	vfd->fd = fd;
 61	vfd->d.close = _vfdClose;
 62	vfd->d.seek = _vfdSeek;
 63	vfd->d.read = _vfdRead;
 64	vfd->d.readline = _vfdReadline;
 65	vfd->d.write = _vfdWrite;
 66	vfd->d.map = _vfdMap;
 67	vfd->d.unmap = _vfdUnmap;
 68	vfd->d.truncate = _vfdTruncate;
 69	vfd->d.size = _vfdSize;
 70	vfd->d.sync = _vfdSync;
 71
 72	return &vfd->d;
 73}
 74
 75bool _vfdClose(struct VFile* vf) {
 76	struct VFileFD* vfd = (struct VFileFD*) vf;
 77	if (close(vfd->fd) < 0) {
 78		return false;
 79	}
 80	free(vfd);
 81	return true;
 82}
 83
 84off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
 85	struct VFileFD* vfd = (struct VFileFD*) vf;
 86	return lseek(vfd->fd, offset, whence);
 87}
 88
 89ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
 90	struct VFileFD* vfd = (struct VFileFD*) vf;
 91	return read(vfd->fd, buffer, size);
 92}
 93
 94ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
 95	struct VFileFD* vfd = (struct VFileFD*) vf;
 96	size_t bytesRead = 0;
 97	while (bytesRead < size - 1) {
 98		size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
 99		if (!newRead || buffer[bytesRead] == '\n') {
100			break;
101		}
102		bytesRead += newRead;
103	}
104	buffer[bytesRead] = '\0';
105	return bytesRead;
106}
107
108ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) {
109	struct VFileFD* vfd = (struct VFileFD*) vf;
110	return write(vfd->fd, buffer, size);
111}
112
113#ifndef _WIN32
114static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
115	struct VFileFD* vfd = (struct VFileFD*) vf;
116	int mmapFlags = MAP_PRIVATE;
117	if (flags & MAP_WRITE) {
118		mmapFlags = MAP_SHARED;
119	}
120	return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
121}
122
123static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
124	UNUSED(vf);
125	munmap(memory, size);
126}
127#else
128static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
129	struct VFileFD* vfd = (struct VFileFD*) vf;
130	int createFlags = PAGE_WRITECOPY;
131	int mapFiles = FILE_MAP_COPY;
132	if (flags & MAP_WRITE) {
133		createFlags = PAGE_READWRITE;
134		mapFiles = FILE_MAP_WRITE;
135	}
136	size_t fileSize;
137	struct stat stat;
138	if (fstat(vfd->fd, &stat) < 0) {
139		return 0;
140	}
141	fileSize = stat.st_size;
142	if (size > fileSize) {
143		size = fileSize;
144	}
145	vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
146	return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
147}
148
149static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
150	UNUSED(size);
151	struct VFileFD* vfd = (struct VFileFD*) vf;
152	UnmapViewOfFile(memory);
153	CloseHandle(vfd->hMap);
154	vfd->hMap = 0;
155}
156#endif
157
158static void _vfdTruncate(struct VFile* vf, size_t size) {
159	struct VFileFD* vfd = (struct VFileFD*) vf;
160	ftruncate(vfd->fd, size);
161}
162
163static ssize_t _vfdSize(struct VFile* vf) {
164	struct VFileFD* vfd = (struct VFileFD*) vf;
165	struct stat stat;
166	if (fstat(vfd->fd, &stat) < 0) {
167		return -1;
168	}
169	return stat.st_size;
170}
171
172static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size) {
173	UNUSED(buffer);
174	UNUSED(size);
175	struct VFileFD* vfd = (struct VFileFD*) vf;
176#ifndef _WIN32
177	return fsync(vfd->fd) == 0;
178#else
179	return FlushFileBuffers((HANDLE) _get_osfhandle(vfd->fd));
180#endif
181}