src/util/vfile.c (view raw)
1#include "util/vfile.h"
2
3#include <fcntl.h>
4
5#ifndef _WIN32
6#include <sys/mman.h>
7#else
8#include <io.h>
9#include <Windows.h>
10#endif
11
12struct VFileFD {
13 struct VFile d;
14 int fd;
15#ifdef _WIN32
16 HANDLE hMap;
17#endif
18};
19
20static bool _vfdClose(struct VFile* vf);
21static size_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
22static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
23static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
24static size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size);
25static void* _vfdMap(struct VFile* vf, size_t size, int flags);
26static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
27static void _vfdTruncate(struct VFile* vf, size_t size);
28
29struct VFile* VFileOpen(const char* path, int flags) {
30 int fd = open(path, flags, 0666);
31 return VFileFromFD(fd);
32}
33
34struct VFile* VFileFromFD(int fd) {
35 if (fd < 0) {
36 return 0;
37 }
38
39 struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
40 if (!vfd) {
41 return 0;
42 }
43
44 vfd->fd = fd;
45 vfd->d.close = _vfdClose;
46 vfd->d.seek = _vfdSeek;
47 vfd->d.read = _vfdRead;
48 vfd->d.readline = _vfdReadline;
49 vfd->d.write = _vfdWrite;
50 vfd->d.map = _vfdMap;
51 vfd->d.unmap = _vfdUnmap;
52 vfd->d.truncate = _vfdTruncate;
53
54 return &vfd->d;
55}
56
57bool _vfdClose(struct VFile* vf) {
58 struct VFileFD* vfd = (struct VFileFD*) vf;
59 if (close(vfd->fd) < 0) {
60 return false;
61 }
62 free(vfd);
63 return true;
64}
65
66size_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
67 struct VFileFD* vfd = (struct VFileFD*) vf;
68 return lseek(vfd->fd, offset, whence);
69}
70
71size_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
72 struct VFileFD* vfd = (struct VFileFD*) vf;
73 return read(vfd->fd, buffer, size);
74}
75
76size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
77 struct VFileFD* vfd = (struct VFileFD*) vf;
78 size_t bytesRead = 0;
79 while (bytesRead < size - 1) {
80 size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
81 bytesRead += newRead;
82 if (!newRead || buffer[bytesRead] == '\n') {
83 break;
84 }
85 }
86 return buffer[bytesRead] = '\0';
87}
88
89size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size) {
90 struct VFileFD* vfd = (struct VFileFD*) vf;
91 return write(vfd->fd, buffer, size);
92}
93
94#ifndef _WIN32
95static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
96 struct VFileFD* vfd = (struct VFileFD*) vf;
97 int mmapFlags = MAP_PRIVATE;
98 if (flags & MEMORY_WRITE) {
99 mmapFlags = MAP_SHARED;
100 }
101 return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
102}
103
104static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
105 UNUSED(vf);
106 munmap(memory, size);
107}
108#else
109static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
110 struct VFileFD* vfd = (struct VFileFD*) vf;
111 int createFlags = PAGE_READONLY;
112 int mapFiles = FILE_MAP_READ;
113 if (flags & MEMORY_WRITE) {
114 createFlags = PAGE_READWRITE;
115 mapFiles = FILE_MAP_WRITE;
116 }
117 size_t location = lseek(vfd->fd, 0, SEEK_CUR);
118 size_t fileSize = lseek(vfd->fd, 0, SEEK_END);
119 lseek(vfd->fd, location, SEEK_SET);
120 if (size > fileSize) {
121 size = fileSize;
122 }
123 vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
124 return MapViewOfFile(hMap, mapFiles, 0, 0, size);
125}
126
127static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
128 UNUSED(size);
129 struct VFileFD* vfd = (struct VFileFD*) vf;
130 UnmapViewOfFile(memory);
131 CloseHandle(vfd->hMap);
132 vfd->hMap = 0;
133}
134#endif
135
136static void _vfdTruncate(struct VFile* vf, size_t size) {
137 struct VFileFD* vfd = (struct VFileFD*) vf;
138 ftruncate(vfd->fd, size);
139}