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 return fseek(vff->file, offset, whence);
78}
79
80ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) {
81 struct VFileFILE* vff = (struct VFileFILE*) vf;
82 return fread(buffer, 1, size, vff->file);
83}
84
85ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size) {
86 struct VFileFILE* vff = (struct VFileFILE*) vf;
87 return fwrite(buffer, 1, size, vff->file);
88}
89
90static void* _vffMap(struct VFile* vf, size_t size, int flags) {
91 struct VFileFILE* vff = (struct VFileFILE*) vf;
92 if (flags & MAP_WRITE) {
93 vff->writable = true;
94 }
95 void* mem = anonymousMemoryMap(size);
96 if (!mem) {
97 return 0;
98 }
99 long pos = ftell(vff->file);
100 fseek(vff->file, 0, SEEK_SET);
101 fread(mem, size, 1, vff->file);
102 fseek(vff->file, pos, SEEK_SET);
103 return mem;
104}
105
106static void _vffUnmap(struct VFile* vf, void* memory, size_t size) {
107 struct VFileFILE* vff = (struct VFileFILE*) vf;
108 if (vff->writable) {
109 long pos = ftell(vff->file);
110 fseek(vff->file, 0, SEEK_SET);
111 fwrite(memory, size, 1, vff->file);
112 fseek(vff->file, pos, SEEK_SET);
113 }
114 mappedMemoryFree(memory, size);
115}
116
117static void _vffTruncate(struct VFile* vf, size_t size) {
118 struct VFileFILE* vff = (struct VFileFILE*) vf;
119 long pos = ftell(vff->file);
120 fseek(vff->file, 0, SEEK_END);
121 ssize_t realSize = ftell(vff->file);
122 if (realSize < 0) {
123 return;
124 }
125 while (size > (size_t) realSize) {
126 static const char zeros[128] = "";
127 size_t diff = size - realSize;
128 if (diff > sizeof(zeros)) {
129 diff = sizeof(zeros);
130 }
131 fwrite(zeros, diff, 1, vff->file);
132 realSize += diff;
133 }
134 fseek(vff->file, pos, SEEK_SET);
135}
136
137static ssize_t _vffSize(struct VFile* vf) {
138 struct VFileFILE* vff = (struct VFileFILE*) vf;
139 long pos = ftell(vff->file);
140 fseek(vff->file, 0, SEEK_END);
141 ssize_t size = ftell(vff->file);
142 fseek(vff->file, pos, SEEK_SET);
143 return size;
144}
145
146static bool _vffSync(struct VFile* vf, const void* buffer, size_t size) {
147 struct VFileFILE* vff = (struct VFileFILE*) vf;
148 if (buffer && size) {
149 long pos = ftell(vff->file);
150 fseek(vff->file, 0, SEEK_SET);
151 fwrite(buffer, size, 1, vff->file);
152 fseek(vff->file, pos, SEEK_SET);
153 }
154 return fflush(vff->file) == 0;
155}