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}