all repos — mgba @ 7bb17bc99ddd1764c99ce209cc017442e30e339f

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