all repos — mgba @ 289e9b0cf12c5458afecfccdabf59f83f161214f

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#endif
 13
 14struct VFileFD {
 15	struct VFile d;
 16	int fd;
 17#ifdef _WIN32
 18	HANDLE hMap;
 19#endif
 20};
 21
 22static bool _vfdClose(struct VFile* vf);
 23static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
 24static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
 25static ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
 26static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size);
 27static void* _vfdMap(struct VFile* vf, size_t size, int flags);
 28static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
 29static void _vfdTruncate(struct VFile* vf, size_t size);
 30static ssize_t _vfdSize(struct VFile* vf);
 31
 32struct VFile* VFileOpen(const char* path, int flags) {
 33	if (!path) {
 34		return 0;
 35	}
 36#ifdef _WIN32
 37	flags |= O_BINARY;
 38#endif
 39	int fd = open(path, flags, 0666);
 40	return VFileFromFD(fd);
 41}
 42
 43struct VFile* VFileFromFD(int fd) {
 44	if (fd < 0) {
 45		return 0;
 46	}
 47
 48	struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
 49	if (!vfd) {
 50		return 0;
 51	}
 52
 53	vfd->fd = fd;
 54	vfd->d.close = _vfdClose;
 55	vfd->d.seek = _vfdSeek;
 56	vfd->d.read = _vfdRead;
 57	vfd->d.readline = _vfdReadline;
 58	vfd->d.write = _vfdWrite;
 59	vfd->d.map = _vfdMap;
 60	vfd->d.unmap = _vfdUnmap;
 61	vfd->d.truncate = _vfdTruncate;
 62	vfd->d.size = _vfdSize;
 63
 64	return &vfd->d;
 65}
 66
 67bool _vfdClose(struct VFile* vf) {
 68	struct VFileFD* vfd = (struct VFileFD*) vf;
 69	if (close(vfd->fd) < 0) {
 70		return false;
 71	}
 72	free(vfd);
 73	return true;
 74}
 75
 76off_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
 77	struct VFileFD* vfd = (struct VFileFD*) vf;
 78	return lseek(vfd->fd, offset, whence);
 79}
 80
 81ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
 82	struct VFileFD* vfd = (struct VFileFD*) vf;
 83	return read(vfd->fd, buffer, size);
 84}
 85
 86ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
 87	struct VFileFD* vfd = (struct VFileFD*) vf;
 88	size_t bytesRead = 0;
 89	while (bytesRead < size - 1) {
 90		size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
 91		if (!newRead || buffer[bytesRead] == '\n') {
 92			break;
 93		}
 94		bytesRead += newRead;
 95	}
 96	buffer[bytesRead] = '\0';
 97	return bytesRead;
 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}