Skip to content

Commit 472d613

Browse files
In __wasilibc_find_abspath, handle relative paths correctly (#632)
Previously, if you called __wasilibc_find_abspath("foo/a.txt"), with "foo" being a preopened directory, it would return "foo" in abs_prefix and "foo/a.txt" in relative_path. Fixed this so it correctly returns "foo" in abs_prefix and "a.txt" in relative_path. --------- Co-authored-by: Pat Hickey <[email protected]>
1 parent 74ec0e4 commit 472d613

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

libc-bottom-half/sources/preopens.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ static int internal_register_preopened_fd(filesystem_preopens_own_descriptor_t f
131131
/// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`?
132132
static bool prefix_matches(const uint8_t *prefix, size_t prefix_len, const char *path) {
133133
// Allow an empty string as a prefix of any relative path.
134-
if (path[0] != '/' /* && prefix_len == 0 */)
134+
if (path[0] != '/' && prefix_len == 0)
135+
return true;
136+
137+
// Allow a '/' as a prefix of any relative path.
138+
if (path[0] != '/' && prefix_len == 1 && prefix[0] == '/')
135139
return true;
136140

137141
// Check whether any bytes of the prefix differ.
@@ -212,6 +216,10 @@ int __wasilibc_find_abspath(const char *path,
212216

213217
// The relative path is the substring after the portion that was matched.
214218
const char *computed = path;
219+
if (prefix_matches((const uint8_t*) *abs_prefix, match_len, path)
220+
&& !((*abs_prefix[0] == '/') && (path[0] != '/')))
221+
computed = path + match_len;
222+
215223
if (path[0] == '/')
216224
computed = path + match_len;
217225

test/src/misc/open_relative_path.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//! add-flags.py(RUN): --dir fs::foo
2+
//! add-flags.py(ARGS): foo
3+
4+
#include <errno.h>
5+
#include <fcntl.h>
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include <unistd.h>
10+
#include <sys/stat.h>
11+
#include "test.h"
12+
13+
#define TEST(c) do { \
14+
errno = 0; \
15+
if (!(c)) \
16+
t_error("%s failed (errno = %d)\n", #c, errno); \
17+
} while(0)
18+
19+
int main(int argc, char **argv)
20+
{
21+
TEST(argc == 2);
22+
23+
char *filename1, *filename2, *filename3, *filename4, *filename5;
24+
TEST(asprintf(&filename1, "%s/input.txt", argv[1]) != -1);
25+
26+
int fd = open(filename1, O_WRONLY | O_CREAT);
27+
TEST(fd > 2);
28+
close(fd);
29+
30+
TEST(asprintf(&filename2, "%s/dir1", argv[1]) != -1);
31+
TEST(mkdir(filename2, 0755) == 0);
32+
TEST(asprintf(&filename3, "%s/dir1/dir2", argv[1]) != -1);
33+
TEST(mkdir(filename3, 0755) == 0);
34+
TEST(asprintf(&filename4, "%s/dir1/dir2/dir3", argv[1]) != -1);
35+
TEST(mkdir(filename4, 0755) == 0);
36+
37+
TEST(asprintf(&filename5, "%s/input.txt", filename4) != -1);
38+
39+
fd = open(filename5, O_WRONLY | O_CREAT);
40+
TEST(fd > 2);
41+
close(fd);
42+
43+
TEST(unlink(filename5)==0);
44+
TEST(rmdir(filename4)==0);
45+
TEST(rmdir(filename3)==0);
46+
TEST(rmdir(filename2)==0);
47+
TEST(unlink(filename1)==0);
48+
49+
return t_status;
50+
}

0 commit comments

Comments
 (0)