]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c
12d62b724cc7855668f62784a431d52312c37551
[wasi-libc.git] / libc-bottom-half / cloudlibc / src / libc / fcntl / openat.c
1 // Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
2 //
3 // SPDX-License-Identifier: BSD-2-Clause
4
5 #include <common/errno.h>
6
7 #include <assert.h>
8 #include <wasi/api.h>
9 #include <wasi/libc.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <string.h>
13
14 #ifdef __wasilibc_unmodified_upstream // fstat
15 static_assert(O_APPEND == __WASI_FDFLAG_APPEND, "Value mismatch");
16 static_assert(O_DSYNC == __WASI_FDFLAG_DSYNC, "Value mismatch");
17 static_assert(O_NONBLOCK == __WASI_FDFLAG_NONBLOCK, "Value mismatch");
18 static_assert(O_RSYNC == __WASI_FDFLAG_RSYNC, "Value mismatch");
19 static_assert(O_SYNC == __WASI_FDFLAG_SYNC, "Value mismatch");
20 #else
21 static_assert(O_APPEND == __WASI_FDFLAGS_APPEND, "Value mismatch");
22 static_assert(O_DSYNC == __WASI_FDFLAGS_DSYNC, "Value mismatch");
23 static_assert(O_NONBLOCK == __WASI_FDFLAGS_NONBLOCK, "Value mismatch");
24 static_assert(O_RSYNC == __WASI_FDFLAGS_RSYNC, "Value mismatch");
25 static_assert(O_SYNC == __WASI_FDFLAGS_SYNC, "Value mismatch");
26 #endif
27
28 #ifdef __wasilibc_unmodified_upstream // fstat
29 static_assert(O_CREAT >> 12 == __WASI_O_CREAT, "Value mismatch");
30 static_assert(O_DIRECTORY >> 12 == __WASI_O_DIRECTORY, "Value mismatch");
31 static_assert(O_EXCL >> 12 == __WASI_O_EXCL, "Value mismatch");
32 static_assert(O_TRUNC >> 12 == __WASI_O_TRUNC, "Value mismatch");
33 #else
34 static_assert(O_CREAT >> 12 == __WASI_OFLAGS_CREAT, "Value mismatch");
35 static_assert(O_DIRECTORY >> 12 == __WASI_OFLAGS_DIRECTORY, "Value mismatch");
36 static_assert(O_EXCL >> 12 == __WASI_OFLAGS_EXCL, "Value mismatch");
37 static_assert(O_TRUNC >> 12 == __WASI_OFLAGS_TRUNC, "Value mismatch");
38 #endif
39
40 int openat(int fd, const char *path, int oflag, ...) {
41 #ifdef __wasilibc_unmodified_upstream // fstat
42 #else
43 return __wasilibc_openat_nomode(fd, path, oflag);
44 }
45
46 int __wasilibc_openat_nomode(int fd, const char *path, int oflag) {
47 #endif
48 // Compute rights corresponding with the access modes provided.
49 // Attempt to obtain all rights, except the ones that contradict the
50 // access mode provided to openat().
51 #ifdef __wasilibc_unmodified_upstream // Let the WASI implementation check this instead.
52 __wasi_rights_t min = 0;
53 #endif
54 __wasi_rights_t max =
55 #ifdef __wasilibc_unmodified_upstream // fstat
56 ~(__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_READ |
57 __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FILE_ALLOCATE |
58 __WASI_RIGHT_FILE_READDIR | __WASI_RIGHT_FILE_STAT_FPUT_SIZE |
59 #else
60 ~(__WASI_RIGHTS_FD_DATASYNC | __WASI_RIGHTS_FD_READ |
61 __WASI_RIGHTS_FD_WRITE | __WASI_RIGHTS_FD_ALLOCATE |
62 __WASI_RIGHTS_FD_READDIR | __WASI_RIGHTS_FD_FILESTAT_SET_SIZE |
63 #endif
64 #ifdef __wasilibc_unmodified_upstream // RIGHT_MEM_MAP_EXEC
65 __WASI_RIGHT_MEM_MAP_EXEC);
66 #else
67 0);
68 #endif
69 switch (oflag & O_ACCMODE) {
70 case O_RDONLY:
71 case O_RDWR:
72 case O_WRONLY:
73 if ((oflag & O_RDONLY) != 0) {
74 #ifdef __wasilibc_unmodified_upstream // Let the WASI implementation check this instead.
75 min |= (oflag & O_DIRECTORY) == 0 ? __WASI_RIGHT_FD_READ
76 : __WASI_RIGHT_FILE_READDIR;
77 #endif
78 #ifdef __wasilibc_unmodified_upstream // RIGHT_MEM_MAP_EXEC
79 max |= __WASI_RIGHT_FD_READ | __WASI_RIGHT_FILE_READDIR |
80 __WASI_RIGHT_MEM_MAP_EXEC;
81 #else
82 max |= __WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_READDIR;
83 #endif
84 }
85 if ((oflag & O_WRONLY) != 0) {
86 #ifdef __wasilibc_unmodified_upstream // Let the WASI implementation check this instead.
87 min |= __WASI_RIGHT_FD_WRITE;
88 if ((oflag & O_APPEND) == 0)
89 min |= __WASI_RIGHT_FD_SEEK;
90 #endif
91 #ifdef __wasilibc_unmodified_upstream // fstat
92 max |= __WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_WRITE |
93 __WASI_RIGHT_FILE_ALLOCATE |
94 __WASI_RIGHT_FILE_STAT_FPUT_SIZE;
95 #else
96 max |= __WASI_RIGHTS_FD_DATASYNC | __WASI_RIGHTS_FD_WRITE |
97 __WASI_RIGHTS_FD_ALLOCATE |
98 __WASI_RIGHTS_FD_FILESTAT_SET_SIZE;
99 #endif
100 }
101 break;
102 case O_EXEC:
103 #ifdef __wasilibc_unmodified_upstream // RIGHT_PROC_EXEC
104 min |= __WASI_RIGHT_PROC_EXEC;
105 #endif
106 break;
107 case O_SEARCH:
108 break;
109 default:
110 errno = EINVAL;
111 return -1;
112 }
113 #ifdef __wasilibc_unmodified_upstream // Let the WASI implementation check this instead.
114 assert((min & max) == min &&
115 "Minimal rights should be a subset of the maximum");
116 #endif
117
118 // Ensure that we can actually obtain the minimal rights needed.
119 __wasi_fdstat_t fsb_cur;
120 #ifdef __wasilibc_unmodified_upstream
121 __wasi_errno_t error = __wasi_fd_stat_get(fd, &fsb_cur);
122 #else
123 __wasi_errno_t error = __wasi_fd_fdstat_get(fd, &fsb_cur);
124 #endif
125 if (error != 0) {
126 errno = error;
127 return -1;
128 }
129 #ifdef __wasilibc_unmodified_upstream // Let the WASI implementation check this instead.
130 if (fsb_cur.fs_filetype != __WASI_FILETYPE_DIRECTORY) {
131 errno = ENOTDIR;
132 return -1;
133 }
134 if ((min & fsb_cur.fs_rights_inheriting) != min) {
135 errno = ENOTCAPABLE;
136 return -1;
137 }
138 #endif
139
140 // Path lookup properties.
141 #ifdef __wasilibc_unmodified_upstream // split out __wasi_lookup_t
142 __wasi_lookup_t lookup = {.fd = fd, .flags = 0};
143 #else
144 __wasi_lookupflags_t lookup_flags = 0;
145 #endif
146 if ((oflag & O_NOFOLLOW) == 0)
147 #ifdef __wasilibc_unmodified_upstream // split out __wasi_lookup_t
148 lookup.flags |= __WASI_LOOKUP_SYMLINK_FOLLOW;
149 #else
150 lookup_flags |= __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW;
151 #endif
152
153 // Open file with appropriate rights.
154 #ifdef __wasilibc_unmodified_upstream // split out __wasi_lookup_t and __wasi_fdstat_t
155 __wasi_fdstat_t fsb_new = {
156 .fs_flags = oflag & 0xfff,
157 .fs_rights_base = max & fsb_cur.fs_rights_inheriting,
158 .fs_rights_inheriting = fsb_cur.fs_rights_inheriting,
159 };
160 __wasi_fd_t newfd;
161 error = __wasi_file_open(lookup, path, strlen(path),
162 (oflag >> 12) & 0xfff, &fsb_new, &newfd);
163 #else
164 __wasi_fdflags_t fs_flags = oflag & 0xfff;
165 __wasi_rights_t fs_rights_base = max & fsb_cur.fs_rights_inheriting;
166 __wasi_rights_t fs_rights_inheriting = fsb_cur.fs_rights_inheriting;
167 __wasi_fd_t newfd;
168 error = __wasi_path_open(fd, lookup_flags, path, strlen(path),
169 (oflag >> 12) & 0xfff,
170 fs_rights_base, fs_rights_inheriting, fs_flags,
171 &newfd);
172 #endif
173 if (error != 0) {
174 #ifdef __wasilibc_unmodified_upstream // split out __wasi_lookup_t
175 errno = errno_fixup_directory(lookup.fd, error);
176 #else
177 errno = errno_fixup_directory(fd, error);
178 #endif
179 return -1;
180 }
181 return newfd;
182 }