Skip to content

Commit 98b4d75

Browse files
committed
Keep our own cwd and resolve paths in os
1 parent 12377c9 commit 98b4d75

4 files changed

Lines changed: 96 additions & 15 deletions

File tree

shared-bindings/os/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdbool.h>
1111

1212
#include "py/objtuple.h"
13+
#include "shared-module/os/__init__.h"
1314

1415
void common_hal_os_chdir(const char *path);
1516
mp_obj_t common_hal_os_getcwd(void);

shared-module/os/__init__.c

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
// SPDX-License-Identifier: MIT
88

9+
#include <stddef.h>
910
#include <string.h>
1011

1112
#include "extmod/vfs.h"
@@ -63,9 +64,73 @@ static mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_
6364
return mp_call_method_n_kw(n_args, 0, meth);
6465
}
6566

67+
const char *common_hal_os_path_abspath(const char *path) {
68+
const char *cwd;
69+
if (path[0] == '/') {
70+
cwd = "";
71+
} else {
72+
cwd = MP_STATE_VM(cwd_path);
73+
if (cwd == NULL) {
74+
char *new_cwd = m_malloc(2);
75+
strcpy(new_cwd, "/");
76+
MP_STATE_VM(cwd_path) = new_cwd;
77+
cwd = new_cwd;
78+
}
79+
}
80+
// Scan to see if the path has any `..` in it and return the same string if it doesn't
81+
bool found_dot_dot = false;
82+
size_t slash_count = 0;
83+
for (size_t i = 0; i < strlen(path); i++) {
84+
if (path[i] == '/') {
85+
slash_count++;
86+
}
87+
if (i + 2 < strlen(path) && path[i] == '/' && path[i + 1] == '.' && path[i + 2] == '.' && (i + 3 == strlen(path) || path[i + 3] == '/')) {
88+
found_dot_dot = true;
89+
}
90+
}
91+
if (!found_dot_dot) {
92+
return path;
93+
}
94+
95+
// Store the current output length for previous components so we can rewind to before them.
96+
size_t slashes[slash_count];
97+
char *full_path = m_malloc(strlen(cwd) + strlen(path) + 1);
98+
memcpy(full_path, cwd, strlen(cwd));
99+
memcpy(full_path + strlen(cwd), path, strlen(path) + 1);
100+
size_t output_len = 0;
101+
size_t component_len = 0;
102+
slash_count = 0;
103+
104+
// Remove `..` and `.`
105+
size_t original_len = strlen(full_path);
106+
for (size_t i = 0; i <= original_len; i++) {
107+
full_path[output_len++] = full_path[i];
108+
// Treat the final nul character as a slash.
109+
if (full_path[i] == '/' || full_path[i] == '\0') {
110+
if (component_len == 1 && full_path[i - 1] == '.') {
111+
// Remove the dot
112+
output_len = slashes[slash_count - 1];
113+
} else if (component_len == 2 && full_path[i - 1] == '.' && full_path[i - 2] == '.') {
114+
// Remove the double dot and the previous component if it exists
115+
slash_count--;
116+
output_len = slashes[slash_count - 1];
117+
} else {
118+
slashes[slash_count] = output_len;
119+
slash_count++;
120+
}
121+
component_len = 0;
122+
} else {
123+
component_len++;
124+
}
125+
}
126+
full_path[output_len] = '\0';
127+
return full_path;
128+
}
129+
66130
void common_hal_os_chdir(const char *path) {
131+
MP_STATE_VM(cwd_path) = common_hal_os_path_abspath(path);
67132
mp_obj_t path_out;
68-
mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out);
133+
mp_vfs_mount_t *vfs = lookup_dir_path(MP_STATE_VM(cwd_path), &path_out);
69134
MP_STATE_VM(vfs_cur) = vfs;
70135
if (vfs == MP_VFS_ROOT) {
71136
// If we change to the root dir and a VFS is mounted at the root then
@@ -84,12 +149,17 @@ void common_hal_os_chdir(const char *path) {
84149
}
85150

86151
mp_obj_t common_hal_os_getcwd(void) {
87-
return mp_vfs_getcwd();
152+
const char *cwd = MP_STATE_VM(cwd_path);
153+
if (cwd == NULL) {
154+
return MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
155+
}
156+
return mp_obj_new_str_of_type(&mp_type_str, (const byte *)cwd, strlen(cwd));
88157
}
89158

90159
mp_obj_t common_hal_os_listdir(const char *path) {
160+
const char *abspath = common_hal_os_path_abspath(path);
91161
mp_obj_t path_out;
92-
mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out);
162+
mp_vfs_mount_t *vfs = lookup_dir_path(abspath, &path_out);
93163
if (vfs == MP_VFS_ROOT) {
94164
vfs = MP_STATE_VM(vfs_mount_table);
95165
while (vfs != NULL) {
@@ -114,17 +184,19 @@ mp_obj_t common_hal_os_listdir(const char *path) {
114184
}
115185

116186
void common_hal_os_mkdir(const char *path) {
187+
const char *abspath = common_hal_os_path_abspath(path);
117188
mp_obj_t path_out;
118-
mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out);
189+
mp_vfs_mount_t *vfs = lookup_dir_path(abspath, &path_out);
119190
if (vfs == MP_VFS_ROOT || (vfs != MP_VFS_NONE && !strcmp(mp_obj_str_get_str(path_out), "/"))) {
120191
mp_raise_OSError(MP_EEXIST);
121192
}
122193
mp_vfs_proxy_call(vfs, MP_QSTR_mkdir, 1, &path_out);
123194
}
124195

125196
void common_hal_os_remove(const char *path) {
197+
const char *abspath = common_hal_os_path_abspath(path);
126198
mp_obj_t path_out;
127-
mp_vfs_mount_t *vfs = lookup_path(path, &path_out);
199+
mp_vfs_mount_t *vfs = lookup_path(abspath, &path_out);
128200
mp_vfs_proxy_call(vfs, MP_QSTR_remove, 1, &path_out);
129201
}
130202

@@ -140,14 +212,16 @@ void common_hal_os_rename(const char *old_path, const char *new_path) {
140212
}
141213

142214
void common_hal_os_rmdir(const char *path) {
215+
const char *abspath = common_hal_os_path_abspath(path);
143216
mp_obj_t path_out;
144-
mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out);
217+
mp_vfs_mount_t *vfs = lookup_dir_path(abspath, &path_out);
145218
mp_vfs_proxy_call(vfs, MP_QSTR_rmdir, 1, &path_out);
146219
}
147220

148221
mp_obj_t common_hal_os_stat(const char *path) {
222+
const char *abspath = common_hal_os_path_abspath(path);
149223
mp_obj_t path_out;
150-
mp_vfs_mount_t *vfs = lookup_path(path, &path_out);
224+
mp_vfs_mount_t *vfs = lookup_path(abspath, &path_out);
151225
if (vfs == MP_VFS_ROOT) {
152226
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
153227
t->items[0] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); // st_mode
@@ -160,8 +234,9 @@ mp_obj_t common_hal_os_stat(const char *path) {
160234
}
161235

162236
mp_obj_t common_hal_os_statvfs(const char *path) {
237+
const char *abspath = common_hal_os_path_abspath(path);
163238
mp_obj_t path_out;
164-
mp_vfs_mount_t *vfs = lookup_path(path, &path_out);
239+
mp_vfs_mount_t *vfs = lookup_path(abspath, &path_out);
165240
if (vfs == MP_VFS_ROOT) {
166241
// statvfs called on the root directory, see if there's anything mounted there
167242
for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
@@ -192,8 +267,11 @@ mp_obj_t common_hal_os_statvfs(const char *path) {
192267
}
193268

194269
void common_hal_os_utime(const char *path, mp_obj_t times) {
270+
const char *abspath = common_hal_os_path_abspath(path);
195271
mp_obj_t args[2];
196-
mp_vfs_mount_t *vfs = lookup_path(path, &args[0]);
272+
mp_vfs_mount_t *vfs = lookup_path(abspath, &args[0]);
197273
args[1] = times;
198274
mp_vfs_proxy_call(vfs, MP_QSTR_utime, 2, args);
199275
}
276+
277+
MP_REGISTER_ROOT_POINTER(const char *cwd_path);

shared-module/os/__init__.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t va
2626
// If any error code is returned, value is guaranteed not modified
2727
// An error that is not 'open' or 'not found' is printed on the repl.
2828
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value);
29+
30+
const char *common_hal_os_path_abspath(const char *path);

shared-module/pathlib/PosixPath.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ typedef struct _mp_obj_path_dir_iter_t {
2626
} mp_obj_path_dir_iter_t;
2727

2828
mp_obj_t pathlib_posixpath_from_str(mp_obj_t path_str) {
29-
pathlib_posixpath_obj_t *self = m_new_obj(pathlib_posixpath_obj_t);
30-
self->base.type = &pathlib_posixpath_type;
29+
pathlib_posixpath_obj_t *self = mp_obj_malloc(pathlib_posixpath_obj_t, &pathlib_posixpath_type);
3130
self->path_str = path_str;
3231
return MP_OBJ_FROM_PTR(self);
3332
}
@@ -290,8 +289,10 @@ mp_obj_t common_hal_pathlib_posixpath_absolute(pathlib_posixpath_obj_t *self) {
290289
}
291290

292291
mp_obj_t common_hal_pathlib_posixpath_resolve(pathlib_posixpath_obj_t *self) {
293-
// For now, just call absolute() since CircuitPython doesn't support symlinks
294-
return common_hal_pathlib_posixpath_absolute(self);
292+
const char *path = mp_obj_str_get_str(self->path_str);
293+
const char *abspath = common_hal_os_path_abspath(path);
294+
mp_obj_t abspath_obj = mp_obj_new_str(abspath, strlen(abspath));
295+
return pathlib_posixpath_from_str(abspath_obj);
295296
}
296297

297298
// Iterator iternext function - called for each iteration
@@ -310,8 +311,7 @@ static mp_obj_t path_dir_iter_iternext(mp_obj_t self_in) {
310311

311312
// Create a new path directory iterator
312313
mp_obj_t mp_obj_new_path_dir_iter(mp_obj_t path, mp_obj_t iter) {
313-
mp_obj_path_dir_iter_t *o = m_new_obj(mp_obj_path_dir_iter_t);
314-
o->base.type = &mp_type_polymorph_iter;
314+
mp_obj_path_dir_iter_t *o = mp_obj_malloc(mp_obj_path_dir_iter_t, &mp_type_polymorph_iter);
315315
o->iternext = path_dir_iter_iternext;
316316
o->path = path;
317317
o->iter = iter;

0 commit comments

Comments
 (0)