2 * Copyright (c) 2016 Stanley Uche Godfrey
3 * Copyright (c) 2016, 2018 Jonathan Anderson
6 * This software was developed at Memorial University under the
7 * NSERC Discovery program (RGPIN-2015-06048).
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
34 * Implementation of high-level libpreopen functions.
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.
45 #ifdef __wasilibc_unmodified_upstream
53 #ifdef __wasilibc_unmodified_upstream
58 po_add(struct po_map
*map
, const char *path
, int fd
)
60 struct po_map_entry
*entry
;
62 po_map_assertvalid(map
);
64 if (path
== NULL
|| fd
< 0) {
68 if (map
->length
== map
->capacity
) {
69 map
= po_map_enlarge(map
);
75 entry
= map
->entries
+ map
->length
;
78 entry
->name
= strdup(path
);
82 #ifdef __wasilibc_unmodified_upstream
83 if (cap_rights_get(fd
, &entry
->rights
) != 0) {
87 __wasi_fdstat_t statbuf
;
88 int r
= __wasi_fd_fdstat_get(fd
, &statbuf
);
91 return NULL
; // TODO: Add an infallible way to get the rights?
94 entry
->rights_base
= statbuf
.fs_rights_base
;
95 entry
->rights_inheriting
= statbuf
.fs_rights_inheriting
;
100 po_map_assertvalid(map
);
105 #ifdef __wasilibc_unmodified_upstream
107 po_find(struct po_map
* map
, const char *path
, cap_rights_t
*rights
)
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
)
114 const char *relpath
;
115 struct po_relpath match
= { .relative_path
= NULL
, .dirfd
= -1 };
119 po_map_assertvalid(map
);
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
);
131 size_t len
= strlen(name
);
132 bool any_matches
= false;
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.
140 } else if (len
== 1 && name
[0] == '.') {
141 // The entry is ".", so match it as an empty string.
148 #ifdef __wasilibc_unmodified_upstream
149 if ((len
<= bestlen
) || !po_isprefix(name
, len
, path
)) {
151 if ((any_matches
&& len
<= bestlen
) || !po_isprefix(name
, len
, path
)) {
157 #ifdef __wasilibc_unmodified_upstream
158 if (rights
&& !cap_rights_contains(&entry
->rights
, rights
)) {
160 if ((rights_base
& ~entry
->rights_base
) != 0 ||
161 (rights_inheriting
& ~entry
->rights_inheriting
) != 0) {
169 #ifdef __wasilibc_unmodified_upstream
175 relpath
= path
+ bestlen
;
177 while (*relpath
== '/') {
181 if (*relpath
== '\0') {
185 match
.relative_path
= relpath
;
191 #ifdef __wasilibc_unmodified_upstream
196 po_isprefix(const char *dir
, size_t dirlen
, const char *path
)
200 assert(path
!= NULL
);
201 #ifdef __wasilibc_unmodified_upstream
203 // Allow an empty string as a prefix of any relative path.
204 if (path
[0] != '/' && dirlen
== 0)
207 for (i
= 0; i
< dirlen
; i
++)
209 if (path
[i
] != dir
[i
])
212 #ifdef __wasilibc_unmodified_upstream
214 // Ignore trailing slashes in directory names.
215 while (i
> 0 && dir
[i
- 1] == '/') {
219 return path
[i
] == '/' || path
[i
] == '\0';
222 #ifdef __wasilibc_unmodified_upstream
224 po_preopen(struct po_map
*map
, const char *path
, int flags
, ...)
229 va_start(args
, flags
);
230 mode
= va_arg(args
, int);
232 po_map_assertvalid(map
);
238 fd
= openat(AT_FDCWD
, path
, flags
, mode
);
243 if (po_add(map
, path
, fd
) == NULL
) {
247 po_map_assertvalid(map
);
253 #ifdef __wasilibc_unmodified_upstream
255 po_print_entry(const char *name
, int fd
, cap_rights_t rights
)
257 printf(" - name: '%s', fd: %d, rights: <rights>\n",