Skip to content

Commit afffaaa

Browse files
authored
Preserve trailing slash in file path (#268)
This commit fixes the behavior of `path_open` such that if the path contains trailing slashes and the target file is not a directory, the call errors. This behavior is consistent with Linux host, Wasmtime, WAMR, and WasmEdge. fixes #267 Signed-off-by: Yage Hu <[email protected]>
1 parent 7aaa0b4 commit afffaaa

File tree

4 files changed

+89
-13
lines changed

4 files changed

+89
-13
lines changed

src/path_resolver.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,13 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path,
7878
char* last;
7979
size_t cur_len;
8080
int is_absolute;
81+
int has_trailing_slash;
8182

8283
if (path_len > normalized_len)
8384
return UVWASI_ENOBUFS;
8485

86+
has_trailing_slash = path_len > 0 && IS_SLASH(path[path_len - 1]);
87+
8588
is_absolute = uvwasi__is_absolute_path(path, path_len);
8689
normalized_path[0] = '\0';
8790
ptr = normalized_path;
@@ -156,6 +159,12 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path,
156159
*ptr = '\0';
157160
}
158161

162+
if (has_trailing_slash && !IS_SLASH(*(ptr - 1))) {
163+
*ptr = '/';
164+
ptr++;
165+
*ptr = '\0';
166+
}
167+
159168
return UVWASI_ESUCCESS;
160169
}
161170

@@ -171,7 +180,9 @@ static int uvwasi__is_path_sandboxed(const char* path,
171180
return path == strstr(path, fd_path) ? 1 : 0;
172181

173182
/* Handle relative fds that normalized to '.' */
174-
if (fd_path_len == 1 && fd_path[0] == '.') {
183+
if ((fd_path_len == 1 && fd_path[0] == '.')
184+
|| (fd_path_len == 2 && fd_path[0] == '.' && fd_path[1] == '/')
185+
) {
175186
/* If the fd's path is '.', then any path does not begin with '..' is OK. */
176187
if ((path_len == 2 && path[0] == '.' && path[1] == '.') ||
177188
(path_len > 2 && path[0] == '.' && path[1] == '.' && path[2] == '/')) {
@@ -348,7 +359,11 @@ static uvwasi_errno_t uvwasi__resolve_path_to_host(
348359
fake_path_len = strlen(fd->normalized_path);
349360

350361
/* If the fake path is '.' just ignore it. */
351-
if (fake_path_len == 1 && fd->normalized_path[0] == '.') {
362+
if ((fake_path_len == 1 && fd->normalized_path[0] == '.')
363+
|| (fake_path_len == 2
364+
&& fd->normalized_path[0] == '.'
365+
&& fd->normalized_path[1] == '/')
366+
) {
352367
fake_path_len = 0;
353368
}
354369

src/uvwasi.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,8 +2105,13 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
21052105
if (err != UVWASI_ESUCCESS)
21062106
goto close_file_and_error_exit;
21072107

2108-
if ((o_flags & UVWASI_O_DIRECTORY) != 0 &&
2109-
filetype != UVWASI_FILETYPE_DIRECTORY) {
2108+
if (
2109+
(filetype != UVWASI_FILETYPE_DIRECTORY)
2110+
&& (
2111+
(o_flags & UVWASI_O_DIRECTORY) != 0
2112+
|| (resolved_path[strlen(resolved_path) - 1] == '/')
2113+
)
2114+
) {
21102115
err = UVWASI_ENOTDIR;
21112116
goto close_file_and_error_exit;
21122117
}

test/test-path-open-trailing-slash.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include "uvwasi.h"
6+
#include "uv.h"
7+
#include "test-common.h"
8+
9+
#define TEST_TMP_DIR "./out/tmp"
10+
#define TEST_FILE "./out/tmp/test-path-open-trailing-slash.file"
11+
12+
int main(void) {
13+
const char* path = "test-path-open-trailing-slash.file/";
14+
uvwasi_t uvwasi;
15+
uvwasi_fd_t fd;
16+
uvwasi_options_t init_options;
17+
uvwasi_errno_t err;
18+
uv_fs_t req;
19+
int r;
20+
21+
setup_test_environment();
22+
23+
r = uv_fs_mkdir(NULL, &req, TEST_TMP_DIR, 0777, NULL);
24+
uv_fs_req_cleanup(&req);
25+
assert(r == 0 || r == UV_EEXIST);
26+
27+
r = uv_fs_open(NULL, &req, TEST_FILE, UV_FS_O_CREAT | UV_FS_O_RDWR, 0777, NULL);
28+
uv_fs_req_cleanup(&req);
29+
assert(r >= 0);
30+
31+
uvwasi_options_init(&init_options);
32+
init_options.preopenc = 1;
33+
init_options.preopens = calloc(1, sizeof(uvwasi_preopen_t));
34+
init_options.preopens[0].mapped_path = "/var";
35+
init_options.preopens[0].real_path = TEST_TMP_DIR;
36+
37+
err = uvwasi_init(&uvwasi, &init_options);
38+
assert(err == 0);
39+
40+
err = uvwasi_path_open(&uvwasi,
41+
3,
42+
0,
43+
path,
44+
strlen(path) + 1,
45+
0,
46+
0,
47+
0,
48+
0,
49+
&fd);
50+
assert(err != UVWASI_ESUCCESS);
51+
52+
uvwasi_destroy(&uvwasi);
53+
free(init_options.preopens);
54+
55+
return 0;
56+
}

test/test-path-resolution.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ int main(void) {
148148
/* Arguments: input path, expected normalized path */
149149
check_normalize("", ".");
150150
check_normalize(".", ".");
151-
check_normalize("./", ".");
151+
check_normalize("./", "./");
152152
check_normalize("./.", ".");
153153
check_normalize("./..", "..");
154-
check_normalize("./../", "..");
154+
check_normalize("./../", "../");
155155
check_normalize("..", "..");
156-
check_normalize("../", "..");
156+
check_normalize("../", "../");
157157
check_normalize("../.", "..");
158158
check_normalize("../..", "../..");
159159
check_normalize("/", "/");
@@ -165,18 +165,18 @@ int main(void) {
165165
check_normalize("/foo/../bar", "/bar");
166166
check_normalize("/../bar", "/bar");
167167
check_normalize("/../../../bar", "/bar");
168-
check_normalize("/../../../bar/", "/bar");
168+
check_normalize("/../../../bar/", "/bar/");
169169
check_normalize("/../../../", "/");
170170
check_normalize("////..//../..///", "/");
171-
check_normalize("./foo//", "foo");
171+
check_normalize("./foo//", "foo/");
172172
check_normalize("./foo/////bar", "foo/bar");
173173
check_normalize("//", "/");
174-
check_normalize("..//", "..");
175-
check_normalize(".//", ".");
174+
check_normalize("..//", "../");
175+
check_normalize(".//", "./");
176176
check_normalize("./foo/bar/baz/../../../..", "..");
177-
check_normalize("./foo/bar/baz/../../../../", "..");
177+
check_normalize("./foo/bar/baz/../../../../", "../");
178178
check_normalize("./foo/bar/baz/../../../../..", "../..");
179-
check_normalize("./foo/bar/baz/../../../../../", "../..");
179+
check_normalize("./foo/bar/baz/../../../../../", "../../");
180180
check_normalize("../../../test_path", "../../../test_path");
181181
check_normalize("./././test_path", "test_path");
182182

0 commit comments

Comments
 (0)