all repos — mgba @ b4c3440bc4b8bf85cd91f3571c91f4a6a958c7aa

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