]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/cloudlibc/src/libc/sys/stat/stat_impl.h
Fix utimensat to avoid passing uninitialized values into WASI calls.
[wasi-libc.git] / libc-bottom-half / cloudlibc / src / libc / sys / stat / stat_impl.h
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
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
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 *st_atim = (__wasi_timestamp_t) { 0 };
79 *st_mtim = (__wasi_timestamp_t) { 0 };
80 } else {
81 // Set individual timestamps.
82 *flags = 0;
83 switch (times[0].tv_nsec) {
84 case UTIME_NOW:
85 *flags |= __WASI_FSTFLAGS_ATIM_NOW;
86 *st_atim = (__wasi_timestamp_t) { 0 };
87 break;
88 case UTIME_OMIT:
89 *st_atim = (__wasi_timestamp_t) { 0 };
90 break;
91 default:
92 *flags |= __WASI_FSTFLAGS_ATIM;
93 if (!timespec_to_timestamp_exact(&times[0], st_atim))
94 return false;
95 break;
96 }
97
98 switch (times[1].tv_nsec) {
99 case UTIME_NOW:
100 *flags |= __WASI_FSTFLAGS_MTIM_NOW;
101 *st_mtim = (__wasi_timestamp_t) { 0 };
102 break;
103 case UTIME_OMIT:
104 *st_mtim = (__wasi_timestamp_t) { 0 };
105 break;
106 default:
107 *flags |= __WASI_FSTFLAGS_MTIM;
108 if (!timespec_to_timestamp_exact(&times[1], st_mtim))
109 return false;
110 break;
111 }
112 }
113 return true;
114 }
115
116 #endif