vfs_posix_rename old_path points to the same as new_path
Hi,
During my investigation of vfs posix MPY 1.15, I found that there is issue in logic as following, although I have not tested it yet. Please refer to file https://github.com/micropython/micropython/blob/master/extmod/vfs_posix.c, line 271.
At first, old_path points to root buffer, member of mp_obj_vfs_posix_t .
After that, new_path also points to root buffer with new value "new_path_in". At this point, both old_path and new_path points to the same string in root buffer with the latest value "new_path_in".
So when executing rename(old_path, new_path) will be failed.
STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
MP_THREAD_GIL_EXIT();
int ret = rename(old_path, new_path);
MP_THREAD_GIL_ENTER();
if (ret != 0) {
mp_raise_OSError(errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);
extmod/vfs_posix: Fix relative paths on non-root VFS
VfsPosix has a couple of bugs regarding handling of relative paths and chdir()/getcwd() that surface when it is instanced with a non-empty root path (i.e. only a subtree of the outer filesystem is exposed to Python).
They are somewhat entangled, but I tried my best to separate the fixes into individually reviewable commits, each with first a failing test that demonstrates what is going wrong, followed by fixes that makes it pass. (The tricky part of that was to get the fixes in the right order and craft the tests such that they actually pass after the respective fix, rather than continuing to fail due to the remaining bugs.)
-
A
VfsPosixcreated with a relative root path gets confused whenchdir()is called on it and becomes unable to properly resolve absolute paths, because changing directories effectively shifts its root. The simplest fix for that would be to say “don’t do that”, but since the unit tests themselves do it, fix it by making a relative path absolute before storing it. -
The unwritten API contract expected of a VFS by
mp_vfs_lookup_path()is that paths passed in are relative to the root of the VFS if they start with/and relative to the current directory of the VFS otherwise. This is not correctly implemented inVfsPosixfor instances with a non-empty root – all paths are interpreted relative to the root. Fix that. SinceVfsPosixtracks its CWD using the “external” CWD of the Unix process, the correct handling for relative paths is to pass them through unmodified. -
The unwritten API contract expected of a VFS
.getcwd()bymp_vfs_getcwd()is that its return value should be either""or"/"when the CWD is at the root of the VFS and otherwise start with a slash and not end with a slash. This is not correctly implemented inVfsPosixfor instances with a non-empty root – the required leading slash, if any, is cut off because the root length includes a trailing slash. This results in missing slashes in the middle of the return value ofos.getcwd()or in uninitialized garbage from beyond a string’s null terminator when the CWD is at the VFS root.
The matter is complicated by the fact that there are some faulty existing tests that only pass by accident due to bug 2. Unmodified, they would fail after the fix for bug 2 (5th commit), however that is insignificant because they actually test an unrealistic situation. Fixing them in the 3rd commit to match the realistic situation makes them pass with bug 2 fixed (and also without, when done in this order, because after the 2nd commit, bug 2 has no effect in that case).
The unrealistic situation is that VfsPosix methods are called with relative paths while the current working directory is somewhere outside of the root of the VFS. In the intended use of VFS objects via os.mount() (as opposed to calling methods directly as the tests do), this never happens, as mp_vfs_lookup_path() directs incoming calls to the VFS that contains the CWD. Fix this by explicitly changing the working directory to the root of the VFS before calling methods on it, as the subsequent relative path accesses expect.