mirror of
https://git.proxmox.com/git/wasi-libc
synced 2025-07-09 18:14:07 +00:00
Revamp and simplify the libpreopen code. (#110)
wasi-libc's copy of libpreopen has evolved so many local changes that it's no longer worth keeping the upstream code structure and marking changes with __wasilibc_unmodified_upstream. This PR merges the source files into a single file, removes all __wasilibc_unmodified_upstream code, eliminates the ability to allocate multiple preopen lists, eliminates the need for __wasilibc_init_preopen, eliminates the non-standard eaccess, and makes several other cleanups. It also enables NDEBUG so that internal assertions are disabled in release builds.
This commit is contained in:
parent
eb7230cf94
commit
7fcc4f29df
10
Makefile
10
Makefile
@ -3,7 +3,7 @@
|
|||||||
WASM_CC ?= clang
|
WASM_CC ?= clang
|
||||||
WASM_NM ?= $(patsubst %clang,%llvm-nm,$(WASM_CC))
|
WASM_NM ?= $(patsubst %clang,%llvm-nm,$(WASM_CC))
|
||||||
WASM_AR ?= $(patsubst %clang,%llvm-ar,$(WASM_CC))
|
WASM_AR ?= $(patsubst %clang,%llvm-ar,$(WASM_CC))
|
||||||
WASM_CFLAGS ?= -O2
|
WASM_CFLAGS ?= -O2 -DNDEBUG
|
||||||
# The directory where we build the sysroot.
|
# The directory where we build the sysroot.
|
||||||
SYSROOT ?= $(CURDIR)/sysroot
|
SYSROOT ?= $(CURDIR)/sysroot
|
||||||
# A directory to install to for "make install".
|
# A directory to install to for "make install".
|
||||||
@ -45,12 +45,10 @@ LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include
|
|||||||
LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public
|
LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public
|
||||||
LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private
|
LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private
|
||||||
LIBC_BOTTOM_HALF_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen
|
LIBC_BOTTOM_HALF_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen
|
||||||
LIBC_BOTTOM_HALF_LIBPREOPEN_LIB = $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/lib
|
|
||||||
LIBC_BOTTOM_HALF_LIBPREOPEN_INC = $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/include
|
|
||||||
LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources
|
LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources
|
||||||
LIBC_BOTTOM_HALF_ALL_SOURCES = \
|
LIBC_BOTTOM_HALF_ALL_SOURCES = \
|
||||||
$(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \
|
$(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \
|
||||||
$(LIBC_BOTTOM_HALF_LIBPREOPEN_LIB)/po_libc_wrappers.c \
|
$(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/libpreopen.c \
|
||||||
$(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c)
|
$(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c)
|
||||||
LIBWASI_EMULATED_MMAN_SOURCES = \
|
LIBWASI_EMULATED_MMAN_SOURCES = \
|
||||||
$(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c)
|
$(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c)
|
||||||
@ -364,9 +362,7 @@ $(DLMALLOC_OBJS): override WASM_CFLAGS += \
|
|||||||
startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \
|
startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \
|
||||||
-I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \
|
-I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \
|
||||||
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \
|
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \
|
||||||
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) \
|
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)
|
||||||
-I$(LIBC_BOTTOM_HALF_LIBPREOPEN_LIB) \
|
|
||||||
-I$(LIBC_BOTTOM_HALF_LIBPREOPEN_INC)
|
|
||||||
|
|
||||||
$(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_CFLAGS += \
|
$(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_CFLAGS += \
|
||||||
-I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \
|
-I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \
|
||||||
|
@ -251,7 +251,6 @@ __uselocale
|
|||||||
__utc
|
__utc
|
||||||
__wasilibc_fd_renumber
|
__wasilibc_fd_renumber
|
||||||
__wasilibc_find_relpath
|
__wasilibc_find_relpath
|
||||||
__wasilibc_init_preopen
|
|
||||||
__wasilibc_populate_environ
|
__wasilibc_populate_environ
|
||||||
__wasilibc_register_preopened_fd
|
__wasilibc_register_preopened_fd
|
||||||
__wasilibc_rmdirat
|
__wasilibc_rmdirat
|
||||||
@ -428,7 +427,6 @@ drand48
|
|||||||
drem
|
drem
|
||||||
dremf
|
dremf
|
||||||
duplocale
|
duplocale
|
||||||
eaccess
|
|
||||||
ecvt
|
ecvt
|
||||||
encrypt
|
encrypt
|
||||||
environ
|
environ
|
||||||
|
@ -1143,6 +1143,7 @@
|
|||||||
#define NAN (0.0f/0.0f)
|
#define NAN (0.0f/0.0f)
|
||||||
#define NBBY 8
|
#define NBBY 8
|
||||||
#define NCARGS 131072
|
#define NCARGS 131072
|
||||||
|
#define NDEBUG 1
|
||||||
#define ND_NA_FLAG_OVERRIDE 0x00000020
|
#define ND_NA_FLAG_OVERRIDE 0x00000020
|
||||||
#define ND_NA_FLAG_ROUTER 0x00000080
|
#define ND_NA_FLAG_ROUTER 0x00000080
|
||||||
#define ND_NA_FLAG_SOLICITED 0x00000040
|
#define ND_NA_FLAG_SOLICITED 0x00000040
|
||||||
@ -3171,7 +3172,7 @@
|
|||||||
#define and_eq &=
|
#define and_eq &=
|
||||||
#define asin(x) __tg_real_complex(asin, (x))
|
#define asin(x) __tg_real_complex(asin, (x))
|
||||||
#define asinh(x) __tg_real_complex(asinh, (x))
|
#define asinh(x) __tg_real_complex(asinh, (x))
|
||||||
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__),0)))
|
#define assert(x) (void)0
|
||||||
#define atan(x) __tg_real_complex(atan, (x))
|
#define atan(x) __tg_real_complex(atan, (x))
|
||||||
#define atan2(x,y) __tg_real_2(atan2, (x), (y))
|
#define atan2(x,y) __tg_real_2(atan2, (x), (y))
|
||||||
#define atanh(x) __tg_real_complex(atanh, (x))
|
#define atanh(x) __tg_real_complex(atanh, (x))
|
||||||
|
@ -11,8 +11,6 @@ extern void __prepare_for_exit(void);
|
|||||||
void _Exit(int) __attribute__((noreturn));
|
void _Exit(int) __attribute__((noreturn));
|
||||||
|
|
||||||
static __wasi_errno_t populate_libpreopen(void) {
|
static __wasi_errno_t populate_libpreopen(void) {
|
||||||
__wasilibc_init_preopen();
|
|
||||||
|
|
||||||
// Skip stdin, stdout, and stderr, and count up until we reach an invalid
|
// Skip stdin, stdout, and stderr, and count up until we reach an invalid
|
||||||
// file descriptor.
|
// file descriptor.
|
||||||
for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
|
for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
|
||||||
|
@ -1,215 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file libpreopen.h
|
|
||||||
* @brief Public header for libpreopen
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2016, 2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBPO_H
|
|
||||||
#define LIBPO_H
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
#include <sys/capsicum.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
|
|
||||||
__BEGIN_DECLS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct po_map
|
|
||||||
* @brief A mapping from paths to pre-opened directories.
|
|
||||||
*
|
|
||||||
* This type is opaque to clients, but it is reference-counted and can be
|
|
||||||
* thought of as containing a set (with no particular ordering guarantees)
|
|
||||||
* of path->dirfd mappings.
|
|
||||||
*/
|
|
||||||
struct po_map;
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* A callback that can be used to inpect the contents of a @ref po_map.
|
|
||||||
*
|
|
||||||
* This callback can be invoked by iteration code to expose elements of a
|
|
||||||
* @ref po_map (in no particular order).
|
|
||||||
*
|
|
||||||
* @returns whether or not to continue iterating over the @ref po_map
|
|
||||||
*/
|
|
||||||
typedef bool (po_map_iter_cb)(const char *dirname, int dirfd, cap_rights_t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple @ref po_map_iter_cb that will print a @ref po_map's entries,
|
|
||||||
* one per line.
|
|
||||||
*/
|
|
||||||
po_map_iter_cb po_print_entry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A filesystem path, relative to a directory descriptor.
|
|
||||||
*/
|
|
||||||
struct po_relpath {
|
|
||||||
/** The directory the path is relative to */
|
|
||||||
int dirfd;
|
|
||||||
|
|
||||||
/** The path, relative to the directory represented by @ref dirfd */
|
|
||||||
const char *relative_path;
|
|
||||||
};
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
// This functionality is exposed in a libc header, so include that header
|
|
||||||
// and use its declarations.
|
|
||||||
#include <wasi/libc-find-relpath.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a @ref po_map of at least the specified capacity.
|
|
||||||
*
|
|
||||||
* The returned @ref po_map will have a reference count of 1.
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map* po_map_create(int capacity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release a reference to a @ref po_map.
|
|
||||||
*
|
|
||||||
* This may cause memory to be freed.
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
void po_map_release(struct po_map *);
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Iterate over a @ref po_map, invoking a callback for each element in the map.
|
|
||||||
*
|
|
||||||
* This function will cause @b callback to be invoked repeatedly, in no
|
|
||||||
* particular order, until the entire map has been iterated over or until the
|
|
||||||
* callback returns `false`.
|
|
||||||
*
|
|
||||||
* @return number of elements iterated over
|
|
||||||
*/
|
|
||||||
size_t po_map_foreach(const struct po_map*, po_map_iter_cb);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an already-opened directory to a @ref po_map.
|
|
||||||
*
|
|
||||||
* @param map the map to add the path->fd mapping to
|
|
||||||
* @param path the path that will map to this directory
|
|
||||||
* (which may or may not be the path used to open it)
|
|
||||||
* @param fd the directory descriptor (must be a directory!)
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map* po_add(struct po_map *map, const char *path, int fd);
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Pre-open a path and store it in a @ref po_map for later use.
|
|
||||||
*
|
|
||||||
* @param map the map to add the path->fd mapping to
|
|
||||||
* @param path the path to pre-open (which may be a directory if
|
|
||||||
* `O_DIRECTORY` is passed via @b flags)
|
|
||||||
* @param flags flags to pass to `open(2)` / `openat(2)`
|
|
||||||
* @param ... optional file mode, as accepted by `open(2)`
|
|
||||||
*
|
|
||||||
* @returns the file descriptor of the opened directory or -1 if
|
|
||||||
* @b path is not a directory or cannot be opened or if
|
|
||||||
* the @ref po_map cannot store the directory (e.g., resizing fails)
|
|
||||||
*/
|
|
||||||
int po_preopen(struct po_map *map, const char *path, int flags, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a directory whose path is a prefix of @b path and (on platforms that
|
|
||||||
* support Capsicum) that has the rights required by @b rights.
|
|
||||||
*
|
|
||||||
* @param map the map to look for a directory in
|
|
||||||
* @param path the path we want to find a pre-opened prefix for
|
|
||||||
* @param rights if non-NULL on a platform with Capsicum support,
|
|
||||||
* the rights any directory descriptor must have to
|
|
||||||
* qualify as a match
|
|
||||||
* @returns a @ref po_relpath containing the descriptor of the best-match
|
|
||||||
* directory in the map (or -1 if none was found) and the remaining
|
|
||||||
* path, relative to the file (or undefined if no match found)
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath po_find(struct po_map *map, const char *path,
|
|
||||||
cap_rights_t *rights);
|
|
||||||
#else
|
|
||||||
static struct po_relpath po_find(struct po_map *map, const char *path,
|
|
||||||
__wasi_rights_t rights_base, __wasi_rights_t rights_inheriting);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Retrieve a message from with the last libpreopen error.
|
|
||||||
*
|
|
||||||
* @returns NULL if there are no errors, null-terminated string otherwise
|
|
||||||
*/
|
|
||||||
const char* po_last_error(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pack a `struct po_map` into a shared memory segment.
|
|
||||||
*
|
|
||||||
* To inherit a `po_map` across the process execution boundary, it needs to be
|
|
||||||
* packed into an inheritable form such as a shared memory segment. This can
|
|
||||||
* then be unpacked in the child process for direct access.
|
|
||||||
*
|
|
||||||
* @param map the map to pack into shared memory
|
|
||||||
*
|
|
||||||
* @returns a file descriptor of a shared memory segment
|
|
||||||
* (or -1 on error)
|
|
||||||
*/
|
|
||||||
int po_pack(struct po_map *map);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack a `struct po_map` from a file.
|
|
||||||
*
|
|
||||||
* Using the representation generated by `po_pack`, unpack a `po_map`
|
|
||||||
* and make it available for normal usage.
|
|
||||||
*
|
|
||||||
* @param fd a file containing a packed `po_map` representation
|
|
||||||
*/
|
|
||||||
struct po_map* po_unpack(int fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__END_DECLS
|
|
||||||
|
|
||||||
#endif /* !LIBPO_H */
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file internal.h
|
|
||||||
* @brief Declarations of internal data structures and functions
|
|
||||||
*
|
|
||||||
* @cond internal
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* Copyright (c) 2016-2017 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2016-2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBPO_INTERNAL_H
|
|
||||||
#define LIBPO_INTERNAL_H
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#ifdef WITH_CAPSICUM
|
|
||||||
#include <sys/capsicum.h>
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
// We do Capsicum-style rights-checking, though we use the WASI API directly
|
|
||||||
// rather than the Capsicum API.
|
|
||||||
#define WITH_CAPSICUM
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "libpreopen.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An entry in a po_map.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
struct po_map_entry {
|
|
||||||
/**
|
|
||||||
* The name this file or directory is mapped to.
|
|
||||||
*
|
|
||||||
* This name should look like a path, but it does not necessarily need
|
|
||||||
* match to match the path it was originally obtained from.
|
|
||||||
*/
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
/** File descriptor (which may be a directory) */
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
#ifdef WITH_CAPSICUM
|
|
||||||
/** Capability rights associated with the file descriptor */
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
cap_rights_t rights;
|
|
||||||
#else
|
|
||||||
__wasi_rights_t rights_base;
|
|
||||||
__wasi_rights_t rights_inheriting;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Documented in external header file
|
|
||||||
struct po_map {
|
|
||||||
//! @internal
|
|
||||||
int refcount;
|
|
||||||
struct po_map_entry *entries;
|
|
||||||
size_t capacity;
|
|
||||||
size_t length;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is a directory a prefix of a given path?
|
|
||||||
*
|
|
||||||
* @param dir a directory path, e.g., `/foo/bar`
|
|
||||||
* @param dirlen the length of @b dir
|
|
||||||
* @param path a path that may have @b dir as a prefix,
|
|
||||||
* e.g., `/foo/bar/baz`
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
bool po_isprefix(const char *dir, size_t dirlen, const char *path);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check that a @ref po_map is valid (assert out if it's not).
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define po_map_assertvalid(...)
|
|
||||||
#else
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
void po_map_assertvalid(const struct po_map *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enlarge a @ref po_map's capacity.
|
|
||||||
*
|
|
||||||
* This results in new memory being allocated and existing entries being copied.
|
|
||||||
* If the allocation fails, the function will return NULL but the original
|
|
||||||
* map will remain valid.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map* po_map_enlarge(struct po_map *map);
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Store an error message in the global "last error message" buffer.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
void po_errormessage(const char *msg);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default map used by the libpreopen libc wrappers.
|
|
||||||
*
|
|
||||||
* If there is an existing default map, it will be freed before it is replaced.
|
|
||||||
* Passing NULL to this function will thus clear the default map.
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
void po_set_libc_map(struct po_map *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LIBPO_INTERNAL_H */
|
|
||||||
|
|
||||||
/** @endcond */
|
|
@ -1,261 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2016, 2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file libpreopen.c
|
|
||||||
* Implementation of high-level libpreopen functions.
|
|
||||||
*
|
|
||||||
* The functions defined in this source file are the highest-level API calls
|
|
||||||
* that client code will mostly use (plus po_map_create and po_map_release).
|
|
||||||
* po_isprefix is also defined here because it doesn't fit anywhere else.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
#include <fcntl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map*
|
|
||||||
po_add(struct po_map *map, const char *path, int fd)
|
|
||||||
{
|
|
||||||
struct po_map_entry *entry;
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
if (path == NULL || fd < 0) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map->length == map->capacity) {
|
|
||||||
map = po_map_enlarge(map);
|
|
||||||
if (map == NULL) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = map->entries + map->length;
|
|
||||||
map->length++;
|
|
||||||
|
|
||||||
entry->name = strdup(path);
|
|
||||||
entry->fd = fd;
|
|
||||||
|
|
||||||
#ifdef WITH_CAPSICUM
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
if (cap_rights_get(fd, &entry->rights) != 0) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
__wasi_fdstat_t statbuf;
|
|
||||||
int r = __wasi_fd_fdstat_get(fd, &statbuf);
|
|
||||||
if (r != 0) {
|
|
||||||
errno = r;
|
|
||||||
return NULL; // TODO: Add an infallible way to get the rights?
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->rights_base = statbuf.fs_rights_base;
|
|
||||||
entry->rights_inheriting = statbuf.fs_rights_inheriting;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
return (map);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath
|
|
||||||
po_find(struct po_map* map, const char *path, cap_rights_t *rights)
|
|
||||||
#else
|
|
||||||
static struct po_relpath
|
|
||||||
po_find(struct po_map* map, const char *path,
|
|
||||||
__wasi_rights_t rights_base, __wasi_rights_t rights_inheriting)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
const char *relpath ;
|
|
||||||
struct po_relpath match = { .relative_path = NULL, .dirfd = -1 };
|
|
||||||
size_t bestlen = 0;
|
|
||||||
int best = -1;
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
return (match);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < map->length; i++) {
|
|
||||||
const struct po_map_entry *entry = map->entries + i;
|
|
||||||
const char *name = entry->name;
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
size_t len = strnlen(name, MAXPATHLEN);
|
|
||||||
#else
|
|
||||||
size_t len = strlen(name);
|
|
||||||
bool any_matches = false;
|
|
||||||
|
|
||||||
if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) {
|
|
||||||
// We're matching a relative path that doesn't start with "./" and isn't ".".
|
|
||||||
if (len >= 2 && name[0] == '.' && name[1] == '/') {
|
|
||||||
// The entry starts with "./", so skip that prefix.
|
|
||||||
name += 2;
|
|
||||||
len -= 2;
|
|
||||||
} else if (len == 1 && name[0] == '.') {
|
|
||||||
// The entry is ".", so match it as an empty string.
|
|
||||||
name += 1;
|
|
||||||
len -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
if ((len <= bestlen) || !po_isprefix(name, len, path)) {
|
|
||||||
#else
|
|
||||||
if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) {
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WITH_CAPSICUM
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
if (rights && !cap_rights_contains(&entry->rights, rights)) {
|
|
||||||
#else
|
|
||||||
if ((rights_base & ~entry->rights_base) != 0 ||
|
|
||||||
(rights_inheriting & ~entry->rights_inheriting) != 0) {
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
best = entry->fd;
|
|
||||||
bestlen = len;
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
any_matches = true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
relpath = path + bestlen;
|
|
||||||
|
|
||||||
while (*relpath == '/') {
|
|
||||||
relpath++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*relpath == '\0') {
|
|
||||||
relpath = ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
match.relative_path = relpath;
|
|
||||||
match.dirfd = best;
|
|
||||||
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
bool
|
|
||||||
po_isprefix(const char *dir, size_t dirlen, const char *path)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
assert(dir != NULL);
|
|
||||||
assert(path != NULL);
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
// Allow an empty string as a prefix of any relative path.
|
|
||||||
if (path[0] != '/' && dirlen == 0)
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
for (i = 0; i < dirlen; i++)
|
|
||||||
{
|
|
||||||
if (path[i] != dir[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
// Ignore trailing slashes in directory names.
|
|
||||||
while (i > 0 && dir[i - 1] == '/') {
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return path[i] == '/' || path[i] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
int
|
|
||||||
po_preopen(struct po_map *map, const char *path, int flags, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int fd, mode;
|
|
||||||
|
|
||||||
va_start(args, flags);
|
|
||||||
mode = va_arg(args, int);
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = openat(AT_FDCWD, path, flags, mode);
|
|
||||||
if (fd == -1) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (po_add(map, path, fd) == NULL) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
return (fd);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
bool
|
|
||||||
po_print_entry(const char *name, int fd, cap_rights_t rights)
|
|
||||||
{
|
|
||||||
printf(" - name: '%s', fd: %d, rights: <rights>\n",
|
|
||||||
name, fd);
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,105 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file po_err.c
|
|
||||||
* @brief Error handling for libpreopen
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
#include "libpreopen.h"
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/* Disable all this error reporting code. */
|
|
||||||
static char error_buffer[1024];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
void
|
|
||||||
po_map_assertvalid(const struct po_map *map)
|
|
||||||
{
|
|
||||||
const struct po_map_entry *entry;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
assert(map->refcount > 0);
|
|
||||||
assert(map->length <= map->capacity);
|
|
||||||
assert(map->entries != NULL || map->capacity == 0);
|
|
||||||
|
|
||||||
for (i = 0; i < map->length; i++) {
|
|
||||||
entry = map->entries + i;
|
|
||||||
|
|
||||||
assert(entry->name != NULL);
|
|
||||||
assert(entry->fd >= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* !defined(NDEBUG) */
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
void
|
|
||||||
po_errormessage(const char *msg)
|
|
||||||
{
|
|
||||||
|
|
||||||
snprintf(error_buffer, sizeof(error_buffer), "%s: error %d",
|
|
||||||
msg, errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
po_last_error()
|
|
||||||
{
|
|
||||||
|
|
||||||
return (error_buffer);
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,717 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file po_libc_wrappers.c
|
|
||||||
* @brief Wrappers of libc functions that access global variables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef __wasilibc_unmodified_upstream // dlfcn
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
#include <errno.h>
|
|
||||||
#include <wasi/libc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
// Make all of the po_* implementation details private.
|
|
||||||
#include "libpreopen.c"
|
|
||||||
#include "po_map.c"
|
|
||||||
#include "po_err.c"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A default po_map that can be used implicitly by libc wrappers.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
static struct po_map *global_map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a relative path within the po_map given by SHARED_MEMORYFD (if it
|
|
||||||
* exists).
|
|
||||||
*
|
|
||||||
* @returns a struct po_relpath with dirfd and relative_path as set by po_find
|
|
||||||
* if there is an available po_map, or AT_FDCWD/path otherwise
|
|
||||||
*/
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
static struct po_relpath find_relative(const char *path, cap_rights_t *);
|
|
||||||
#else
|
|
||||||
static struct po_relpath find_relative(const char *path,
|
|
||||||
__wasi_rights_t rights_base,
|
|
||||||
__wasi_rights_t rights_inheriting);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the map that was handed into the process via `SHARED_MEMORYFD`
|
|
||||||
* (if it exists).
|
|
||||||
*/
|
|
||||||
static struct po_map* get_shared_map(void);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wrappers around system calls:
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `_open(2)` system call.
|
|
||||||
*
|
|
||||||
* `_open(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `openat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `openat(AT_FDCWD, original_path, ...)`, which is
|
|
||||||
* the same as the unwrapped `open(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
_open(const char *path, int flags, ...)
|
|
||||||
#else
|
|
||||||
/* We just need a plain open definition. */
|
|
||||||
open(const char *path, int flags, ...)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
struct po_relpath rel;
|
|
||||||
va_list args;
|
|
||||||
int mode;
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
va_start(args, flags);
|
|
||||||
mode = va_arg(args, int);
|
|
||||||
rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
if (flags & O_CREAT) {
|
|
||||||
va_start(args, flags);
|
|
||||||
mode = va_arg(args, int);
|
|
||||||
va_end(args);
|
|
||||||
} else {
|
|
||||||
mode = 0;
|
|
||||||
}
|
|
||||||
rel = find_relative(path, __WASI_RIGHT_PATH_OPEN, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
// If the file is already opened, no need of relative opening!
|
|
||||||
if( strcmp(rel.relative_path,".") == 0 )
|
|
||||||
return dup(rel.dirfd);
|
|
||||||
else
|
|
||||||
return openat(rel.dirfd, rel.relative_path, flags, mode);
|
|
||||||
#else
|
|
||||||
return openat(rel.dirfd, rel.relative_path, flags, mode);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `access(2)` system call.
|
|
||||||
*
|
|
||||||
* `access(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `faccessat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `faccessat(AT_FDCWD, original_path, ...)`, which is
|
|
||||||
* the same as the unwrapped `access(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
access(const char *path, int mode)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return faccessat(rel.dirfd, rel.relative_path, mode,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `connect(2)` system call.
|
|
||||||
*
|
|
||||||
* `connect(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `connectat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path, this
|
|
||||||
* wrapper will call `connectat(AT_FDCWD, original_path, ...)`, which is the
|
|
||||||
* same as the unwrapped `connect(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
connect(int s, const struct sockaddr *name, socklen_t namelen)
|
|
||||||
{
|
|
||||||
struct po_relpath rel;
|
|
||||||
|
|
||||||
if (name->sa_family == AF_UNIX) {
|
|
||||||
struct sockaddr_un *usock = (struct sockaddr_un *)name;
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
rel = find_relative(usock->sun_path, NULL);
|
|
||||||
strlcpy(usock->sun_path, rel.relative_path, sizeof(usock->sun_path));
|
|
||||||
#else
|
|
||||||
rel = find_relative(usock->sun_path, __WASI_RIGHT_CONNECT, 0);
|
|
||||||
if (strlen(rel.relative_path) + 1 > sizeof(usock->sun_path)) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(usock->sun_path, rel.relative_path);
|
|
||||||
#endif
|
|
||||||
return connectat(rel.dirfd, s, name, namelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return connectat(AT_FDCWD, s, name, namelen);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `eaccess(2)` system call.
|
|
||||||
*
|
|
||||||
* `eaccess(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `faccessat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path, this
|
|
||||||
* wrapper will call `faccessat(AT_FDCWD, original_path, ...)`, which is the
|
|
||||||
* same as the unwrapped `eaccess(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
eaccess(const char *path, int mode)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return faccessat(rel.dirfd, rel.relative_path, mode, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `lstat(2)` system call.
|
|
||||||
*
|
|
||||||
* `lstat(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `fstatat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `fstatat(AT_FDCWD, original_path, ...)`, which is
|
|
||||||
* the same as the unwrapped `lstat(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lstat(const char *path, struct stat *st)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return fstatat(rel.dirfd, rel.relative_path,st,AT_SYMLINK_NOFOLLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `open(2)` system call.
|
|
||||||
*
|
|
||||||
* `open(2)` will behave just like `_open(2)` if the varargs are unpacked and
|
|
||||||
* passed.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
open(const char *path, int flags, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int mode;
|
|
||||||
|
|
||||||
va_start(args, flags);
|
|
||||||
mode = va_arg(args, int);
|
|
||||||
return _open(path, flags, mode);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `rename(2)` system call.
|
|
||||||
*
|
|
||||||
* `rename(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `renameat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `renameat(AT_FDCWD, original_path, ...)`, which is
|
|
||||||
* the same as the unwrapped `rename(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
rename(const char *from, const char *to)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel_from = find_relative(from, NULL);
|
|
||||||
struct po_relpath rel_to = find_relative(to, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel_from = find_relative(from, __WASI_RIGHT_PATH_RENAME_SOURCE, 0);
|
|
||||||
struct po_relpath rel_to = find_relative(to, __WASI_RIGHT_PATH_RENAME_TARGET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_from.dirfd == -1 || rel_to.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return renameat(rel_from.dirfd, rel_from.relative_path, rel_to.dirfd,
|
|
||||||
rel_to.relative_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `stat(2)` system call.
|
|
||||||
*
|
|
||||||
* `stat(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `fstatat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `fstatat(AT_FDCWD, original_path, ...)`, which is
|
|
||||||
* the same as the unwrapped `stat(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
stat(const char *path, struct stat *st)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return fstatat(rel.dirfd, rel.relative_path,st, AT_SYMLINK_NOFOLLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `unlink(2)` system call.
|
|
||||||
*
|
|
||||||
* `unlink(2)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `unlinkat(2)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path,
|
|
||||||
* this wrapper will call `unlinkat(AT_FDCWD, original_path, 0) which is
|
|
||||||
* the same as the unwrapped `unlink(2)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
unlink(const char *path)
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
#else
|
|
||||||
struct po_relpath rel_pathname = find_relative(path, __WASI_RIGHT_PATH_UNLINK_FILE, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
return unlinkat(rel.dirfd, rel.relative_path, 0);
|
|
||||||
#else
|
|
||||||
// `unlinkat` ends up importing `__wasi_path_remove_directory` even
|
|
||||||
// though we're not passing `AT_REMOVEDIR` here. So instead, use a
|
|
||||||
// specialized function which just imports `__wasi_path_unlink_file`.
|
|
||||||
return __wasilibc_unlinkat(rel_pathname.dirfd, rel_pathname.relative_path);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wrappers around other libc calls:
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
/**
|
|
||||||
* Capability-safe wrapper around the `dlopen(3)` libc function.
|
|
||||||
*
|
|
||||||
* `dlopen(3)` accepts a path argument that can reference the global filesystem
|
|
||||||
* namespace. This is not a capability-safe operation, so this wrapper function
|
|
||||||
* attempts to look up the path (or a prefix of it) within the current global
|
|
||||||
* po_map and converts the call into the capability-safe `fdlopen(3)` if
|
|
||||||
* possible. If the current po_map does not contain the sought-after path, this
|
|
||||||
* wrapper will call `fdlopen(openat(AT_FDCWD, original_path), ...)`, which is
|
|
||||||
* the same as the unwrapped `dlopen(3)` call (i.e., will fail with `ECAPMODE`).
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
dlopen(const char *path, int mode)
|
|
||||||
{
|
|
||||||
struct po_relpath rel = find_relative(path, NULL);
|
|
||||||
|
|
||||||
return fdlopen(openat(rel.dirfd, rel.relative_path, 0, mode), mode);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
rmdir(const char *pathname)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return __wasilibc_rmdirat(rel_pathname.dirfd, rel_pathname.relative_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
remove(const char *pathname)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_pathname = find_relative(pathname,
|
|
||||||
__WASI_RIGHT_PATH_UNLINK_FILE |
|
|
||||||
__WASI_RIGHT_PATH_REMOVE_DIRECTORY,
|
|
||||||
0);
|
|
||||||
|
|
||||||
// If searching for both file and directory rights failed, try searching
|
|
||||||
// for either individually.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_UNLINK_FILE, 0);
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int r = __wasilibc_unlinkat(rel_pathname.dirfd, rel_pathname.relative_path);
|
|
||||||
if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE))
|
|
||||||
r = __wasilibc_rmdirat(rel_pathname.dirfd, rel_pathname.relative_path);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
link(const char *oldpath, const char *newpath)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_oldpath = find_relative(oldpath, __WASI_RIGHT_PATH_LINK_SOURCE, 0);
|
|
||||||
struct po_relpath rel_newpath = find_relative(newpath, __WASI_RIGHT_PATH_LINK_TARGET, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_oldpath.dirfd == -1 || rel_newpath.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return linkat(rel_oldpath.dirfd, rel_oldpath.relative_path,
|
|
||||||
rel_newpath.dirfd, rel_newpath.relative_path,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
mkdir(const char *pathname, mode_t mode)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mkdirat(rel_pathname.dirfd, rel_pathname.relative_path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
DIR *
|
|
||||||
opendir(const char *name)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_name = find_relative(name, __WASI_RIGHT_PATH_OPEN, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_name.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return opendirat(rel_name.dirfd, rel_name.relative_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
readlink(const char *pathname, char *buf, size_t bufsiz)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_READLINK, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_pathname.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return readlinkat(rel_pathname.dirfd, rel_pathname.relative_path,
|
|
||||||
buf, bufsiz);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
scandir(const char *dirp, struct dirent ***namelist,
|
|
||||||
int (*filter)(const struct dirent *),
|
|
||||||
int (*compar)(const struct dirent **, const struct dirent **))
|
|
||||||
{
|
|
||||||
struct po_relpath rel_dirp = find_relative(dirp,
|
|
||||||
__WASI_RIGHT_PATH_OPEN,
|
|
||||||
__WASI_RIGHT_FD_READDIR);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_dirp.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scandirat(rel_dirp.dirfd, rel_dirp.relative_path,
|
|
||||||
namelist, filter, compar);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
symlink(const char *target, const char *linkpath)
|
|
||||||
{
|
|
||||||
struct po_relpath rel_linkpath = find_relative(linkpath, __WASI_RIGHT_PATH_SYMLINK, 0);
|
|
||||||
|
|
||||||
// If we can't find a preopened directory handle to open this file with,
|
|
||||||
// indicate that the program lacks the capabilities.
|
|
||||||
if (rel_linkpath.dirfd == -1) {
|
|
||||||
errno = ENOTCAPABLE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return symlinkat(target, rel_linkpath.dirfd, rel_linkpath.relative_path);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
/* Provide tests with mechanism to set our static po_map */
|
|
||||||
void
|
|
||||||
po_set_libc_map(struct po_map *map)
|
|
||||||
{
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
map->refcount += 1;
|
|
||||||
|
|
||||||
if (global_map != NULL) {
|
|
||||||
po_map_release(global_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
global_map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct po_relpath
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
find_relative(const char *path, cap_rights_t *rights)
|
|
||||||
#else
|
|
||||||
find_relative(const char *path,
|
|
||||||
__wasi_rights_t rights_base,
|
|
||||||
__wasi_rights_t rights_inheriting)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
struct po_relpath rel;
|
|
||||||
struct po_map *map;
|
|
||||||
|
|
||||||
map = get_shared_map();
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
if (map == NULL) {
|
|
||||||
rel.dirfd = AT_FDCWD;
|
|
||||||
rel.relative_path = path;
|
|
||||||
} else {
|
|
||||||
rel = po_find(map, path, NULL);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
rel = po_find(map, path, rights_base, rights_inheriting);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct po_map*
|
|
||||||
get_shared_map()
|
|
||||||
{
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
struct po_map *map;
|
|
||||||
char *end, *env;
|
|
||||||
long fd;
|
|
||||||
|
|
||||||
// Do we already have a default map?
|
|
||||||
if (global_map) {
|
|
||||||
po_map_assertvalid(global_map);
|
|
||||||
return (global_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to unwrap po_map from a shared memory segment specified by
|
|
||||||
// SHARED_MEMORYFD
|
|
||||||
env = getenv("SHARED_MEMORYFD");
|
|
||||||
if (env == NULL || *env == '\0') {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We expect this environment variable to be an integer and nothing but
|
|
||||||
// an integer.
|
|
||||||
fd = strtol(env, &end, 10);
|
|
||||||
if (*end != '\0') {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map = po_unpack(fd);
|
|
||||||
if (map == NULL) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
global_map = map;
|
|
||||||
|
|
||||||
return (map);
|
|
||||||
#else
|
|
||||||
assert(global_map);
|
|
||||||
po_map_assertvalid(global_map);
|
|
||||||
return global_map;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
void
|
|
||||||
__wasilibc_init_preopen(void)
|
|
||||||
{
|
|
||||||
global_map = po_map_create(4);
|
|
||||||
if (global_map == NULL)
|
|
||||||
__builtin_trap();
|
|
||||||
po_map_assertvalid(global_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register the given pre-opened file descriptor under the given path.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
__wasilibc_register_preopened_fd(int fd, const char *path)
|
|
||||||
{
|
|
||||||
po_map_assertvalid(global_map);
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _REENTRANT
|
|
||||||
#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct po_map *map = po_add(global_map, path, fd);
|
|
||||||
if (map == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
global_map = map;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __wasilibc_find_relpath(const char *path,
|
|
||||||
__wasi_rights_t rights_base,
|
|
||||||
__wasi_rights_t rights_inheriting,
|
|
||||||
const char **relpath)
|
|
||||||
{
|
|
||||||
struct po_relpath rel = find_relative(path, rights_base, rights_inheriting);
|
|
||||||
*relpath = rel.relative_path;
|
|
||||||
return rel.dirfd;
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,131 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Stanley Uche Godfrey
|
|
||||||
* Copyright (c) 2016, 2018 Jonathan Anderson
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This software was developed at Memorial University under the
|
|
||||||
* NSERC Discovery program (RGPIN-2015-06048).
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file po_map.c
|
|
||||||
* @brief Implementation of po_map management functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map*
|
|
||||||
po_map_create(int capacity)
|
|
||||||
{
|
|
||||||
struct po_map *map;
|
|
||||||
|
|
||||||
map = malloc(sizeof(struct po_map));
|
|
||||||
if (map == NULL) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map->entries = calloc(sizeof(struct po_map_entry), capacity);
|
|
||||||
if (map->entries == NULL) {
|
|
||||||
free(map);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map->refcount = 1;
|
|
||||||
map->capacity = capacity;
|
|
||||||
map->length = 0;
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
return (map);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
struct po_map*
|
|
||||||
po_map_enlarge(struct po_map *map)
|
|
||||||
{
|
|
||||||
struct po_map_entry *enlarged;
|
|
||||||
enlarged = calloc(sizeof(struct po_map_entry), 2 * map->capacity);
|
|
||||||
if (enlarged == NULL) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
memcpy(enlarged, map->entries, map->length * sizeof(*enlarged));
|
|
||||||
free(map->entries);
|
|
||||||
map->entries = enlarged;
|
|
||||||
map->capacity = 2 * map->capacity;
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
size_t
|
|
||||||
po_map_foreach(const struct po_map *map, po_map_iter_cb cb)
|
|
||||||
{
|
|
||||||
struct po_map_entry *entry;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
for (n = 0; n < map->length; n++) {
|
|
||||||
entry = map->entries + n;
|
|
||||||
|
|
||||||
if (!cb(entry->name, entry->fd, entry->rights)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (n);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
#else
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
void
|
|
||||||
po_map_release(struct po_map *map)
|
|
||||||
{
|
|
||||||
if (map == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
po_map_assertvalid(map);
|
|
||||||
|
|
||||||
map->refcount -= 1;
|
|
||||||
|
|
||||||
if (map->refcount == 0) {
|
|
||||||
free(map->entries);
|
|
||||||
free(map);
|
|
||||||
}
|
|
||||||
}
|
|
551
libc-bottom-half/libpreopen/libpreopen.c
Normal file
551
libc-bottom-half/libpreopen/libpreopen.c
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
//! Preopen functionality for WASI libc, for emulating support for absolute
|
||||||
|
//! path names on top of WASI's OCap-style API.
|
||||||
|
//!
|
||||||
|
//! This file is derived from code in libpreopen, the upstream for which is:
|
||||||
|
//!
|
||||||
|
//! https://github.com/musec/libpreopen
|
||||||
|
//!
|
||||||
|
//! and which bears the following copyrights and license:
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2016-2017 Stanley Uche Godfrey
|
||||||
|
* Copyright (c) 2016-2018 Jonathan Anderson
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software was developed at Memorial University under the
|
||||||
|
* NSERC Discovery program (RGPIN-2015-06048).
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _REENTRANT
|
||||||
|
#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _ALL_SOURCE
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wasi/libc.h>
|
||||||
|
#include <wasi/libc-find-relpath.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// POSIX API compatibility wrappers
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int
|
||||||
|
open(const char *path, int flags, ...)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_OPEN, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WASI libc's openat ignores the mode argument, so don't bother passing
|
||||||
|
// the actual mode value through.
|
||||||
|
return openat(dirfd, relative_path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
access(const char *path, int mode)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return faccessat(dirfd, relative_path, mode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lstat(const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rename(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
const char *from_relative_path;
|
||||||
|
int from_dirfd = __wasilibc_find_relpath(from, __WASI_RIGHT_PATH_RENAME_SOURCE, 0,
|
||||||
|
&from_relative_path);
|
||||||
|
|
||||||
|
const char *to_relative_path;
|
||||||
|
int to_dirfd = __wasilibc_find_relpath(to, __WASI_RIGHT_PATH_RENAME_TARGET, 0,
|
||||||
|
&to_relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (from_dirfd == -1 || to_dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return renameat(from_dirfd, from_relative_path, to_dirfd, to_relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
stat(const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
unlink(const char *path)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_UNLINK_FILE, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `unlinkat` ends up importing `__wasi_path_remove_directory` even
|
||||||
|
// though we're not passing `AT_REMOVEDIR` here. So instead, use a
|
||||||
|
// specialized function which just imports `__wasi_path_unlink_file`.
|
||||||
|
return __wasilibc_unlinkat(dirfd, relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rmdir(const char *pathname)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __wasilibc_rmdirat(dirfd, relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
remove(const char *pathname)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(pathname,
|
||||||
|
__WASI_RIGHT_PATH_UNLINK_FILE |
|
||||||
|
__WASI_RIGHT_PATH_REMOVE_DIRECTORY,
|
||||||
|
0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If searching for both file and directory rights failed, try searching
|
||||||
|
// for either individually.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_UNLINK_FILE, 0,
|
||||||
|
&relative_path);
|
||||||
|
if (dirfd == -1) {
|
||||||
|
dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0,
|
||||||
|
&relative_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = __wasilibc_unlinkat(dirfd, relative_path);
|
||||||
|
if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE))
|
||||||
|
r = __wasilibc_rmdirat(dirfd, relative_path);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
link(const char *oldpath, const char *newpath)
|
||||||
|
{
|
||||||
|
const char *old_relative_path;
|
||||||
|
int old_dirfd = __wasilibc_find_relpath(oldpath, __WASI_RIGHT_PATH_LINK_SOURCE, 0,
|
||||||
|
&old_relative_path);
|
||||||
|
|
||||||
|
const char *new_relative_path;
|
||||||
|
int new_dirfd = __wasilibc_find_relpath(newpath, __WASI_RIGHT_PATH_LINK_TARGET, 0,
|
||||||
|
&new_relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (old_dirfd == -1 || new_dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkat(old_dirfd, old_relative_path, new_dirfd, new_relative_path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mkdir(const char *pathname, mode_t mode)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mkdirat(dirfd, relative_path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *
|
||||||
|
opendir(const char *name)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(name, __WASI_RIGHT_PATH_OPEN, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opendirat(dirfd, relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
readlink(const char *pathname, char *buf, size_t bufsiz)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_READLINK, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return readlinkat(dirfd, relative_path, buf, bufsiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
scandir(
|
||||||
|
const char *dirp,
|
||||||
|
struct dirent ***namelist,
|
||||||
|
int (*filter)(const struct dirent *),
|
||||||
|
int (*compar)(const struct dirent **, const struct dirent **))
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(dirp,
|
||||||
|
__WASI_RIGHT_PATH_OPEN,
|
||||||
|
__WASI_RIGHT_FD_READDIR,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scandirat(dirfd, relative_path, namelist, filter, compar);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
symlink(const char *target, const char *linkpath)
|
||||||
|
{
|
||||||
|
const char *relative_path;
|
||||||
|
int dirfd = __wasilibc_find_relpath(linkpath, __WASI_RIGHT_PATH_SYMLINK, 0,
|
||||||
|
&relative_path);
|
||||||
|
|
||||||
|
// If we can't find a preopened directory handle to open this file with,
|
||||||
|
// indicate that the program lacks the capabilities.
|
||||||
|
if (dirfd == -1) {
|
||||||
|
errno = ENOTCAPABLE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return symlinkat(target, dirfd, relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Support library
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// An entry in a po_map.
|
||||||
|
struct po_map_entry {
|
||||||
|
/// The name this file or directory is mapped to.
|
||||||
|
///
|
||||||
|
/// This name should look like a path, but it does not necessarily need
|
||||||
|
/// match to match the path it was originally obtained from.
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/// File descriptor (which may be a directory)
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/// Capability rights associated with the file descriptor
|
||||||
|
__wasi_rights_t rights_base;
|
||||||
|
__wasi_rights_t rights_inheriting;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A vector of po_map_entry.
|
||||||
|
struct po_map {
|
||||||
|
struct po_map_entry *entries;
|
||||||
|
size_t capacity;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct po_map global_map;
|
||||||
|
|
||||||
|
/// Is a directory a prefix of a given path?
|
||||||
|
///
|
||||||
|
/// @param dir a directory path, e.g., `/foo/bar`
|
||||||
|
/// @param dirlen the length of @b dir
|
||||||
|
/// @param path a path that may have @b dir as a prefix,
|
||||||
|
/// e.g., `/foo/bar/baz`
|
||||||
|
static bool
|
||||||
|
po_isprefix(const char *dir, size_t dirlen, const char *path)
|
||||||
|
{
|
||||||
|
assert(dir != NULL);
|
||||||
|
assert(path != NULL);
|
||||||
|
|
||||||
|
// Allow an empty string as a prefix of any relative path.
|
||||||
|
if (path[0] != '/' && dirlen == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < dirlen; i++)
|
||||||
|
{
|
||||||
|
if (path[i] != dir[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore trailing slashes in directory names.
|
||||||
|
while (i > 0 && dir[i - 1] == '/') {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path[i] == '/' || path[i] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enlarge a @ref po_map's capacity.
|
||||||
|
///
|
||||||
|
/// This results in new memory being allocated and existing entries being copied.
|
||||||
|
/// If the allocation fails, the function will return -1.
|
||||||
|
static int
|
||||||
|
po_map_enlarge(void)
|
||||||
|
{
|
||||||
|
size_t start_capacity = 4;
|
||||||
|
size_t new_capacity = global_map.capacity == 0 ?
|
||||||
|
start_capacity :
|
||||||
|
global_map.capacity * 2;
|
||||||
|
|
||||||
|
struct po_map_entry *enlarged =
|
||||||
|
calloc(sizeof(struct po_map_entry), new_capacity);
|
||||||
|
if (enlarged == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(enlarged, global_map.entries, global_map.length * sizeof(*enlarged));
|
||||||
|
free(global_map.entries);
|
||||||
|
global_map.entries = enlarged;
|
||||||
|
global_map.capacity = new_capacity;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assert that the global_map is valid.
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define po_map_assertvalid()
|
||||||
|
#else
|
||||||
|
static void
|
||||||
|
po_map_assertvalid(void)
|
||||||
|
{
|
||||||
|
const struct po_map_entry *entry;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
assert(global_map.length <= global_map.capacity);
|
||||||
|
assert(global_map.entries != NULL || global_map.capacity == 0);
|
||||||
|
|
||||||
|
for (i = 0; i < global_map.length; i++) {
|
||||||
|
entry = &global_map.entries[i];
|
||||||
|
|
||||||
|
assert(entry->name != NULL);
|
||||||
|
assert(entry->fd >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Register the given pre-opened file descriptor under the given path.
|
||||||
|
int
|
||||||
|
__wasilibc_register_preopened_fd(int fd, const char *path)
|
||||||
|
{
|
||||||
|
po_map_assertvalid();
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert(path != NULL);
|
||||||
|
|
||||||
|
if (global_map.length == global_map.capacity) {
|
||||||
|
int n = po_map_enlarge();
|
||||||
|
|
||||||
|
po_map_assertvalid();
|
||||||
|
|
||||||
|
if (n != 0) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__wasi_fdstat_t statbuf;
|
||||||
|
int r = __wasi_fd_fdstat_get((__wasi_fd_t)fd, &statbuf);
|
||||||
|
if (r != 0) {
|
||||||
|
errno = r;
|
||||||
|
return -1; // TODO: Add an infallible way to get the rights?
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *name = strdup(path);
|
||||||
|
if (name == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct po_map_entry *entry = &global_map.entries[global_map.length++];
|
||||||
|
|
||||||
|
entry->name = name;
|
||||||
|
entry->fd = fd;
|
||||||
|
entry->rights_base = statbuf.fs_rights_base;
|
||||||
|
entry->rights_inheriting = statbuf.fs_rights_inheriting;
|
||||||
|
|
||||||
|
po_map_assertvalid();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__wasilibc_find_relpath(
|
||||||
|
const char *path,
|
||||||
|
__wasi_rights_t rights_base,
|
||||||
|
__wasi_rights_t rights_inheriting,
|
||||||
|
const char **relative_path)
|
||||||
|
{
|
||||||
|
size_t bestlen = 0;
|
||||||
|
int best = -1;
|
||||||
|
|
||||||
|
po_map_assertvalid();
|
||||||
|
|
||||||
|
assert(path != NULL);
|
||||||
|
assert(relative_path != NULL);
|
||||||
|
|
||||||
|
bool any_matches = false;
|
||||||
|
for (size_t i = 0; i < global_map.length; i++) {
|
||||||
|
const struct po_map_entry *entry = &global_map.entries[i];
|
||||||
|
const char *name = entry->name;
|
||||||
|
size_t len = strlen(name);
|
||||||
|
|
||||||
|
if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) {
|
||||||
|
// We're matching a relative path that doesn't start with "./" and isn't ".".
|
||||||
|
if (len >= 2 && name[0] == '.' && name[1] == '/') {
|
||||||
|
// The entry starts with "./", so skip that prefix.
|
||||||
|
name += 2;
|
||||||
|
len -= 2;
|
||||||
|
} else if (len == 1 && name[0] == '.') {
|
||||||
|
// The entry is ".", so match it as an empty string.
|
||||||
|
name += 1;
|
||||||
|
len -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rights_base & ~entry->rights_base) != 0 ||
|
||||||
|
(rights_inheriting & ~entry->rights_inheriting) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
best = entry->fd;
|
||||||
|
bestlen = len;
|
||||||
|
any_matches = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *relpath = path + bestlen;
|
||||||
|
|
||||||
|
while (*relpath == '/') {
|
||||||
|
relpath++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*relpath == '\0') {
|
||||||
|
relpath = ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
*relative_path = relpath;
|
||||||
|
return best;
|
||||||
|
}
|
@ -35,7 +35,9 @@
|
|||||||
|
|
||||||
#undef TRE_MBSTATE
|
#undef TRE_MBSTATE
|
||||||
|
|
||||||
|
#ifdef __wasilibc_unmodified_upstream // Allow NDEBUG to be predefined.
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TRE_REGEX_T_FIELD __opaque
|
#define TRE_REGEX_T_FIELD __opaque
|
||||||
typedef int reg_errcode_t;
|
typedef int reg_errcode_t;
|
||||||
|
Loading…
Reference in New Issue
Block a user