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