1 //! POSIX-like functions supporting absolute path arguments, implemented in
2 //! terms of `__wasilibc_find_relpath` and `*at`-style functions.
11 #include <wasi/libc.h>
12 #include <wasi/libc-find-relpath.h>
13 #include <wasi/libc-nocwd.h>
15 static int find_relpath2(
20 // See comments in `preopens.c` for what this trick is doing.
22 if (__wasilibc_find_relpath_alloc
)
23 return __wasilibc_find_relpath_alloc(path
, &abs
, relative
, relative_len
, 1);
24 return __wasilibc_find_relpath(path
, &abs
, relative
, *relative_len
);
27 // Helper to call `__wasilibc_find_relpath` and return an already-managed
28 // pointer for the `relative` path. This function is not reentrant since the
29 // `relative` pointer will point to static data that cannot be reused until
30 // `relative` is no longer used.
31 static int find_relpath(const char *path
, char **relative
) {
32 static __thread
char *relative_buf
= NULL
;
33 static __thread
size_t relative_buf_len
= 0;
34 int fd
= find_relpath2(path
, &relative_buf
, &relative_buf_len
);
35 // find_relpath2 can update relative_buf, so assign it after the call
36 *relative
= relative_buf
;
40 // same as `find_relpath`, but uses another set of static variables to cache
41 static int find_relpath_alt(const char *path
, char **relative
) {
42 static __thread
char *relative_buf
= NULL
;
43 static __thread
size_t relative_buf_len
= 0;
44 int fd
= find_relpath2(path
, &relative_buf
, &relative_buf_len
);
45 // find_relpath2 can update relative_buf, so assign it after the call
46 *relative
= relative_buf
;
50 int open(const char *path
, int oflag
, ...) {
51 // WASI libc's `openat` ignores the mode argument, so call a special
52 // entrypoint which avoids the varargs calling convention.
53 return __wasilibc_open_nomode(path
, oflag
);
56 // See the documentation in libc.h
57 int __wasilibc_open_nomode(const char *path
, int oflag
) {
59 int dirfd
= find_relpath(path
, &relative_path
);
61 // If we can't find a preopen for it, fail as if we can't find the path.
67 return __wasilibc_nocwd_openat_nomode(dirfd
, relative_path
, oflag
);
70 int access(const char *path
, int amode
) {
72 int dirfd
= find_relpath(path
, &relative_path
);
74 // If we can't find a preopen for it, fail as if we can't find the path.
80 return __wasilibc_nocwd_faccessat(dirfd
, relative_path
, amode
, 0);
84 const char *restrict path
,
89 int dirfd
= find_relpath(path
, &relative_path
);
91 // If we can't find a preopen for it, fail as if we can't find the path.
97 return __wasilibc_nocwd_readlinkat(dirfd
, relative_path
, buf
, bufsize
);
100 int stat(const char *restrict path
, struct stat
*restrict buf
) {
102 int dirfd
= find_relpath(path
, &relative_path
);
104 // If we can't find a preopen for it, fail as if we can't find the path.
110 return __wasilibc_nocwd_fstatat(dirfd
, relative_path
, buf
, 0);
113 int lstat(const char *restrict path
, struct stat
*restrict buf
) {
115 int dirfd
= find_relpath(path
, &relative_path
);
117 // If we can't find a preopen for it, fail as if we can't find the path.
123 return __wasilibc_nocwd_fstatat(dirfd
, relative_path
, buf
, AT_SYMLINK_NOFOLLOW
);
126 int utime(const char *path
, const struct utimbuf
*times
) {
128 int dirfd
= find_relpath(path
, &relative_path
);
130 // If we can't find a preopen for it, fail as if we can't find the path.
136 return __wasilibc_nocwd_utimensat(
137 dirfd
, relative_path
,
138 times
? ((struct timespec
[2]) {
139 { .tv_sec
= times
->actime
},
140 { .tv_sec
= times
->modtime
}
146 int utimes(const char *path
, const struct timeval times
[2]) {
148 int dirfd
= find_relpath(path
, &relative_path
);
150 // If we can't find a preopen for it, fail as if we can't find the path.
156 return __wasilibc_nocwd_utimensat(
157 dirfd
, relative_path
,
158 times
? ((struct timespec
[2]) {
159 { .tv_sec
= times
[0].tv_sec
,
160 .tv_nsec
= times
[0].tv_usec
* 1000 },
161 { .tv_sec
= times
[1].tv_sec
,
162 .tv_nsec
= times
[1].tv_usec
* 1000 },
168 int unlink(const char *path
) {
170 int dirfd
= find_relpath(path
, &relative_path
);
172 // If we can't find a preopen for it, fail as if we can't find the path.
178 // `unlinkat` imports `__wasi_path_remove_directory` even when
179 // `AT_REMOVEDIR` isn't passed. Instead, use a specialized function which
180 // just imports `__wasi_path_unlink_file`.
181 return __wasilibc_nocwd___wasilibc_unlinkat(dirfd
, relative_path
);
184 int rmdir(const char *path
) {
186 int dirfd
= find_relpath(path
, &relative_path
);
188 // If we can't find a preopen for it, fail as if we can't find the path.
194 return __wasilibc_nocwd___wasilibc_rmdirat(dirfd
, relative_path
);
197 int remove(const char *path
) {
199 int dirfd
= find_relpath(path
, &relative_path
);
201 // If we can't find a preopen for it, fail as if we can't find the path.
207 // First try to remove it as a file.
208 int r
= __wasilibc_nocwd___wasilibc_unlinkat(dirfd
, relative_path
);
209 if (r
!= 0 && (errno
== EISDIR
|| errno
== ENOENT
)) {
210 // That failed, but it might be a directory.
211 r
= __wasilibc_nocwd___wasilibc_rmdirat(dirfd
, relative_path
);
213 // If it isn't a directory, we lack capabilities to remove it as a file.
214 if (errno
== ENOTDIR
)
220 int mkdir(const char *path
, mode_t mode
) {
222 int dirfd
= find_relpath(path
, &relative_path
);
224 // If we can't find a preopen for it, fail as if we can't find the path.
230 return __wasilibc_nocwd_mkdirat_nomode(dirfd
, relative_path
);
233 DIR *opendir(const char *dirname
) {
235 int dirfd
= find_relpath(dirname
, &relative_path
);
237 // If we can't find a preopen for it, fail as if we can't find the path.
243 return __wasilibc_nocwd_opendirat(dirfd
, relative_path
);
247 const char *restrict dir
,
248 struct dirent
***restrict namelist
,
249 int (*filter
)(const struct dirent
*),
250 int (*compar
)(const struct dirent
**, const struct dirent
**)
253 int dirfd
= find_relpath(dir
, &relative_path
);
255 // If we can't find a preopen for it, fail as if we can't find the path.
261 return __wasilibc_nocwd_scandirat(dirfd
, relative_path
, namelist
, filter
, compar
);
264 int symlink(const char *target
, const char *linkpath
) {
266 int dirfd
= find_relpath(linkpath
, &relative_path
);
268 // If we can't find a preopen for it, fail as if we can't find the path.
274 return __wasilibc_nocwd_symlinkat(target
, dirfd
, relative_path
);
277 int link(const char *old
, const char *new) {
278 char *old_relative_path
;
279 int old_dirfd
= find_relpath_alt(old
, &old_relative_path
);
281 if (old_dirfd
!= -1) {
282 char *new_relative_path
;
283 int new_dirfd
= find_relpath(new, &new_relative_path
);
286 return __wasilibc_nocwd_linkat(old_dirfd
, old_relative_path
,
287 new_dirfd
, new_relative_path
, 0);
290 // We couldn't find a preopen for it; fail as if we can't find the path.
295 int rename(const char *old
, const char *new) {
296 char *old_relative_path
;
297 int old_dirfd
= find_relpath_alt(old
, &old_relative_path
);
299 if (old_dirfd
!= -1) {
300 char *new_relative_path
;
301 int new_dirfd
= find_relpath(new, &new_relative_path
);
304 return __wasilibc_nocwd_renameat(old_dirfd
, old_relative_path
,
305 new_dirfd
, new_relative_path
);
308 // We couldn't find a preopen for it; fail as if we can't find the path.
313 // Like `access`, but with `faccessat`'s flags argument.
315 __wasilibc_access(const char *path
, int mode
, int flags
)
318 int dirfd
= find_relpath(path
, &relative_path
);
320 // If we can't find a preopen for it, fail as if we can't find the path.
326 return __wasilibc_nocwd_faccessat(dirfd
, relative_path
,
330 // Like `utimensat`, but without the `at` part.
332 __wasilibc_utimens(const char *path
, const struct timespec times
[2], int flags
)
335 int dirfd
= find_relpath(path
, &relative_path
);
337 // If we can't find a preopen for it, fail as if we can't find the path.
343 return __wasilibc_nocwd_utimensat(dirfd
, relative_path
,
347 // Like `stat`, but with `fstatat`'s flags argument.
349 __wasilibc_stat(const char *__restrict path
, struct stat
*__restrict st
, int flags
)
352 int dirfd
= find_relpath(path
, &relative_path
);
354 // If we can't find a preopen for it, fail as if we can't find the path.
360 return __wasilibc_nocwd_fstatat(dirfd
, relative_path
, st
, flags
);
363 // Like `link`, but with `linkat`'s flags argument.
365 __wasilibc_link(const char *oldpath
, const char *newpath
, int flags
)
367 char *old_relative_path
;
368 char *new_relative_path
;
369 int old_dirfd
= find_relpath(oldpath
, &old_relative_path
);
370 int new_dirfd
= find_relpath(newpath
, &new_relative_path
);
372 // If we can't find a preopen for it, fail as if we can't find the path.
373 if (old_dirfd
== -1 || new_dirfd
== -1) {
378 return __wasilibc_nocwd_linkat(old_dirfd
, old_relative_path
,
379 new_dirfd
, new_relative_path
,
383 // Like `__wasilibc_link`, but oldpath is relative to olddirfd.
385 __wasilibc_link_oldat(int olddirfd
, const char *oldpath
, const char *newpath
, int flags
)
387 char *new_relative_path
;
388 int new_dirfd
= find_relpath(newpath
, &new_relative_path
);
390 // If we can't find a preopen for it, fail as if we can't find the path.
391 if (new_dirfd
== -1) {
396 return __wasilibc_nocwd_linkat(olddirfd
, oldpath
,
397 new_dirfd
, new_relative_path
,
401 // Like `__wasilibc_link`, but newpath is relative to newdirfd.
403 __wasilibc_link_newat(const char *oldpath
, int newdirfd
, const char *newpath
, int flags
)
405 char *old_relative_path
;
406 int old_dirfd
= find_relpath(oldpath
, &old_relative_path
);
408 // If we can't find a preopen for it, fail as if we can't find the path.
409 if (old_dirfd
== -1) {
414 return __wasilibc_nocwd_linkat(old_dirfd
, old_relative_path
,
419 // Like `rename`, but from is relative to fromdirfd.
421 __wasilibc_rename_oldat(int fromdirfd
, const char *from
, const char *to
)
423 char *to_relative_path
;
424 int to_dirfd
= find_relpath(to
, &to_relative_path
);
426 // If we can't find a preopen for it, fail as if we can't find the path.
427 if (to_dirfd
== -1) {
432 return __wasilibc_nocwd_renameat(fromdirfd
, from
, to_dirfd
, to_relative_path
);
435 // Like `rename`, but to is relative to todirfd.
437 __wasilibc_rename_newat(const char *from
, int todirfd
, const char *to
)
439 char *from_relative_path
;
440 int from_dirfd
= find_relpath(from
, &from_relative_path
);
442 // If we can't find a preopen for it, fail as if we can't find the path.
443 if (from_dirfd
== -1) {
448 return __wasilibc_nocwd_renameat(from_dirfd
, from_relative_path
, todirfd
, to
);