]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/libpreopen/lib/libpreopen.c
Remove more unsupported headers. (#123)
[wasi-libc.git] / libc-bottom-half / libpreopen / lib / libpreopen.c
1 /*-
2 * Copyright (c) 2016 Stanley Uche Godfrey
3 * Copyright (c) 2016, 2018 Jonathan Anderson
4 * All rights reserved.
5 *
6 * This software was developed at Memorial University under the
7 * NSERC Discovery program (RGPIN-2015-06048).
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /**
33 * @file libpreopen.c
34 * Implementation of high-level libpreopen functions.
35 *
36 * The functions defined in this source file are the highest-level API calls
37 * that client code will mostly use (plus po_map_create and po_map_release).
38 * po_isprefix is also defined here because it doesn't fit anywhere else.
39 */
40
41 #include <assert.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <string.h>
45 #ifdef __wasilibc_unmodified_upstream
46 #else
47 #include <fcntl.h>
48 #endif
49
50 #include "internal.h"
51
52
53 #ifdef __wasilibc_unmodified_upstream
54 #else
55 static
56 #endif
57 struct po_map*
58 po_add(struct po_map *map, const char *path, int fd)
59 {
60 struct po_map_entry *entry;
61
62 po_map_assertvalid(map);
63
64 if (path == NULL || fd < 0) {
65 return (NULL);
66 }
67
68 if (map->length == map->capacity) {
69 map = po_map_enlarge(map);
70 if (map == NULL) {
71 return (NULL);
72 }
73 }
74
75 entry = map->entries + map->length;
76 map->length++;
77
78 entry->name = strdup(path);
79 entry->fd = fd;
80
81 #ifdef WITH_CAPSICUM
82 #ifdef __wasilibc_unmodified_upstream
83 if (cap_rights_get(fd, &entry->rights) != 0) {
84 return (NULL);
85 }
86 #else
87 __wasi_fdstat_t statbuf;
88 int r = __wasi_fd_fdstat_get(fd, &statbuf);
89 if (r != 0) {
90 errno = r;
91 return NULL; // TODO: Add an infallible way to get the rights?
92 }
93
94 entry->rights_base = statbuf.fs_rights_base;
95 entry->rights_inheriting = statbuf.fs_rights_inheriting;
96 #endif
97 #endif
98
99
100 po_map_assertvalid(map);
101
102 return (map);
103 }
104
105 #ifdef __wasilibc_unmodified_upstream
106 struct po_relpath
107 po_find(struct po_map* map, const char *path, cap_rights_t *rights)
108 #else
109 static struct po_relpath
110 po_find(struct po_map* map, const char *path,
111 __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting)
112 #endif
113 {
114 const char *relpath ;
115 struct po_relpath match = { .relative_path = NULL, .dirfd = -1 };
116 size_t bestlen = 0;
117 int best = -1;
118
119 po_map_assertvalid(map);
120
121 if (path == NULL) {
122 return (match);
123 }
124
125 for(size_t i = 0; i < map->length; i++) {
126 const struct po_map_entry *entry = map->entries + i;
127 const char *name = entry->name;
128 #ifdef __wasilibc_unmodified_upstream
129 size_t len = strnlen(name, MAXPATHLEN);
130 #else
131 size_t len = strlen(name);
132 bool any_matches = false;
133
134 if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) {
135 // We're matching a relative path that doesn't start with "./" and isn't ".".
136 if (len >= 2 && name[0] == '.' && name[1] == '/') {
137 // The entry starts with "./", so skip that prefix.
138 name += 2;
139 len -= 2;
140 } else if (len == 1 && name[0] == '.') {
141 // The entry is ".", so match it as an empty string.
142 name += 1;
143 len -= 1;
144 }
145 }
146 #endif
147
148 #ifdef __wasilibc_unmodified_upstream
149 if ((len <= bestlen) || !po_isprefix(name, len, path)) {
150 #else
151 if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) {
152 #endif
153 continue;
154 }
155
156 #ifdef WITH_CAPSICUM
157 #ifdef __wasilibc_unmodified_upstream
158 if (rights && !cap_rights_contains(&entry->rights, rights)) {
159 #else
160 if ((rights_base & ~entry->rights_base) != 0 ||
161 (rights_inheriting & ~entry->rights_inheriting) != 0) {
162 #endif
163 continue;
164 }
165 #endif
166
167 best = entry->fd;
168 bestlen = len;
169 #ifdef __wasilibc_unmodified_upstream
170 #else
171 any_matches = true;
172 #endif
173 }
174
175 relpath = path + bestlen;
176
177 while (*relpath == '/') {
178 relpath++;
179 }
180
181 if (*relpath == '\0') {
182 relpath = ".";
183 }
184
185 match.relative_path = relpath;
186 match.dirfd = best;
187
188 return match;
189 }
190
191 #ifdef __wasilibc_unmodified_upstream
192 #else
193 static
194 #endif
195 bool
196 po_isprefix(const char *dir, size_t dirlen, const char *path)
197 {
198 size_t i;
199 assert(dir != NULL);
200 assert(path != NULL);
201 #ifdef __wasilibc_unmodified_upstream
202 #else
203 // Allow an empty string as a prefix of any relative path.
204 if (path[0] != '/' && dirlen == 0)
205 return true;
206 #endif
207 for (i = 0; i < dirlen; i++)
208 {
209 if (path[i] != dir[i])
210 return false;
211 }
212 #ifdef __wasilibc_unmodified_upstream
213 #else
214 // Ignore trailing slashes in directory names.
215 while (i > 0 && dir[i - 1] == '/') {
216 --i;
217 }
218 #endif
219 return path[i] == '/' || path[i] == '\0';
220 }
221
222 #ifdef __wasilibc_unmodified_upstream
223 int
224 po_preopen(struct po_map *map, const char *path, int flags, ...)
225 {
226 va_list args;
227 int fd, mode;
228
229 va_start(args, flags);
230 mode = va_arg(args, int);
231
232 po_map_assertvalid(map);
233
234 if (path == NULL) {
235 return (-1);
236 }
237
238 fd = openat(AT_FDCWD, path, flags, mode);
239 if (fd == -1) {
240 return (-1);
241 }
242
243 if (po_add(map, path, fd) == NULL) {
244 return (-1);
245 }
246
247 po_map_assertvalid(map);
248
249 return (fd);
250 }
251 #endif
252
253 #ifdef __wasilibc_unmodified_upstream
254 bool
255 po_print_entry(const char *name, int fd, cap_rights_t rights)
256 {
257 printf(" - name: '%s', fd: %d, rights: <rights>\n",
258 name, fd);
259 return (true);
260 }
261 #endif