]>
git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/sources/chdir.c
8 #include <wasi/libc-find-relpath.h>
12 #error "chdir doesn't yet support multiple threads"
15 extern char *__wasilibc_cwd
;
16 static int __wasilibc_cwd_mallocd
= 0;
18 int chdir(const char *path
)
20 static char *relative_buf
= NULL
;
21 static size_t relative_buf_len
= 0;
23 // Find a preopen'd directory as well as a relative path we're anchored
24 // from which we're changing directories to.
26 int parent_fd
= __wasilibc_find_relpath_alloc(path
, &abs
, &relative_buf
, &relative_buf_len
, 1);
30 // Make sure that this directory we're accessing is indeed a directory.
32 int ret
= fstatat(parent_fd
, relative_buf
, &dirinfo
, 0);
35 if (!S_ISDIR(dirinfo
.st_mode
)) {
40 // Create a string that looks like:
42 // __wasilibc_cwd = "/" + abs + "/" + relative_buf
44 // If `relative_buf` is equal to "." or `abs` is equal to the empty string,
45 // however, we skip that part and the middle slash.
46 size_t abs_len
= strlen(abs
);
47 int copy_relative
= strcmp(relative_buf
, ".") != 0;
48 int mid
= copy_relative
&& abs
[0] != 0;
49 char *new_cwd
= malloc(1 + abs_len
+ mid
+ (copy_relative
? strlen(relative_buf
) : 0) + 1);
50 if (new_cwd
== NULL
) {
55 strcpy(new_cwd
+ 1, abs
);
57 new_cwd
[1 + abs_len
] = '/';
59 strcpy(new_cwd
+ 1 + abs_len
+ mid
, relative_buf
);
61 // And set our new malloc'd buffer into the global cwd, freeing the
62 // previous one if necessary.
63 char *prev_cwd
= __wasilibc_cwd
;
64 __wasilibc_cwd
= new_cwd
;
65 if (__wasilibc_cwd_mallocd
)
67 __wasilibc_cwd_mallocd
= 1;
71 static const char *make_absolute(const char *path
) {
72 static char *make_absolute_buf
= NULL
;
73 static size_t make_absolute_len
= 0;
75 // If this path is absolute, then we return it as-is.
80 // If the path is empty, or points to the current directory, then return
81 // the current directory.
82 if (path
[0] == 0 || !strcmp(path
, ".") || !strcmp(path
, "./")) {
83 return __wasilibc_cwd
;
86 // If the path starts with `./` then we won't be appending that to the cwd.
87 if (path
[0] == '.' && path
[1] == '/')
90 // Otherwise we'll take the current directory, add a `/`, and then add the
91 // input `path`. Note that this doesn't do any normalization (like removing
93 size_t cwd_len
= strlen(__wasilibc_cwd
);
94 size_t path_len
= strlen(path
);
95 int need_slash
= __wasilibc_cwd
[cwd_len
- 1] == '/' ? 0 : 1;
96 size_t alloc_len
= cwd_len
+ path_len
+ 1 + need_slash
;
97 if (alloc_len
> make_absolute_len
) {
98 char *tmp
= realloc(make_absolute_buf
, alloc_len
);
101 make_absolute_buf
= tmp
;
102 make_absolute_len
= alloc_len
;
104 strcpy(make_absolute_buf
, __wasilibc_cwd
);
106 strcpy(make_absolute_buf
+ cwd_len
, "/");
107 strcpy(make_absolute_buf
+ cwd_len
+ need_slash
, path
);
108 return make_absolute_buf
;
111 // Helper function defined only in this object file and weakly referenced from
112 // `preopens.c` and `posix.c` This function isn't necessary unless `chdir` is
113 // pulled in because all paths are otherwise absolute or relative to the root.
114 int __wasilibc_find_relpath_alloc(
116 const char **abs_prefix
,
118 size_t *relative_buf_len
,
121 // First, make our path absolute taking the cwd into account.
122 const char *abspath
= make_absolute(path
);
123 if (abspath
== NULL
) {
128 // Next use our absolute path and split it. Find the preopened `fd` parent
129 // directory and set `abs_prefix`. Next up we'll be trying to fit `rel`
130 // into `relative_buf`.
132 int fd
= __wasilibc_find_abspath(abspath
, abs_prefix
, &rel
);
136 size_t rel_len
= strlen(rel
);
137 if (*relative_buf_len
< rel_len
+ 1) {
142 char *tmp
= realloc(*relative_buf
, rel_len
+ 1);
148 *relative_buf_len
= rel_len
+ 1;
150 strcpy(*relative_buf
, rel
);