1 // Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
2 //
3 // SPDX-License-Identifier: BSD-2-Clause
4 
5 #ifndef SYS_STAT_STAT_IMPL_H
6 #define SYS_STAT_STAT_IMPL_H
7 
8 #include <common/time.h>
9 
10 #include <sys/stat.h>
11 
12 #include <assert.h>
13 #include <wasi/api.h>
14 #include <stdbool.h>
15 
16 static_assert(S_ISBLK(S_IFBLK), "Value mismatch");
17 static_assert(S_ISCHR(S_IFCHR), "Value mismatch");
18 static_assert(S_ISDIR(S_IFDIR), "Value mismatch");
19 static_assert(S_ISFIFO(S_IFIFO), "Value mismatch");
20 static_assert(S_ISLNK(S_IFLNK), "Value mismatch");
21 static_assert(S_ISREG(S_IFREG), "Value mismatch");
22 static_assert(S_ISSOCK(S_IFSOCK), "Value mismatch");
23 
to_public_stat(const __wasi_filestat_t * in,struct stat * out)24 static inline void to_public_stat(const __wasi_filestat_t *in,
25                                   struct stat *out) {
26   // Ensure that we don't truncate any values.
27   static_assert(sizeof(in->dev) == sizeof(out->st_dev), "Size mismatch");
28   static_assert(sizeof(in->ino) == sizeof(out->st_ino), "Size mismatch");
29   /*
30    * The non-standard __st_filetype field appears to only be used for shared
31    * memory, which we don't currently support.
32    */
33   /* nlink_t is 64-bit on wasm32, following the x32 ABI. */
34   static_assert(sizeof(in->nlink) <= sizeof(out->st_nlink), "Size shortfall");
35   static_assert(sizeof(in->size) == sizeof(out->st_size), "Size mismatch");
36 
37   *out = (struct stat){
38       .st_dev = in->dev,
39       .st_ino = in->ino,
40       .st_nlink = in->nlink,
41       .st_size = in->size,
42       .st_atim = timestamp_to_timespec(in->atim),
43       .st_mtim = timestamp_to_timespec(in->mtim),
44       .st_ctim = timestamp_to_timespec(in->ctim),
45   };
46 
47   // Convert file type to legacy types encoded in st_mode.
48   switch (in->filetype) {
49     case __WASI_FILETYPE_BLOCK_DEVICE:
50       out->st_mode |= S_IFBLK;
51       break;
52     case __WASI_FILETYPE_CHARACTER_DEVICE:
53       out->st_mode |= S_IFCHR;
54       break;
55     case __WASI_FILETYPE_DIRECTORY:
56       out->st_mode |= S_IFDIR;
57       break;
58     case __WASI_FILETYPE_REGULAR_FILE:
59       out->st_mode |= S_IFREG;
60       break;
61     case __WASI_FILETYPE_SOCKET_DGRAM:
62     case __WASI_FILETYPE_SOCKET_STREAM:
63       out->st_mode |= S_IFSOCK;
64       break;
65     case __WASI_FILETYPE_SYMBOLIC_LINK:
66       out->st_mode |= S_IFLNK;
67       break;
68   }
69 }
70 
utimens_get_timestamps(const struct timespec * times,__wasi_timestamp_t * st_atim,__wasi_timestamp_t * st_mtim,__wasi_fstflags_t * flags)71 static inline bool utimens_get_timestamps(const struct timespec *times,
72                                           __wasi_timestamp_t *st_atim,
73                                           __wasi_timestamp_t *st_mtim,
74                                           __wasi_fstflags_t *flags) {
75   if (times == NULL) {
76     // Update both timestamps.
77     *flags = __WASI_FSTFLAGS_ATIM_NOW | __WASI_FSTFLAGS_MTIM_NOW;
78   } else {
79     // Set individual timestamps.
80     *flags = 0;
81     switch (times[0].tv_nsec) {
82       case UTIME_NOW:
83         *flags |= __WASI_FSTFLAGS_ATIM_NOW;
84         break;
85       case UTIME_OMIT:
86         break;
87       default:
88         *flags |= __WASI_FSTFLAGS_ATIM;
89         if (!timespec_to_timestamp_exact(&times[0], st_atim))
90           return false;
91         break;
92     }
93 
94     switch (times[1].tv_nsec) {
95       case UTIME_NOW:
96         *flags |= __WASI_FSTFLAGS_MTIM_NOW;
97         break;
98       case UTIME_OMIT:
99         break;
100       default:
101         *flags |= __WASI_FSTFLAGS_MTIM;
102         if (!timespec_to_timestamp_exact(&times[1], st_mtim))
103           return false;
104         break;
105     }
106   }
107   return true;
108 }
109 
110 #endif
111