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+
66130void 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
86151mp_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
90159mp_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
116186void 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
125196void 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
142214void 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
148221mp_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
162236mp_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
194269void 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 );
0 commit comments