extmod/vfs_posix: Fix relative paths on non-root VFS.

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 was not correctly implemented in VfsPosix for instances with a
non-empty root - all paths were interpreted relative to the root. Fix
that. Since VfsPosix tracks its CWD using the "external" CWD of the Unix
process, the correct handling for relative paths is to pass them through
unmodified.

Also, when concatenating absolute paths, fix an off-by-one resulting in
a harmless double slash (the root path already has a trailing slash).

Signed-off-by: Christian Walther <cwalther@gmx.ch>
pull/12137/head
Christian Walther 2023-07-30 14:48:22 +02:00
rodzic 5f7065f57a
commit 0c4fb16871
3 zmienionych plików z 95 dodań i 7 usunięć

Wyświetl plik

@ -58,21 +58,23 @@ typedef struct _mp_obj_vfs_posix_t {
} mp_obj_vfs_posix_t;
STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) {
if (self->root_len == 0) {
return mp_obj_str_get_str(path);
const char *path_str = mp_obj_str_get_str(path);
if (self->root_len == 0 || path_str[0] != '/') {
return path_str;
} else {
self->root.len = self->root_len;
vstr_add_str(&self->root, mp_obj_str_get_str(path));
self->root.len = self->root_len - 1;
vstr_add_str(&self->root, path_str);
return vstr_null_terminated_str(&self->root);
}
}
STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) {
if (self->root_len == 0) {
const char *path_str = mp_obj_str_get_str(path);
if (self->root_len == 0 || path_str[0] != '/') {
return path;
} else {
self->root.len = self->root_len;
vstr_add_str(&self->root, mp_obj_str_get_str(path));
self->root.len = self->root_len - 1;
vstr_add_str(&self->root, path_str);
return mp_obj_new_str(self->root.buf, self->root.len);
}
}

Wyświetl plik

@ -0,0 +1,73 @@
# Test for VfsPosix with relative paths
try:
import os
os.VfsPosix
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit
# We need a directory for testing that doesn't already exist.
# Skip the test if it does exist.
temp_dir = "vfs_posix_paths_test_dir"
try:
import os
os.stat(temp_dir)
print("SKIP")
raise SystemExit
except OSError:
pass
curdir = os.getcwd()
os.mkdir(temp_dir)
# construct new VfsPosix with absolute path argument
temp_dir_abs = os.getcwd() + os.sep + temp_dir
vfs = os.VfsPosix(temp_dir_abs)
# when VfsPosix is used the intended way via os.mount(), it can only be called
# with relative paths when the CWD is inside or at its root, so simulate that
os.chdir(temp_dir_abs)
vfs.mkdir("subdir")
vfs.mkdir("subdir/one")
print('listdir("/"):', sorted(i[0] for i in vfs.ilistdir("/")))
print('listdir("."):', sorted(i[0] for i in vfs.ilistdir(".")))
print('getcwd() in {"", "/"}:', vfs.getcwd() in {"", "/"})
print('chdir("subdir"):', vfs.chdir("subdir"))
print("getcwd():", vfs.getcwd())
print('mkdir("two"):', vfs.mkdir("two"))
f = vfs.open("file.py", "w")
f.write("print('hello')")
f.close()
print('listdir("/"):', sorted(i[0] for i in vfs.ilistdir("/")))
print('listdir("/subdir"):', sorted(i[0] for i in vfs.ilistdir("/subdir")))
print('listdir("."):', sorted(i[0] for i in vfs.ilistdir(".")))
try:
f = vfs.open("/subdir/file.py", "r")
print(f.read())
f.close()
except Exception as e:
print(e)
import sys
sys.path.insert(0, "")
try:
import file
print(file)
except Exception as e:
print(e)
del sys.path[0]
vfs.remove("file.py")
vfs.rmdir("two")
vfs.rmdir("/subdir/one")
vfs.chdir("/")
vfs.rmdir("/subdir")
# done with vfs, restore CWD
os.chdir(curdir)
# rmdir
os.rmdir(temp_dir)
print(temp_dir in os.listdir())

Wyświetl plik

@ -0,0 +1,13 @@
listdir("/"): ['subdir']
listdir("."): ['subdir']
getcwd() in {"", "/"}: True
chdir("subdir"): None
getcwd(): subdir
mkdir("two"): None
listdir("/"): ['subdir']
listdir("/subdir"): ['file.py', 'one', 'two']
listdir("."): ['file.py', 'one', 'two']
print('hello')
hello
<module 'file' from 'file.py'>
False