Line data Source code
1 : /*
2 : This program is free software: you can redistribute it and/or modify
3 : it under the terms of the GNU General Public License as published by
4 : the Free Software Foundation, either version 3 of the License, or
5 : (at your option) any later version.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program. If not, see <http://www.gnu.org/licenses/>.
14 : */
15 : /*
16 : compatibility with posix APIs using AP_Filesystem
17 :
18 : This implements the FILE* API from posix sufficiently well for Lua
19 : scripting to function. It has no buffering so is inefficient for
20 : single character operations. We deliberately use this implementation
21 : in HAL_SITL and HAL_Linux where it is not needed in order to have a
22 : uniform implementation across all platforms
23 : */
24 :
25 : #include "AP_Filesystem.h"
26 :
27 : #if AP_FILESYSTEM_FATFS_ENABLED || AP_FILESYSTEM_POSIX_ENABLED || AP_FILESYSTEM_ESP32_ENABLED || AP_FILESYSTEM_ROMFS_ENABLED
28 :
29 : #include "posix_compat.h"
30 : #include <stdarg.h>
31 : #include <AP_Math/AP_Math.h>
32 :
33 : #define CHECK_STREAM(stream, ret) while (stream == NULL || stream->fd < 0) { errno = EBADF; return ret; }
34 :
35 : #define modecmp(str, pat) (strcmp(str, pat) == 0 ? 1: 0)
36 :
37 : /*
38 : map a fopen() file mode to a open() mode
39 : */
40 170 : static int posix_fopen_modes_to_open(const char *mode)
41 : {
42 170 : int flag = 0;
43 :
44 170 : if (modecmp(mode,"r") || modecmp(mode,"rb")) {
45 170 : flag = O_RDONLY;
46 170 : return flag;
47 : }
48 0 : if (modecmp(mode,"r+") || modecmp(mode, "r+b" ) || modecmp(mode, "rb+" )) {
49 0 : flag = O_RDWR | O_TRUNC;
50 0 : return flag;
51 : }
52 0 : if (modecmp(mode,"w") || modecmp(mode,"wb")) {
53 0 : flag = O_WRONLY | O_CREAT | O_TRUNC;
54 0 : return flag;
55 : }
56 0 : if (modecmp(mode,"w+") || modecmp(mode, "w+b" ) || modecmp(mode, "wb+" )) {
57 0 : flag = O_RDWR | O_CREAT | O_TRUNC;
58 0 : return flag;
59 : }
60 0 : if (modecmp(mode,"a") || modecmp(mode,"ab")) {
61 0 : flag = O_WRONLY | O_CREAT | O_APPEND;
62 0 : return flag;
63 : }
64 0 : if (modecmp(mode,"a+") || modecmp(mode, "a+b" ) || modecmp(mode, "ab+" )) {
65 0 : flag = O_RDWR | O_CREAT | O_APPEND;
66 0 : return flag;
67 : }
68 0 : return -1;
69 : }
70 :
71 170 : APFS_FILE *apfs_fopen(const char *pathname, const char *mode)
72 : {
73 170 : APFS_FILE *f = NEW_NOTHROW APFS_FILE;
74 170 : if (!f) {
75 0 : return nullptr;
76 : }
77 170 : f->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
78 170 : if (f->fd == -1) {
79 39 : delete f;
80 39 : return nullptr;
81 : }
82 131 : f->unget = -1;
83 131 : return f;
84 : }
85 :
86 0 : int apfs_fprintf(APFS_FILE *stream, const char *fmt, ...)
87 : {
88 0 : CHECK_STREAM(stream, -1);
89 : va_list va;
90 0 : char* buf = NULL;
91 : int16_t len;
92 0 : va_start(va, fmt);
93 0 : len = vasprintf(&buf, fmt, va);
94 0 : va_end(va);
95 0 : if (len > 0) {
96 0 : len = AP::FS().write(stream->fd, buf, len);
97 0 : free(buf);
98 : }
99 :
100 0 : return len;
101 : }
102 :
103 0 : int apfs_fflush(APFS_FILE *stream)
104 : {
105 0 : CHECK_STREAM(stream, EOF);
106 0 : if (AP::FS().fsync(stream->fd) == 0) {
107 0 : return 0;
108 : }
109 0 : return EOF;
110 : }
111 :
112 6448 : size_t apfs_fread(void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
113 : {
114 6448 : CHECK_STREAM(stream, 0);
115 6448 : ssize_t ret = AP::FS().read(stream->fd, ptr, size*nmemb);
116 6448 : if (ret <= 0) {
117 111 : stream->eof = true;
118 111 : return 0;
119 : }
120 6337 : return ret / size;
121 : }
122 :
123 0 : size_t apfs_fwrite(const void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
124 : {
125 0 : CHECK_STREAM(stream, 0);
126 0 : ssize_t ret = AP::FS().write(stream->fd, ptr, size*nmemb);
127 0 : if (ret <= 0) {
128 0 : stream->error = true;
129 0 : return 0;
130 : }
131 0 : return ret / size;
132 : }
133 :
134 0 : int apfs_fputs(const char *s, APFS_FILE *stream)
135 : {
136 0 : CHECK_STREAM(stream, EOF);
137 0 : ssize_t ret = AP::FS().write(stream->fd, s, strlen(s));
138 0 : if (ret < 0) {
139 0 : stream->error = true;
140 0 : return EOF;
141 : }
142 0 : return ret;
143 : }
144 :
145 : #undef fgets
146 0 : char *apfs_fgets(char *s, int size, APFS_FILE *stream)
147 : {
148 0 : CHECK_STREAM(stream, NULL);
149 0 : auto &fs = AP::FS();
150 0 : if (!fs.fgets(s, size, stream->fd)) {
151 0 : return NULL;
152 : }
153 0 : return s;
154 : }
155 :
156 102 : void apfs_clearerr(APFS_FILE *stream)
157 : {
158 102 : stream->error = false;
159 102 : }
160 :
161 0 : int apfs_fseek(APFS_FILE *stream, long offset, int whence)
162 : {
163 0 : CHECK_STREAM(stream, EOF);
164 0 : stream->eof = false;
165 0 : AP::FS().lseek(stream->fd, offset, whence);
166 0 : return 0;
167 : }
168 :
169 6661 : int apfs_ferror(APFS_FILE *stream)
170 : {
171 6661 : CHECK_STREAM(stream, EOF);
172 6661 : return stream->error;
173 : }
174 :
175 131 : int apfs_fclose(APFS_FILE *stream)
176 : {
177 131 : CHECK_STREAM(stream, EOF);
178 131 : int ret = AP::FS().close(stream->fd);
179 131 : stream->fd = -1;
180 131 : if (stream->tmpfile_name) {
181 0 : AP::FS().unlink(stream->tmpfile_name);
182 0 : free(stream->tmpfile_name);
183 0 : stream->tmpfile_name = NULL;
184 : }
185 131 : delete stream;
186 131 : return ret;
187 : }
188 :
189 0 : APFS_FILE *apfs_tmpfile(void)
190 : {
191 0 : char *fname = NULL;
192 0 : if (asprintf(&fname, "tmp.%03u", unsigned(get_random16()) % 1000) <= 0) {
193 0 : return NULL;
194 : }
195 0 : APFS_FILE *ret = apfs_fopen(fname, "w");
196 0 : if (!ret) {
197 0 : free(fname);
198 0 : return NULL;
199 : }
200 0 : ret->tmpfile_name = fname;
201 0 : return ret;
202 : }
203 :
204 4003 : int apfs_getc(APFS_FILE *stream)
205 : {
206 4003 : CHECK_STREAM(stream, EOF);
207 : uint8_t c;
208 4003 : if (stream->unget != -1) {
209 0 : c = stream->unget;
210 0 : stream->unget = -1;
211 0 : return c;
212 : }
213 4003 : ssize_t ret = AP::FS().read(stream->fd, &c, 1);
214 4003 : if (ret <= 0) {
215 1 : stream->eof = true;
216 1 : return EOF;
217 : }
218 4002 : return c;
219 : }
220 :
221 0 : int apfs_ungetc(int c, APFS_FILE *stream)
222 : {
223 0 : CHECK_STREAM(stream, EOF);
224 0 : stream->unget = c;
225 0 : stream->eof = false;
226 0 : return c;
227 : }
228 :
229 0 : int apfs_feof(APFS_FILE *stream)
230 : {
231 0 : return stream->eof;
232 : }
233 :
234 0 : APFS_FILE *apfs_freopen(const char *pathname, const char *mode, APFS_FILE *stream)
235 : {
236 0 : CHECK_STREAM(stream, NULL);
237 0 : int ret = AP::FS().close(stream->fd);
238 0 : if (ret < 0) {
239 0 : return NULL;
240 : }
241 0 : if (stream->tmpfile_name) {
242 0 : AP::FS().unlink(stream->tmpfile_name);
243 0 : free(stream->tmpfile_name);
244 0 : stream->tmpfile_name = NULL;
245 : }
246 0 : stream->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
247 0 : stream->error = false;
248 0 : stream->eof = false;
249 0 : stream->unget = -1;
250 0 : return stream;
251 : }
252 :
253 0 : long apfs_ftell(APFS_FILE *stream)
254 : {
255 0 : CHECK_STREAM(stream, EOF);
256 0 : return AP::FS().lseek(stream->fd, 0, SEEK_CUR);
257 : }
258 :
259 0 : int apfs_remove(const char *pathname)
260 : {
261 0 : return AP::FS().unlink(pathname);
262 : }
263 :
264 : #endif // AP_FILESYSTEM_POSIX_ENABLED
|