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