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