LCOV - code coverage report
Current view: top level - AP_Filesystem - posix_compat.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 42 141 29.8 %
Date: 2026-09-09 11:02:08 Functions: 7 19 36.8 %

          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

Generated by: LCOV version 1.14