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}