CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_Filesystem/posix_compat.cpp
Views: 1798
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
static int posix_fopen_modes_to_open(const char *mode)
41
{
42
int flag = 0;
43
44
if (modecmp(mode,"r") || modecmp(mode,"rb")) {
45
flag = O_RDONLY;
46
return flag;
47
}
48
if (modecmp(mode,"r+") || modecmp(mode, "r+b" ) || modecmp(mode, "rb+" )) {
49
flag = O_RDWR | O_TRUNC;
50
return flag;
51
}
52
if (modecmp(mode,"w") || modecmp(mode,"wb")) {
53
flag = O_WRONLY | O_CREAT | O_TRUNC;
54
return flag;
55
}
56
if (modecmp(mode,"w+") || modecmp(mode, "w+b" ) || modecmp(mode, "wb+" )) {
57
flag = O_RDWR | O_CREAT | O_TRUNC;
58
return flag;
59
}
60
if (modecmp(mode,"a") || modecmp(mode,"ab")) {
61
flag = O_WRONLY | O_CREAT | O_APPEND;
62
return flag;
63
}
64
if (modecmp(mode,"a+") || modecmp(mode, "a+b" ) || modecmp(mode, "ab+" )) {
65
flag = O_RDWR | O_CREAT | O_APPEND;
66
return flag;
67
}
68
return -1;
69
}
70
71
APFS_FILE *apfs_fopen(const char *pathname, const char *mode)
72
{
73
APFS_FILE *f = NEW_NOTHROW APFS_FILE;
74
if (!f) {
75
return nullptr;
76
}
77
f->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
78
if (f->fd == -1) {
79
delete f;
80
return nullptr;
81
}
82
f->unget = -1;
83
return f;
84
}
85
86
int apfs_fprintf(APFS_FILE *stream, const char *fmt, ...)
87
{
88
CHECK_STREAM(stream, -1);
89
va_list va;
90
char* buf = NULL;
91
int16_t len;
92
va_start(va, fmt);
93
len = vasprintf(&buf, fmt, va);
94
va_end(va);
95
if (len > 0) {
96
len = AP::FS().write(stream->fd, buf, len);
97
free(buf);
98
}
99
100
return len;
101
}
102
103
int apfs_fflush(APFS_FILE *stream)
104
{
105
CHECK_STREAM(stream, EOF);
106
if (AP::FS().fsync(stream->fd) == 0) {
107
return 0;
108
}
109
return EOF;
110
}
111
112
size_t apfs_fread(void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
113
{
114
CHECK_STREAM(stream, 0);
115
ssize_t ret = AP::FS().read(stream->fd, ptr, size*nmemb);
116
if (ret <= 0) {
117
stream->eof = true;
118
return 0;
119
}
120
return ret / size;
121
}
122
123
size_t apfs_fwrite(const void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
124
{
125
CHECK_STREAM(stream, 0);
126
ssize_t ret = AP::FS().write(stream->fd, ptr, size*nmemb);
127
if (ret <= 0) {
128
stream->error = true;
129
return 0;
130
}
131
return ret / size;
132
}
133
134
int apfs_fputs(const char *s, APFS_FILE *stream)
135
{
136
CHECK_STREAM(stream, EOF);
137
ssize_t ret = AP::FS().write(stream->fd, s, strlen(s));
138
if (ret < 0) {
139
stream->error = true;
140
return EOF;
141
}
142
return ret;
143
}
144
145
#undef fgets
146
char *apfs_fgets(char *s, int size, APFS_FILE *stream)
147
{
148
CHECK_STREAM(stream, NULL);
149
auto &fs = AP::FS();
150
if (!fs.fgets(s, size, stream->fd)) {
151
return NULL;
152
}
153
return s;
154
}
155
156
void apfs_clearerr(APFS_FILE *stream)
157
{
158
stream->error = false;
159
}
160
161
int apfs_fseek(APFS_FILE *stream, long offset, int whence)
162
{
163
CHECK_STREAM(stream, EOF);
164
stream->eof = false;
165
AP::FS().lseek(stream->fd, offset, whence);
166
return 0;
167
}
168
169
int apfs_ferror(APFS_FILE *stream)
170
{
171
CHECK_STREAM(stream, EOF);
172
return stream->error;
173
}
174
175
int apfs_fclose(APFS_FILE *stream)
176
{
177
CHECK_STREAM(stream, EOF);
178
int ret = AP::FS().close(stream->fd);
179
stream->fd = -1;
180
if (stream->tmpfile_name) {
181
AP::FS().unlink(stream->tmpfile_name);
182
free(stream->tmpfile_name);
183
stream->tmpfile_name = NULL;
184
}
185
delete stream;
186
return ret;
187
}
188
189
APFS_FILE *apfs_tmpfile(void)
190
{
191
char *fname = NULL;
192
if (asprintf(&fname, "tmp.%03u", unsigned(get_random16()) % 1000) <= 0) {
193
return NULL;
194
}
195
APFS_FILE *ret = apfs_fopen(fname, "w");
196
if (!ret) {
197
free(fname);
198
return NULL;
199
}
200
ret->tmpfile_name = fname;
201
return ret;
202
}
203
204
int apfs_getc(APFS_FILE *stream)
205
{
206
CHECK_STREAM(stream, EOF);
207
uint8_t c;
208
if (stream->unget != -1) {
209
c = stream->unget;
210
stream->unget = -1;
211
return c;
212
}
213
ssize_t ret = AP::FS().read(stream->fd, &c, 1);
214
if (ret <= 0) {
215
stream->eof = true;
216
return EOF;
217
}
218
return c;
219
}
220
221
int apfs_ungetc(int c, APFS_FILE *stream)
222
{
223
CHECK_STREAM(stream, EOF);
224
stream->unget = c;
225
stream->eof = false;
226
return c;
227
}
228
229
int apfs_feof(APFS_FILE *stream)
230
{
231
return stream->eof;
232
}
233
234
APFS_FILE *apfs_freopen(const char *pathname, const char *mode, APFS_FILE *stream)
235
{
236
CHECK_STREAM(stream, NULL);
237
int ret = AP::FS().close(stream->fd);
238
if (ret < 0) {
239
return NULL;
240
}
241
if (stream->tmpfile_name) {
242
AP::FS().unlink(stream->tmpfile_name);
243
free(stream->tmpfile_name);
244
stream->tmpfile_name = NULL;
245
}
246
stream->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
247
stream->error = false;
248
stream->eof = false;
249
stream->unget = -1;
250
return stream;
251
}
252
253
long apfs_ftell(APFS_FILE *stream)
254
{
255
CHECK_STREAM(stream, EOF);
256
return AP::FS().lseek(stream->fd, 0, SEEK_CUR);
257
}
258
259
int apfs_remove(const char *pathname)
260
{
261
return AP::FS().unlink(pathname);
262
}
263
264
#endif // AP_FILESYSTEM_POSIX_ENABLED
265
266