extmod/vfs_reader: Fix mp_reader_new_file to open file in "rb" mode.
mp_reader_new_file() is used to read in files for importing, either .py or .mpy files, for the lexer and persistent code loader respectively. In both cases the file should be opened in raw bytes mode: the lexer handles unicode characters itself, and .mpy files contain 8-bit bytes by nature. Before this commit importing was working correctly because, although the file was opened in text mode, all native filesystem implementations (POSIX, FAT, LFS) would access the file in raw bytes mode via mp_stream_rw() calling mp_stream_p_t.read(). So it was only an issue for non-native filesystems, such as those implemented in Python. For Python-based filesystem implementations, a call to mp_stream_rw() would go via IOBase and then to readinto() at the Python level, and readinto() is only defined on files opened in raw bytes mode. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
b731bd0ce6
commit
60f5b941e0
|
@ -71,8 +71,11 @@ STATIC void mp_reader_vfs_close(void *data) {
|
||||||
|
|
||||||
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
|
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
|
||||||
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
|
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
|
||||||
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));
|
mp_obj_t args[2] = {
|
||||||
rf->file = mp_vfs_open(1, &arg, (mp_map_t *)&mp_const_empty_map);
|
mp_obj_new_str(filename, strlen(filename)),
|
||||||
|
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
|
||||||
|
};
|
||||||
|
rf->file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
|
||||||
int errcode;
|
int errcode;
|
||||||
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
||||||
if (errcode != 0) {
|
if (errcode != 0) {
|
||||||
|
|
|
@ -16,14 +16,20 @@ except (ImportError, AttributeError):
|
||||||
|
|
||||||
|
|
||||||
class UserFile(uio.IOBase):
|
class UserFile(uio.IOBase):
|
||||||
def __init__(self, data):
|
def __init__(self, mode, data):
|
||||||
|
assert isinstance(data, bytes)
|
||||||
|
self.is_text = mode.find("b") == -1
|
||||||
self.data = data
|
self.data = data
|
||||||
self.pos = 0
|
self.pos = 0
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
|
if self.is_text:
|
||||||
|
return str(self.data, "utf8")
|
||||||
|
else:
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def readinto(self, buf):
|
def readinto(self, buf):
|
||||||
|
assert not self.is_text
|
||||||
n = 0
|
n = 0
|
||||||
while n < len(buf) and self.pos < len(self.data):
|
while n < len(buf) and self.pos < len(self.data):
|
||||||
buf[n] = self.data[self.pos]
|
buf[n] = self.data[self.pos]
|
||||||
|
@ -54,12 +60,12 @@ class UserFS:
|
||||||
|
|
||||||
def open(self, path, mode):
|
def open(self, path, mode):
|
||||||
print("open", path, mode)
|
print("open", path, mode)
|
||||||
return UserFile(self.files[path])
|
return UserFile(mode, self.files[path])
|
||||||
|
|
||||||
|
|
||||||
# create and mount a user filesystem
|
# create and mount a user filesystem
|
||||||
user_files = {
|
user_files = {
|
||||||
"/data.txt": b"some data in a text file\n",
|
"/data.txt": b"some data in a text file",
|
||||||
"/usermod1.py": b"print('in usermod1')\nimport usermod2",
|
"/usermod1.py": b"print('in usermod1')\nimport usermod2",
|
||||||
"/usermod2.py": b"print('in usermod2')",
|
"/usermod2.py": b"print('in usermod2')",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
open /data.txt r
|
open /data.txt r
|
||||||
b'some data in a text file\n'
|
some data in a text file
|
||||||
stat /usermod1
|
stat /usermod1
|
||||||
stat /usermod1.py
|
stat /usermod1.py
|
||||||
open /usermod1.py r
|
open /usermod1.py rb
|
||||||
ioctl 4 0
|
ioctl 4 0
|
||||||
in usermod1
|
in usermod1
|
||||||
stat /usermod2
|
stat /usermod2
|
||||||
stat /usermod2.py
|
stat /usermod2.py
|
||||||
open /usermod2.py r
|
open /usermod2.py rb
|
||||||
ioctl 4 0
|
ioctl 4 0
|
||||||
in usermod2
|
in usermod2
|
||||||
|
|
Loading…
Reference in New Issue