From 28383afa11863f1fe289cc811c8eab403ea79f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 9 Nov 2018 18:25:55 +0100 Subject: [PATCH] shared-module/os: Fix os.mkdir('a/b') This fixes commit a99f9427420d("'/' and '\' are also acceptable ends of the path now") which broke mkdir. The problem is where the directory name is a single letter like this: >>> os.mkdir('a') >>> os.mkdir('a/b') Traceback (most recent call last): File "", line 1, in OSError: [Errno 17] File exists >>> os.mkdir('a/bb') >>> I wasn't smart enough to fix this in the oofatfs library, so I did it in the os shared module by creating a path lookup function for the os methods that only deals with directories. I reverted the library change introduced by the aforementioned commit. This means that os.stat and os.rename can't handle trailing slashes. This is to avoid allowing filenames with trailing slashes to pass through. In order to handle trailing slashes for these it would be necessary to check if it really is a directory before stripping. I didn't do this since the original issue was to make os.chdir tolerate trailing slashes. There's an open MicroPython issue #2929 wrt. trailing slashes and mkdir. --- lib/oofatfs/ff.c | 2 +- shared-module/os/__init__.c | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index 4e86805458..b0984756bf 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -2579,8 +2579,8 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ lfn[di++] = w; /* Store the Unicode character */ } - cf = ((w < ' ') || ((w == '/' || w == '\\') && p[si+1] < ' ')) ? NS_LAST : 0; /* Set last segment flag if end of the path */ *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ #if _FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index a38f3781f1..313893d977 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -50,6 +50,20 @@ STATIC mp_vfs_mount_t *lookup_path(const char* path, mp_obj_t *path_out) { return vfs; } +// Strip off trailing slashes to please underlying libraries +STATIC mp_vfs_mount_t *lookup_dir_path(const char* path, mp_obj_t *path_out) { + const char *p_out; + mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &p_out); + if (vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) { + size_t len = strlen(p_out); + while (len > 1 && p_out[len - 1] == '/') { + len--; + } + *path_out = mp_obj_new_str_of_type(&mp_type_str, (const byte*)p_out, len); + } + return vfs; +} + STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) { if (vfs == MP_VFS_NONE) { // mount point not found @@ -69,7 +83,7 @@ STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_ void common_hal_os_chdir(const char* path) { mp_obj_t path_out; - mp_vfs_mount_t *vfs = lookup_path(path, &path_out); + mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out); MP_STATE_VM(vfs_cur) = vfs; if (vfs == MP_VFS_ROOT) { // If we change to the root dir and a VFS is mounted at the root then @@ -93,7 +107,7 @@ mp_obj_t common_hal_os_getcwd(void) { mp_obj_t common_hal_os_listdir(const char* path) { mp_obj_t path_out; - mp_vfs_mount_t *vfs = lookup_path(path, &path_out); + mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out); mp_vfs_ilistdir_it_t iter; mp_obj_t iter_obj = MP_OBJ_FROM_PTR(&iter); @@ -120,7 +134,7 @@ mp_obj_t common_hal_os_listdir(const char* path) { void common_hal_os_mkdir(const char* path) { mp_obj_t path_out; - mp_vfs_mount_t *vfs = lookup_path(path, &path_out); + mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out); if (vfs == MP_VFS_ROOT || (vfs != MP_VFS_NONE && !strcmp(mp_obj_str_get_str(path_out), "/"))) { mp_raise_OSError(MP_EEXIST); } @@ -146,7 +160,7 @@ void common_hal_os_rename(const char* old_path, const char* new_path) { void common_hal_os_rmdir(const char* path) { mp_obj_t path_out; - mp_vfs_mount_t *vfs = lookup_path(path, &path_out); + mp_vfs_mount_t *vfs = lookup_dir_path(path, &path_out); mp_vfs_proxy_call(vfs, MP_QSTR_rmdir, 1, &path_out); }