src/util/vfs/vfs-file.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 "util/memory.h"
9
10#include <errno.h>
11#include <stdio.h>
12
13struct VFileFILE {
14 struct VFile d;
15 FILE* file;
16 bool writable;
17};
18
19static bool _vffClose(struct VFile* vf);
20static off_t _vffSeek(struct VFile* vf, off_t offset, int whence);
21static ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size);
22static ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size);
23static void* _vffMap(struct VFile* vf, size_t size, int flags);
24static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
25static void _vffTruncate(struct VFile* vf, size_t size);
26static ssize_t _vffSize(struct VFile* vf);
27static bool _vffSync(struct VFile* vf, const void* buffer, size_t size);
28
29struct VFile* VFileFOpen(const char* path, const char* mode) {
30 if (!path && !mode) {
31 return 0;
32 }
33 FILE* file = fopen(path, mode);
34 if (!file && errno == ENOENT && strcmp(mode, "r+b") == 0) {
35 file = fopen(path, "w+b");
36 }
37 return VFileFromFILE(file);
38}
39
40struct VFile* VFileFromFILE(FILE* file) {
41 if (!file) {
42 return 0;
43 }
44
45 struct VFileFILE* vff = malloc(sizeof(struct VFileFILE));
46 if (!vff) {
47 return 0;
48 }
49
50 vff->file = file;
51 vff->writable = false;
52 vff->d.close = _vffClose;
53 vff->d.seek = _vffSeek;
54 vff->d.read = _vffRead;
55 vff->d.readline = VFileReadline;
56 vff->d.write = _vffWrite;
57 vff->d.map = _vffMap;
58 vff->d.unmap = _vffUnmap;
59 vff->d.truncate = _vffTruncate;
60 vff->d.size = _vffSize;
61 vff->d.sync = _vffSync;
62
63 return &vff->d;
64}
65
66bool _vffClose(struct VFile* vf) {
67 struct VFileFILE* vff = (struct VFileFILE*) vf;
68 if (fclose(vff->file) < 0) {
69 return false;
70 }
71 free(vff);
72 return true;
73}
74
75off_t _vffSeek(struct VFile* vf, off_t offset, int whence) {
76 struct VFileFILE* vff = (struct VFileFILE*) vf;
77 fseek(vff->file, offset, whence);
78 return ftell(vff->file);
79}
80
81ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) {
82 struct VFileFILE* vff = (struct VFileFILE*) vf;
83 return fread(buffer, 1, size, vff->file);
84}
85
86ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size) {
87 struct VFileFILE* vff = (struct VFileFILE*) vf;
88 return fwrite(buffer, 1, size, vff->file);
89}
90
91static void* _vffMap(struct VFile* vf, size_t size, int flags) {
92 struct VFileFILE* vff = (struct VFileFILE*) vf;
93 if (flags & MAP_WRITE) {
94 vff->writable = true;
95 }
96 void* mem = anonymousMemoryMap(size);
97 if (!mem) {
98 return 0;
99 }
100 long pos = ftell(vff->file);
101 fseek(vff->file, 0, SEEK_SET);
102 fread(mem, size, 1, vff->file);
103 fseek(vff->file, pos, SEEK_SET);
104 return mem;
105}
106
107static void _vffUnmap(struct VFile* vf, void* memory, size_t size) {
108 struct VFileFILE* vff = (struct VFileFILE*) vf;
109 if (vff->writable) {
110 long pos = ftell(vff->file);
111 fseek(vff->file, 0, SEEK_SET);
112 fwrite(memory, size, 1, vff->file);
113 fseek(vff->file, pos, SEEK_SET);
114 }
115 mappedMemoryFree(memory, size);
116}
117
118static void _vffTruncate(struct VFile* vf, size_t size) {
119 struct VFileFILE* vff = (struct VFileFILE*) vf;
120 long pos = ftell(vff->file);
121 fseek(vff->file, 0, SEEK_END);
122 ssize_t realSize = ftell(vff->file);
123 if (realSize < 0) {
124 return;
125 }
126 while (size > (size_t) realSize) {
127 static const char zeros[128] = "";
128 size_t diff = size - realSize;
129 if (diff > sizeof(zeros)) {
130 diff = sizeof(zeros);
131 }
132 fwrite(zeros, diff, 1, vff->file);
133 realSize += diff;
134 }
135 fseek(vff->file, pos, SEEK_SET);
136}
137
138static ssize_t _vffSize(struct VFile* vf) {
139 struct VFileFILE* vff = (struct VFileFILE*) vf;
140 long pos = ftell(vff->file);
141 fseek(vff->file, 0, SEEK_END);
142 ssize_t size = ftell(vff->file);
143 fseek(vff->file, pos, SEEK_SET);
144 return size;
145}
146
147static bool _vffSync(struct VFile* vf, const void* buffer, size_t size) {
148 struct VFileFILE* vff = (struct VFileFILE*) vf;
149 if (buffer && size) {
150 long pos = ftell(vff->file);
151 fseek(vff->file, 0, SEEK_SET);
152 fwrite(buffer, size, 1, vff->file);
153 fseek(vff->file, pos, SEEK_SET);
154 }
155 return fflush(vff->file) == 0;
156}