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