posix_compat.cpp 6.2 KB

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