espidf_file.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /*
  2. * Copyright (C) 2023 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "platform_api_extension.h"
  6. #include "libc_errno.h"
  7. #include <unistd.h>
  8. #if !defined(__APPLE__) && !defined(ESP_PLATFORM)
  9. #define CONFIG_HAS_PWRITEV 1
  10. #define CONFIG_HAS_PREADV 1
  11. #else
  12. #define CONFIG_HAS_PWRITEV 0
  13. #define CONFIG_HAS_PREADV 0
  14. #endif
  15. #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM)
  16. #define CONFIG_HAS_FDATASYNC 1
  17. #else
  18. #define CONFIG_HAS_FDATASYNC 0
  19. #endif
  20. /*
  21. * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header.
  22. * (platform_internal.h)
  23. */
  24. #if !defined(CONFIG_HAS_D_INO)
  25. #if !defined(__NuttX__)
  26. #define CONFIG_HAS_D_INO 1
  27. #define CONFIG_HAS_ISATTY 1
  28. #else
  29. #define CONFIG_HAS_D_INO 0
  30. #endif
  31. #endif
  32. #if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__)
  33. #define CONFIG_HAS_POSIX_FALLOCATE 1
  34. #else
  35. #define CONFIG_HAS_POSIX_FALLOCATE 0
  36. #endif
  37. #if defined(O_DSYNC)
  38. #define CONFIG_HAS_O_DSYNC
  39. #endif
  40. // POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support
  41. // it.
  42. #if defined(O_RSYNC) && !defined(__linux__)
  43. #define CONFIG_HAS_O_RSYNC
  44. #endif
  45. #if defined(O_SYNC)
  46. #define CONFIG_HAS_O_SYNC
  47. #endif
  48. #ifndef STDIN_FILENO
  49. #define STDIN_FILENO 0
  50. #endif
  51. #ifndef STDOUT_FILENO
  52. #define STDOUT_FILENO 1
  53. #endif
  54. #ifndef STDERR_FILENO
  55. #define STDERR_FILENO 2
  56. #endif
  57. // Converts a POSIX timespec to a WASI timestamp.
  58. static __wasi_timestamp_t
  59. convert_timespec(const struct timespec *ts)
  60. {
  61. if (ts->tv_sec < 0)
  62. return 0;
  63. if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000)
  64. return UINT64_MAX;
  65. return (__wasi_timestamp_t)ts->tv_sec * 1000000000
  66. + (__wasi_timestamp_t)ts->tv_nsec;
  67. }
  68. // Converts a POSIX stat structure to a WASI filestat structure
  69. static void
  70. convert_stat(os_file_handle handle, const struct stat *in,
  71. __wasi_filestat_t *out)
  72. {
  73. out->st_dev = in->st_dev;
  74. out->st_ino = in->st_ino;
  75. out->st_nlink = (__wasi_linkcount_t)in->st_nlink;
  76. out->st_size = (__wasi_filesize_t)in->st_size;
  77. #ifdef __APPLE__
  78. out->st_atim = convert_timespec(&in->st_atimespec);
  79. out->st_mtim = convert_timespec(&in->st_mtimespec);
  80. out->st_ctim = convert_timespec(&in->st_ctimespec);
  81. #else
  82. out->st_atim = convert_timespec(&in->st_atim);
  83. out->st_mtim = convert_timespec(&in->st_mtim);
  84. out->st_ctim = convert_timespec(&in->st_ctim);
  85. #endif
  86. // Convert the file type. In the case of sockets there is no way we
  87. // can easily determine the exact socket type.
  88. if (S_ISBLK(in->st_mode)) {
  89. out->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE;
  90. }
  91. else if (S_ISCHR(in->st_mode)) {
  92. out->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE;
  93. }
  94. else if (S_ISDIR(in->st_mode)) {
  95. out->st_filetype = __WASI_FILETYPE_DIRECTORY;
  96. }
  97. else if (S_ISFIFO(in->st_mode)) {
  98. out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
  99. }
  100. else if (S_ISLNK(in->st_mode)) {
  101. out->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK;
  102. }
  103. else if (S_ISREG(in->st_mode)) {
  104. out->st_filetype = __WASI_FILETYPE_REGULAR_FILE;
  105. }
  106. else if (S_ISSOCK(in->st_mode)) {
  107. int socktype;
  108. socklen_t socktypelen = sizeof(socktype);
  109. if (getsockopt(handle, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen)
  110. < 0) {
  111. out->st_filetype = __WASI_FILETYPE_UNKNOWN;
  112. return;
  113. }
  114. switch (socktype) {
  115. case SOCK_DGRAM:
  116. out->st_filetype = __WASI_FILETYPE_SOCKET_DGRAM;
  117. break;
  118. case SOCK_STREAM:
  119. out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
  120. break;
  121. default:
  122. out->st_filetype = __WASI_FILETYPE_UNKNOWN;
  123. return;
  124. }
  125. }
  126. else {
  127. out->st_filetype = __WASI_FILETYPE_UNKNOWN;
  128. }
  129. }
  130. static void
  131. convert_timestamp(__wasi_timestamp_t in, struct timespec *out)
  132. {
  133. // Store sub-second remainder.
  134. #if defined(__SYSCALL_SLONG_TYPE)
  135. out->tv_nsec = (__SYSCALL_SLONG_TYPE)(in % 1000000000);
  136. #else
  137. out->tv_nsec = (long)(in % 1000000000);
  138. #endif
  139. in /= 1000000000;
  140. // Clamp to the maximum in case it would overflow our system's time_t.
  141. out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX;
  142. }
  143. // Converts the provided timestamps and flags to a set of arguments for
  144. // futimens() and utimensat().
  145. static void
  146. convert_utimens_arguments(__wasi_timestamp_t st_atim,
  147. __wasi_timestamp_t st_mtim,
  148. __wasi_fstflags_t fstflags, struct timespec *ts)
  149. {
  150. if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) {
  151. ts[0].tv_nsec = UTIME_NOW;
  152. }
  153. else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) {
  154. convert_timestamp(st_atim, &ts[0]);
  155. }
  156. else {
  157. ts[0].tv_nsec = UTIME_OMIT;
  158. }
  159. if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) {
  160. ts[1].tv_nsec = UTIME_NOW;
  161. }
  162. else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) {
  163. convert_timestamp(st_mtim, &ts[1]);
  164. }
  165. else {
  166. ts[1].tv_nsec = UTIME_OMIT;
  167. }
  168. }
  169. __wasi_errno_t
  170. os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf)
  171. {
  172. struct stat stat_buf;
  173. int ret = fstat(handle, &stat_buf);
  174. if (ret < 0)
  175. return convert_errno(errno);
  176. convert_stat(handle, &stat_buf, buf);
  177. return __WASI_ESUCCESS;
  178. }
  179. __wasi_errno_t
  180. os_fstatat(os_file_handle handle, const char *path,
  181. struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags)
  182. {
  183. struct stat stat_buf;
  184. int ret = fstatat(handle, path, &stat_buf,
  185. (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
  186. ? AT_SYMLINK_FOLLOW
  187. : AT_SYMLINK_NOFOLLOW);
  188. if (ret < 0)
  189. return convert_errno(errno);
  190. convert_stat(handle, &stat_buf, buf);
  191. return __WASI_ESUCCESS;
  192. }
  193. __wasi_errno_t
  194. os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
  195. {
  196. int ret = fcntl(handle, F_GETFL);
  197. if (ret < 0)
  198. return convert_errno(errno);
  199. *flags = 0;
  200. if ((ret & O_APPEND) != 0)
  201. *flags |= __WASI_FDFLAG_APPEND;
  202. #ifdef CONFIG_HAS_O_DSYNC
  203. if ((ret & O_DSYNC) != 0)
  204. *flags |= __WASI_FDFLAG_DSYNC;
  205. #endif
  206. if ((ret & O_NONBLOCK) != 0)
  207. *flags |= __WASI_FDFLAG_NONBLOCK;
  208. #ifdef CONFIG_HAS_O_RSYNC
  209. if ((ret & O_RSYNC) != 0)
  210. *flags |= __WASI_FDFLAG_RSYNC;
  211. #endif
  212. #ifdef CONFIG_HAS_O_SYNC
  213. if ((ret & O_SYNC) != 0)
  214. *flags |= __WASI_FDFLAG_SYNC;
  215. #endif
  216. return __WASI_ESUCCESS;
  217. }
  218. __wasi_errno_t
  219. os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
  220. {
  221. int fcntl_flags = 0;
  222. if ((flags & __WASI_FDFLAG_APPEND) != 0)
  223. fcntl_flags |= O_APPEND;
  224. if ((flags & __WASI_FDFLAG_DSYNC) != 0)
  225. #ifdef CONFIG_HAS_O_DSYNC
  226. fcntl_flags |= O_DSYNC;
  227. #else
  228. return __WASI_ENOTSUP;
  229. #endif
  230. if ((flags & __WASI_FDFLAG_NONBLOCK) != 0)
  231. fcntl_flags |= O_NONBLOCK;
  232. if ((flags & __WASI_FDFLAG_RSYNC) != 0)
  233. #ifdef CONFIG_HAS_O_RSYNC
  234. fcntl_flags |= O_RSYNC;
  235. #else
  236. return __WASI_ENOTSUP;
  237. #endif
  238. if ((flags & __WASI_FDFLAG_SYNC) != 0)
  239. #ifdef CONFIG_HAS_O_SYNC
  240. fcntl_flags |= O_SYNC;
  241. #else
  242. return __WASI_ENOTSUP;
  243. #endif
  244. int ret = fcntl(handle, F_SETFL, fcntl_flags);
  245. if (ret < 0)
  246. return convert_errno(errno);
  247. return __WASI_ESUCCESS;
  248. }
  249. __wasi_errno_t
  250. os_fdatasync(os_file_handle handle)
  251. {
  252. #if CONFIG_HAS_FDATASYNC
  253. int ret = fdatasync(handle);
  254. #else
  255. int ret = fsync(handle);
  256. #endif
  257. if (ret < 0)
  258. return convert_errno(errno);
  259. return __WASI_ESUCCESS;
  260. }
  261. __wasi_errno_t
  262. os_fsync(os_file_handle handle)
  263. {
  264. int ret = fsync(handle);
  265. if (ret < 0)
  266. return convert_errno(errno);
  267. return __WASI_ESUCCESS;
  268. }
  269. __wasi_errno_t
  270. os_open_preopendir(const char *path, os_file_handle *out)
  271. {
  272. int fd = open(path, O_RDONLY | O_DIRECTORY, 0);
  273. if (fd < 0)
  274. return convert_errno(errno);
  275. *out = fd;
  276. return __WASI_ESUCCESS;
  277. }
  278. __wasi_errno_t
  279. os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
  280. __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags,
  281. wasi_libc_file_access_mode read_write_mode, os_file_handle *out)
  282. {
  283. int open_flags = 0;
  284. // Convert open flags.
  285. if ((oflags & __WASI_O_CREAT) != 0) {
  286. open_flags |= O_CREAT;
  287. }
  288. if ((oflags & __WASI_O_DIRECTORY) != 0)
  289. open_flags |= O_DIRECTORY;
  290. if ((oflags & __WASI_O_EXCL) != 0)
  291. open_flags |= O_EXCL;
  292. if ((oflags & __WASI_O_TRUNC) != 0) {
  293. open_flags |= O_TRUNC;
  294. }
  295. // Convert file descriptor flags.
  296. if ((fs_flags & __WASI_FDFLAG_APPEND) != 0)
  297. open_flags |= O_APPEND;
  298. if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) {
  299. #ifdef CONFIG_HAS_O_DSYNC
  300. open_flags |= O_DSYNC;
  301. #else
  302. return __WASI_ENOTSUP;
  303. #endif
  304. }
  305. if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0)
  306. open_flags |= O_NONBLOCK;
  307. if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) {
  308. #ifdef CONFIG_HAS_O_RSYNC
  309. open_flags |= O_RSYNC;
  310. #else
  311. return __WASI_ENOTSUP;
  312. #endif
  313. }
  314. if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) {
  315. #ifdef CONFIG_HAS_O_SYNC
  316. open_flags |= O_SYNC;
  317. #else
  318. return __WASI_ENOTSUP;
  319. #endif
  320. }
  321. if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) {
  322. open_flags |= O_NOFOLLOW;
  323. }
  324. switch (read_write_mode) {
  325. case WASI_LIBC_ACCESS_MODE_READ_WRITE:
  326. open_flags |= O_RDWR;
  327. break;
  328. case WASI_LIBC_ACCESS_MODE_READ_ONLY:
  329. open_flags |= O_RDONLY;
  330. break;
  331. case WASI_LIBC_ACCESS_MODE_WRITE_ONLY:
  332. open_flags |= O_WRONLY;
  333. break;
  334. default:
  335. return __WASI_EINVAL;
  336. }
  337. int fd = openat(handle, path, open_flags, 0666);
  338. if (fd < 0) {
  339. int openat_errno = errno;
  340. // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket.
  341. if (openat_errno == ENXIO) {
  342. struct stat sb;
  343. int ret = fstatat(handle, path, &sb,
  344. (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
  345. ? 0
  346. : AT_SYMLINK_NOFOLLOW);
  347. return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP
  348. : __WASI_ENXIO;
  349. }
  350. // Linux returns ENOTDIR instead of ELOOP when using
  351. // O_NOFOLLOW|O_DIRECTORY on a symlink.
  352. if (openat_errno == ENOTDIR
  353. && (open_flags & (O_NOFOLLOW | O_DIRECTORY)) != 0) {
  354. struct stat sb;
  355. int ret = fstatat(handle, path, &sb, AT_SYMLINK_NOFOLLOW);
  356. if (S_ISLNK(sb.st_mode)) {
  357. return __WASI_ELOOP;
  358. }
  359. (void)ret;
  360. }
  361. // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
  362. // a symlink.
  363. if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0
  364. && openat_errno == EMLINK)
  365. return __WASI_ELOOP;
  366. return convert_errno(openat_errno);
  367. }
  368. *out = fd;
  369. return __WASI_ESUCCESS;
  370. }
  371. __wasi_errno_t
  372. os_file_get_access_mode(os_file_handle handle,
  373. wasi_libc_file_access_mode *access_mode)
  374. {
  375. int ret = fcntl(handle, F_GETFL, 0);
  376. if (ret < 0)
  377. return convert_errno(errno);
  378. switch (ret & O_ACCMODE) {
  379. case O_RDONLY:
  380. *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY;
  381. break;
  382. case O_WRONLY:
  383. *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY;
  384. break;
  385. case O_RDWR:
  386. *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
  387. break;
  388. default:
  389. return __WASI_EINVAL;
  390. }
  391. return __WASI_ESUCCESS;
  392. }
  393. __wasi_errno_t
  394. os_close(os_file_handle handle, bool is_stdio)
  395. {
  396. if (is_stdio)
  397. return __WASI_ESUCCESS;
  398. int ret = close(handle);
  399. if (ret < 0)
  400. return convert_errno(errno);
  401. return __WASI_ESUCCESS;
  402. }
  403. __wasi_errno_t
  404. os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
  405. __wasi_filesize_t offset, size_t *nread)
  406. {
  407. #if CONFIG_HAS_PREADV
  408. ssize_t len =
  409. preadv(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
  410. if (len < 0)
  411. return convert_errno(errno);
  412. *nread = (size_t)len;
  413. return __WASI_ESUCCESS;
  414. #else
  415. if (iovcnt == 1) {
  416. ssize_t len = pread(handle, iov->buf, iov->buf_len, offset);
  417. if (len < 0)
  418. return convert_errno(errno);
  419. *nread = len;
  420. return __WASI_ESUCCESS;
  421. }
  422. // Allocate a single buffer to fit all data.
  423. size_t totalsize = 0;
  424. for (int i = 0; i < iovcnt; ++i)
  425. totalsize += iov[i].buf_len;
  426. char *buf = BH_MALLOC(totalsize);
  427. if (buf == NULL) {
  428. return __WASI_ENOMEM;
  429. }
  430. // Perform a single read operation.
  431. ssize_t len = pread(handle, buf, totalsize, offset);
  432. if (len < 0) {
  433. BH_FREE(buf);
  434. return convert_errno(errno);
  435. }
  436. // Copy data back to vectors.
  437. size_t bufoff = 0;
  438. for (int i = 0; i < iovcnt; ++i) {
  439. if (bufoff + iov[i].buf_len < (size_t)len) {
  440. memcpy(iov[i].buf, buf + bufoff, iov[i].buf_len);
  441. bufoff += iov[i].buf_len;
  442. }
  443. else {
  444. memcpy(iov[i].buf, buf + bufoff, len - bufoff);
  445. break;
  446. }
  447. }
  448. BH_FREE(buf);
  449. *nread = len;
  450. return __WASI_ESUCCESS;
  451. #endif
  452. }
  453. __wasi_errno_t
  454. os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
  455. __wasi_filesize_t offset, size_t *nwritten)
  456. {
  457. if (iovcnt == 0)
  458. return __WASI_EINVAL;
  459. ssize_t len = 0;
  460. #if CONFIG_HAS_PWRITEV
  461. len =
  462. pwritev(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
  463. #else
  464. if (iovcnt == 1) {
  465. len = pwrite(handle, iov->buf, iov->buf_len, offset);
  466. }
  467. else {
  468. // Allocate a single buffer to fit all data.
  469. size_t totalsize = 0;
  470. for (int i = 0; i < iovcnt; ++i)
  471. totalsize += iov[i].buf_len;
  472. char *buf = BH_MALLOC(totalsize);
  473. if (buf == NULL) {
  474. return __WASI_ENOMEM;
  475. }
  476. size_t bufoff = 0;
  477. for (int i = 0; i < iovcnt; ++i) {
  478. memcpy(buf + bufoff, iov[i].buf, iov[i].buf_len);
  479. bufoff += iov[i].buf_len;
  480. }
  481. // Perform a single write operation.
  482. len = pwrite(handle, buf, totalsize, offset);
  483. BH_FREE(buf);
  484. }
  485. #endif
  486. if (len < 0)
  487. return convert_errno(errno);
  488. *nwritten = (size_t)len;
  489. return __WASI_ESUCCESS;
  490. }
  491. __wasi_errno_t
  492. os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
  493. size_t *nread)
  494. {
  495. ssize_t len = readv(handle, (const struct iovec *)iov, (int)iovcnt);
  496. if (len < 0)
  497. return convert_errno(errno);
  498. *nread = (size_t)len;
  499. return __WASI_ESUCCESS;
  500. }
  501. __wasi_errno_t
  502. os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
  503. size_t *nwritten)
  504. {
  505. ssize_t len = writev(handle, (const struct iovec *)iov, (int)iovcnt);
  506. if (len < 0)
  507. return convert_errno(errno);
  508. *nwritten = (size_t)len;
  509. return __WASI_ESUCCESS;
  510. }
  511. __wasi_errno_t
  512. os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
  513. __wasi_filesize_t length)
  514. {
  515. #if CONFIG_HAS_POSIX_FALLOCATE
  516. int ret = posix_fallocate(handle, (off_t)offset, (off_t)length);
  517. #else
  518. // At least ensure that the file is grown to the right size.
  519. // TODO(ed): See if this can somehow be implemented without any race
  520. // conditions. We may end up shrinking the file right now.
  521. struct stat sb;
  522. int ret = fstat(handle, &sb);
  523. off_t newsize = (off_t)(offset + length);
  524. if (ret == 0 && sb.st_size < newsize)
  525. ret = ftruncate(handle, newsize);
  526. #endif
  527. if (ret != 0)
  528. return convert_errno(ret);
  529. return __WASI_ESUCCESS;
  530. }
  531. __wasi_errno_t
  532. os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
  533. {
  534. int ret = ftruncate(handle, (off_t)size);
  535. if (ret < 0)
  536. return convert_errno(errno);
  537. return __WASI_ESUCCESS;
  538. }
  539. __wasi_errno_t
  540. os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
  541. __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags)
  542. {
  543. struct timespec ts[2];
  544. convert_utimens_arguments(access_time, modification_time, fstflags, ts);
  545. int ret = futimens(handle, ts);
  546. if (ret < 0)
  547. return convert_errno(errno);
  548. return __WASI_ESUCCESS;
  549. }
  550. __wasi_errno_t
  551. os_utimensat(os_file_handle handle, const char *path,
  552. __wasi_timestamp_t access_time,
  553. __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
  554. __wasi_lookupflags_t lookup_flags)
  555. {
  556. struct timespec ts[2];
  557. convert_utimens_arguments(access_time, modification_time, fstflags, ts);
  558. int ret = utimensat(handle, path, ts,
  559. (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
  560. ? 0
  561. : AT_SYMLINK_NOFOLLOW);
  562. if (ret < 0)
  563. return convert_errno(errno);
  564. return __WASI_ESUCCESS;
  565. }
  566. __wasi_errno_t
  567. os_readlinkat(os_file_handle handle, const char *path, char *buf,
  568. size_t bufsize, size_t *nread)
  569. {
  570. // Linux requires that the buffer size is positive. whereas POSIX does
  571. // not. Use a fake buffer to store the results if the size is zero.
  572. char fakebuf[1];
  573. ssize_t len = readlinkat(handle, path, bufsize == 0 ? fakebuf : buf,
  574. bufsize == 0 ? sizeof(fakebuf) : bufsize);
  575. if (len < 0)
  576. return convert_errno(errno);
  577. *nread = (size_t)len < bufsize ? (size_t)len : bufsize;
  578. return __WASI_ESUCCESS;
  579. }
  580. __wasi_errno_t
  581. os_linkat(os_file_handle from_handle, const char *from_path,
  582. os_file_handle to_handle, const char *to_path,
  583. __wasi_lookupflags_t lookup_flags)
  584. {
  585. int ret = linkat(
  586. from_handle, from_path, to_handle, to_path,
  587. (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) ? AT_SYMLINK_FOLLOW : 0);
  588. if (ret < 0)
  589. return convert_errno(errno);
  590. return __WASI_ESUCCESS;
  591. }
  592. __wasi_errno_t
  593. os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
  594. {
  595. int ret = symlinkat(old_path, handle, new_path);
  596. if (ret < 0)
  597. return convert_errno(errno);
  598. return __WASI_ESUCCESS;
  599. }
  600. __wasi_errno_t
  601. os_mkdirat(os_file_handle handle, const char *path)
  602. {
  603. int ret = mkdirat(handle, path, 0777);
  604. if (ret < 0)
  605. return convert_errno(errno);
  606. return __WASI_ESUCCESS;
  607. }
  608. __wasi_errno_t
  609. os_renameat(os_file_handle old_handle, const char *old_path,
  610. os_file_handle new_handle, const char *new_path)
  611. {
  612. int ret = renameat(old_handle, old_path, new_handle, new_path);
  613. if (ret < 0)
  614. return convert_errno(errno);
  615. return __WASI_ESUCCESS;
  616. }
  617. __wasi_errno_t
  618. os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
  619. {
  620. int ret = unlinkat(handle, path, is_dir ? AT_REMOVEDIR : 0);
  621. #ifndef __linux__
  622. if (ret < 0) {
  623. // Non-Linux implementations may return EPERM when attempting to remove
  624. // a directory without REMOVEDIR. While that's what POSIX specifies,
  625. // it's less useful. Adjust this to EISDIR. It doesn't matter that this
  626. // is not atomic with the unlinkat, because if the file is removed and a
  627. // directory is created before fstatat sees it, we're racing with that
  628. // change anyway and unlinkat could have legitimately seen the directory
  629. // if the race had turned out differently.
  630. if (errno == EPERM) {
  631. struct stat statbuf;
  632. if (fstatat(handle, path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0
  633. && S_ISDIR(statbuf.st_mode)) {
  634. errno = EISDIR;
  635. }
  636. }
  637. // POSIX permits either EEXIST or ENOTEMPTY when the directory is not
  638. // empty. Map it to ENOTEMPTY.
  639. else if (errno == EEXIST) {
  640. errno = ENOTEMPTY;
  641. }
  642. return convert_errno(errno);
  643. }
  644. #endif
  645. if (ret < 0)
  646. return convert_errno(errno);
  647. return __WASI_ESUCCESS;
  648. }
  649. __wasi_errno_t
  650. os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
  651. __wasi_whence_t whence, __wasi_filesize_t *new_offset)
  652. {
  653. int nwhence;
  654. switch (whence) {
  655. case __WASI_WHENCE_CUR:
  656. nwhence = SEEK_CUR;
  657. break;
  658. case __WASI_WHENCE_END:
  659. nwhence = SEEK_END;
  660. break;
  661. case __WASI_WHENCE_SET:
  662. nwhence = SEEK_SET;
  663. break;
  664. default:
  665. return __WASI_EINVAL;
  666. }
  667. off_t ret = lseek(handle, offset, nwhence);
  668. if (ret < 0)
  669. return convert_errno(errno);
  670. *new_offset = (__wasi_filesize_t)ret;
  671. return __WASI_ESUCCESS;
  672. }
  673. __wasi_errno_t
  674. os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
  675. __wasi_filesize_t length, __wasi_advice_t advice)
  676. {
  677. #ifdef POSIX_FADV_NORMAL
  678. int nadvice;
  679. switch (advice) {
  680. case __WASI_ADVICE_DONTNEED:
  681. nadvice = POSIX_FADV_DONTNEED;
  682. break;
  683. case __WASI_ADVICE_NOREUSE:
  684. nadvice = POSIX_FADV_NOREUSE;
  685. break;
  686. case __WASI_ADVICE_NORMAL:
  687. nadvice = POSIX_FADV_NORMAL;
  688. break;
  689. case __WASI_ADVICE_RANDOM:
  690. nadvice = POSIX_FADV_RANDOM;
  691. break;
  692. case __WASI_ADVICE_SEQUENTIAL:
  693. nadvice = POSIX_FADV_SEQUENTIAL;
  694. break;
  695. case __WASI_ADVICE_WILLNEED:
  696. nadvice = POSIX_FADV_WILLNEED;
  697. break;
  698. default:
  699. return __WASI_EINVAL;
  700. }
  701. int ret = posix_fadvise(handle, (off_t)offset, (off_t)length, nadvice);
  702. if (ret != 0)
  703. return convert_errno(ret);
  704. return __WASI_ESUCCESS;
  705. #else
  706. // Advisory information can be safely ignored if not supported
  707. switch (advice) {
  708. case __WASI_ADVICE_DONTNEED:
  709. case __WASI_ADVICE_NOREUSE:
  710. case __WASI_ADVICE_NORMAL:
  711. case __WASI_ADVICE_RANDOM:
  712. case __WASI_ADVICE_SEQUENTIAL:
  713. case __WASI_ADVICE_WILLNEED:
  714. return __WASI_ESUCCESS;
  715. default:
  716. return __WASI_EINVAL;
  717. }
  718. #endif
  719. }
  720. __wasi_errno_t
  721. os_isatty(os_file_handle handle)
  722. {
  723. #if CONFIG_HAS_ISATTY
  724. int ret = isatty(handle);
  725. if (ret == 1)
  726. return __WASI_ESUCCESS;
  727. return __WASI_ENOTTY;
  728. #else
  729. return __WASI_ENOTSUP;
  730. #endif
  731. }
  732. bool
  733. os_is_stdin_handle(os_file_handle fd)
  734. {
  735. return fd == STDIN_FILENO;
  736. }
  737. bool
  738. os_is_stdout_handle(os_file_handle fd)
  739. {
  740. return fd == STDOUT_FILENO;
  741. }
  742. bool
  743. os_is_stderr_handle(os_file_handle fd)
  744. {
  745. return fd == STDERR_FILENO;
  746. }
  747. os_file_handle
  748. os_convert_stdin_handle(os_raw_file_handle raw_stdin)
  749. {
  750. return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO;
  751. }
  752. os_file_handle
  753. os_convert_stdout_handle(os_raw_file_handle raw_stdout)
  754. {
  755. return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO;
  756. }
  757. os_file_handle
  758. os_convert_stderr_handle(os_raw_file_handle raw_stderr)
  759. {
  760. return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO;
  761. }
  762. __wasi_errno_t
  763. os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
  764. {
  765. *dir_stream = fdopendir(handle);
  766. if (*dir_stream == NULL)
  767. return convert_errno(errno);
  768. return __WASI_ESUCCESS;
  769. }
  770. __wasi_errno_t
  771. os_rewinddir(os_dir_stream dir_stream)
  772. {
  773. rewinddir(dir_stream);
  774. return __WASI_ESUCCESS;
  775. }
  776. __wasi_errno_t
  777. os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position)
  778. {
  779. seekdir(dir_stream, (long)position);
  780. return __WASI_ESUCCESS;
  781. }
  782. __wasi_errno_t
  783. os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
  784. const char **d_name)
  785. {
  786. errno = 0;
  787. struct dirent *dent = readdir(dir_stream);
  788. if (dent == NULL) {
  789. *d_name = NULL;
  790. if (errno != 0) {
  791. return convert_errno(errno);
  792. }
  793. else {
  794. return 0;
  795. }
  796. }
  797. long offset = (__wasi_dircookie_t)telldir(dir_stream);
  798. size_t namlen = strlen(dent->d_name);
  799. *d_name = dent->d_name;
  800. entry->d_next = offset;
  801. entry->d_namlen = (__wasi_dirnamlen_t)namlen;
  802. #if CONFIG_HAS_D_INO
  803. entry->d_ino = dent->d_ino;
  804. #else
  805. entry->d_ino = 0;
  806. #endif
  807. switch (dent->d_type) {
  808. case DT_BLK:
  809. entry->d_type = __WASI_FILETYPE_BLOCK_DEVICE;
  810. break;
  811. case DT_CHR:
  812. entry->d_type = __WASI_FILETYPE_CHARACTER_DEVICE;
  813. break;
  814. case DT_DIR:
  815. entry->d_type = __WASI_FILETYPE_DIRECTORY;
  816. break;
  817. case DT_FIFO:
  818. entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
  819. break;
  820. case DT_LNK:
  821. entry->d_type = __WASI_FILETYPE_SYMBOLIC_LINK;
  822. break;
  823. case DT_REG:
  824. entry->d_type = __WASI_FILETYPE_REGULAR_FILE;
  825. break;
  826. #ifdef DT_SOCK
  827. case DT_SOCK:
  828. // Technically not correct, but good enough.
  829. entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
  830. break;
  831. #endif
  832. default:
  833. entry->d_type = __WASI_FILETYPE_UNKNOWN;
  834. break;
  835. }
  836. return __WASI_ESUCCESS;
  837. }
  838. __wasi_errno_t
  839. os_closedir(os_dir_stream dir_stream)
  840. {
  841. int ret = closedir(dir_stream);
  842. if (ret < 0)
  843. return convert_errno(errno);
  844. return __WASI_ESUCCESS;
  845. }
  846. os_dir_stream
  847. os_get_invalid_dir_stream()
  848. {
  849. return NULL;
  850. }
  851. bool
  852. os_is_dir_stream_valid(os_dir_stream *dir_stream)
  853. {
  854. assert(dir_stream != NULL);
  855. return *dir_stream != NULL;
  856. }
  857. bool
  858. os_is_handle_valid(os_file_handle *handle)
  859. {
  860. assert(handle != NULL);
  861. return *handle > -1;
  862. }
  863. char *
  864. os_realpath(const char *path, char *resolved_path)
  865. {
  866. return realpath(path, resolved_path);
  867. }
  868. os_raw_file_handle
  869. os_invalid_raw_handle(void)
  870. {
  871. return -1;
  872. }