mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 23:38:09 +00:00
Merge pull request #878 from trezor/matejcik/fatfs-corruption
FatFS API rework
This commit is contained in:
commit
86b010a18b
@ -27,7 +27,19 @@
|
|||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
/// package: trezorio.__init__
|
/// package: trezorio.fatfs
|
||||||
|
|
||||||
|
static FATFS fs_instance;
|
||||||
|
|
||||||
|
bool _fatfs_instance_is_mounted() { return fs_instance.fs_type != 0; }
|
||||||
|
void _fatfs_unmount_instance() { fs_instance.fs_type = 0; }
|
||||||
|
|
||||||
|
#define FATFS_ONLY_MOUNTED \
|
||||||
|
{ \
|
||||||
|
if (!_fatfs_instance_is_mounted()) { \
|
||||||
|
mp_raise_OSError(MP_ENODEV); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
DSTATUS disk_initialize(BYTE pdrv) { return disk_status(pdrv); }
|
DSTATUS disk_initialize(BYTE pdrv) { return disk_status(pdrv); }
|
||||||
|
|
||||||
@ -315,33 +327,14 @@ STATIC const mp_obj_type_t mod_trezorio_FatFSDir_type = {
|
|||||||
.iternext = mod_trezorio_FatFSDir_iternext,
|
.iternext = mod_trezorio_FatFSDir_iternext,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// class FatFS:
|
/// mock:global
|
||||||
/// """
|
|
||||||
/// Class encapsulating FAT filesystem
|
|
||||||
/// """
|
|
||||||
typedef struct _mp_obj_FatFS_t {
|
|
||||||
mp_obj_base_t base;
|
|
||||||
FATFS fs;
|
|
||||||
} mp_obj_FatFS_t;
|
|
||||||
|
|
||||||
/// def __init__(self) -> None:
|
/// def open(path: str, flags: str) -> FatFSFile:
|
||||||
/// """
|
|
||||||
/// """
|
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_make_new(const mp_obj_type_t *type,
|
|
||||||
size_t n_args, size_t n_kw,
|
|
||||||
const mp_obj_t *args) {
|
|
||||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
|
||||||
mp_obj_FatFS_t *o = m_new_obj(mp_obj_FatFS_t);
|
|
||||||
o->base.type = type;
|
|
||||||
return MP_OBJ_FROM_PTR(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// def open(self, path: str, flags: str) -> FatFSFile:
|
|
||||||
/// """
|
/// """
|
||||||
/// Open or create a file
|
/// Open or create a file
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_open(mp_obj_t self, mp_obj_t path,
|
STATIC mp_obj_t mod_trezorio_fatfs_open(mp_obj_t path, mp_obj_t flags) {
|
||||||
mp_obj_t flags) {
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _path, _flags;
|
mp_buffer_info_t _path, _flags;
|
||||||
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
||||||
mp_get_buffer_raise(flags, &_flags, MP_BUFFER_READ);
|
mp_get_buffer_raise(flags, &_flags, MP_BUFFER_READ);
|
||||||
@ -376,14 +369,15 @@ STATIC mp_obj_t mod_trezorio_FatFS_open(mp_obj_t self, mp_obj_t path,
|
|||||||
f->fp = fp;
|
f->fp = fp;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_FatFS_open_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_fatfs_open_obj,
|
||||||
mod_trezorio_FatFS_open);
|
mod_trezorio_fatfs_open);
|
||||||
|
|
||||||
/// def listdir(self, path: str) -> FatFSDir:
|
/// def listdir(path: str) -> FatFSDir:
|
||||||
/// """
|
/// """
|
||||||
/// List a directory (return generator)
|
/// List a directory (return generator)
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_listdir(mp_obj_t self, mp_obj_t path) {
|
STATIC mp_obj_t mod_trezorio_fatfs_listdir(mp_obj_t path) {
|
||||||
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _path;
|
mp_buffer_info_t _path;
|
||||||
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
||||||
DIR dp;
|
DIR dp;
|
||||||
@ -396,19 +390,20 @@ STATIC mp_obj_t mod_trezorio_FatFS_listdir(mp_obj_t self, mp_obj_t path) {
|
|||||||
d->dp = dp;
|
d->dp = dp;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FatFS_listdir_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_fatfs_listdir_obj,
|
||||||
mod_trezorio_FatFS_listdir);
|
mod_trezorio_fatfs_listdir);
|
||||||
|
|
||||||
/// def mkdir(self, path: str, exist_ok: bool=False) -> None:
|
/// def mkdir(path: str, exist_ok: bool=False) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Create a sub directory
|
/// Create a sub directory
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_mkdir(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_trezorio_fatfs_mkdir(size_t n_args, const mp_obj_t *args) {
|
||||||
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t path;
|
mp_buffer_info_t path;
|
||||||
mp_get_buffer_raise(args[1], &path, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[0], &path, MP_BUFFER_READ);
|
||||||
FRESULT res = f_mkdir(path.buf);
|
FRESULT res = f_mkdir(path.buf);
|
||||||
// directory exists and exist_ok is True, return without failure
|
// directory exists and exist_ok is True, return without failure
|
||||||
if (res == FR_EXIST && n_args > 2 && args[2] == mp_const_true) {
|
if (res == FR_EXIST && n_args > 1 && args[1] == mp_const_true) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
@ -416,14 +411,15 @@ STATIC mp_obj_t mod_trezorio_FatFS_mkdir(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FatFS_mkdir_obj, 2, 3,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_fatfs_mkdir_obj, 1, 2,
|
||||||
mod_trezorio_FatFS_mkdir);
|
mod_trezorio_fatfs_mkdir);
|
||||||
|
|
||||||
/// def unlink(self, path: str) -> None:
|
/// def unlink(path: str) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Delete an existing file or directory
|
/// Delete an existing file or directory
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_unlink(mp_obj_t self, mp_obj_t path) {
|
STATIC mp_obj_t mod_trezorio_fatfs_unlink(mp_obj_t path) {
|
||||||
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _path;
|
mp_buffer_info_t _path;
|
||||||
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
||||||
FRESULT res = f_unlink(_path.buf);
|
FRESULT res = f_unlink(_path.buf);
|
||||||
@ -432,14 +428,15 @@ STATIC mp_obj_t mod_trezorio_FatFS_unlink(mp_obj_t self, mp_obj_t path) {
|
|||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FatFS_unlink_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_fatfs_unlink_obj,
|
||||||
mod_trezorio_FatFS_unlink);
|
mod_trezorio_fatfs_unlink);
|
||||||
|
|
||||||
/// def stat(self, path: str) -> Tuple[int, str, str]:
|
/// def stat(path: str) -> Tuple[int, str, str]:
|
||||||
/// """
|
/// """
|
||||||
/// Get file status
|
/// Get file status
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_stat(mp_obj_t self, mp_obj_t path) {
|
STATIC mp_obj_t mod_trezorio_fatfs_stat(mp_obj_t path) {
|
||||||
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _path;
|
mp_buffer_info_t _path;
|
||||||
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
@ -449,15 +446,15 @@ STATIC mp_obj_t mod_trezorio_FatFS_stat(mp_obj_t self, mp_obj_t path) {
|
|||||||
}
|
}
|
||||||
return filinfo_to_tuple(&info);
|
return filinfo_to_tuple(&info);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FatFS_stat_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_fatfs_stat_obj,
|
||||||
mod_trezorio_FatFS_stat);
|
mod_trezorio_fatfs_stat);
|
||||||
|
|
||||||
/// def rename(self, oldpath: str, newpath: str) -> None:
|
/// def rename(oldpath: str, newpath: str) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Rename/Move a file or directory
|
/// Rename/Move a file or directory
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_rename(mp_obj_t self, mp_obj_t oldpath,
|
STATIC mp_obj_t mod_trezorio_fatfs_rename(mp_obj_t oldpath, mp_obj_t newpath) {
|
||||||
mp_obj_t newpath) {
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _oldpath, _newpath;
|
mp_buffer_info_t _oldpath, _newpath;
|
||||||
mp_get_buffer_raise(oldpath, &_oldpath, MP_BUFFER_READ);
|
mp_get_buffer_raise(oldpath, &_oldpath, MP_BUFFER_READ);
|
||||||
mp_get_buffer_raise(newpath, &_newpath, MP_BUFFER_READ);
|
mp_get_buffer_raise(newpath, &_newpath, MP_BUFFER_READ);
|
||||||
@ -467,44 +464,52 @@ STATIC mp_obj_t mod_trezorio_FatFS_rename(mp_obj_t self, mp_obj_t oldpath,
|
|||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_FatFS_rename_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_fatfs_rename_obj,
|
||||||
mod_trezorio_FatFS_rename);
|
mod_trezorio_fatfs_rename);
|
||||||
|
|
||||||
/// def mount(self) -> None:
|
/// def mount() -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Mount/Unmount a logical drive
|
/// Mount the SD card filesystem.
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_mount(mp_obj_t self) {
|
STATIC mp_obj_t mod_trezorio_fatfs_mount() {
|
||||||
mp_obj_FatFS_t *o = MP_OBJ_TO_PTR(self);
|
FRESULT res = f_mount(&fs_instance, "", 1);
|
||||||
FRESULT res = f_mount(&(o->fs), "", 1);
|
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_FatFS_mount_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_mount_obj,
|
||||||
mod_trezorio_FatFS_mount);
|
mod_trezorio_fatfs_mount);
|
||||||
|
|
||||||
/// def unmount(self) -> None:
|
/// def unmount() -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Unmount a logical drive
|
/// Unmount the SD card filesystem.
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_unmount(mp_obj_t self) {
|
STATIC mp_obj_t mod_trezorio_fatfs_unmount() {
|
||||||
// to unmount we have to call mount with the first parameter NULL
|
_fatfs_unmount_instance();
|
||||||
FRESULT res = f_mount(NULL, "", 0);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
|
||||||
}
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_FatFS_unmount_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_unmount_obj,
|
||||||
mod_trezorio_FatFS_unmount);
|
mod_trezorio_fatfs_unmount);
|
||||||
|
|
||||||
/// def mkfs(self) -> None:
|
/// def is_mounted() -> bool:
|
||||||
|
/// """
|
||||||
|
/// Check if the filesystem is mounted.
|
||||||
|
/// """
|
||||||
|
STATIC mp_obj_t mod_trezorio_fatfs_is_mounted() {
|
||||||
|
return mp_obj_new_bool(_fatfs_instance_is_mounted());
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj,
|
||||||
|
mod_trezorio_fatfs_is_mounted);
|
||||||
|
|
||||||
|
/// def mkfs() -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Create a FAT volume
|
/// Create a FAT volume on the SD card,
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_mkfs(mp_obj_t self) {
|
STATIC mp_obj_t mod_trezorio_fatfs_mkfs() {
|
||||||
|
if (_fatfs_instance_is_mounted()) {
|
||||||
|
mp_raise_OSError(MP_EBUSY);
|
||||||
|
}
|
||||||
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
|
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
|
||||||
uint8_t working_buf[FF_MAX_SS];
|
uint8_t working_buf[FF_MAX_SS];
|
||||||
FRESULT res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf));
|
FRESULT res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf));
|
||||||
@ -513,14 +518,18 @@ STATIC mp_obj_t mod_trezorio_FatFS_mkfs(mp_obj_t self) {
|
|||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_FatFS_mkfs_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_mkfs_obj,
|
||||||
mod_trezorio_FatFS_mkfs);
|
mod_trezorio_fatfs_mkfs);
|
||||||
|
|
||||||
/// def setlabel(self, label: str) -> None:
|
/// def setlabel(label: str) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Set volume label
|
/// Set volume label
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_FatFS_setlabel(mp_obj_t self, mp_obj_t label) {
|
STATIC mp_obj_t mod_trezorio_fatfs_setlabel(mp_obj_t label) {
|
||||||
|
/* setlabel is marked as only-mounted, because "mounting" in ff.c terms means
|
||||||
|
having parsed the FAT table, which is of course a prerequisite for setting
|
||||||
|
label. */
|
||||||
|
FATFS_ONLY_MOUNTED;
|
||||||
mp_buffer_info_t _label;
|
mp_buffer_info_t _label;
|
||||||
mp_get_buffer_raise(label, &_label, MP_BUFFER_READ);
|
mp_get_buffer_raise(label, &_label, MP_BUFFER_READ);
|
||||||
FRESULT res = f_setlabel(_label.buf);
|
FRESULT res = f_setlabel(_label.buf);
|
||||||
@ -529,28 +538,32 @@ STATIC mp_obj_t mod_trezorio_FatFS_setlabel(mp_obj_t self, mp_obj_t label) {
|
|||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FatFS_setlabel_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_fatfs_setlabel_obj,
|
||||||
mod_trezorio_FatFS_setlabel);
|
mod_trezorio_fatfs_setlabel);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t mod_trezorio_FatFS_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t mod_trezorio_fatfs_globals_table[] = {
|
||||||
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_FatFS_open_obj)},
|
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fatfs)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mod_trezorio_FatFS_listdir_obj)},
|
{MP_ROM_QSTR(MP_QSTR_FatFSFile), MP_ROM_PTR(&mod_trezorio_FatFSFile_type)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mod_trezorio_FatFS_mkdir_obj)},
|
{MP_ROM_QSTR(MP_QSTR_FatFSDir), MP_ROM_PTR(&mod_trezorio_FatFSDir_type)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mod_trezorio_FatFS_unlink_obj)},
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mod_trezorio_FatFS_rename_obj)},
|
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_fatfs_open_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_trezorio_FatFS_stat_obj)},
|
{MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mod_trezorio_fatfs_listdir_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mod_trezorio_FatFS_mount_obj)},
|
{MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mod_trezorio_fatfs_mkdir_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_unmount), MP_ROM_PTR(&mod_trezorio_FatFS_unmount_obj)},
|
{MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mod_trezorio_fatfs_unlink_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&mod_trezorio_FatFS_mkfs_obj)},
|
{MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mod_trezorio_fatfs_rename_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_trezorio_fatfs_stat_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mod_trezorio_fatfs_mount_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_unmount), MP_ROM_PTR(&mod_trezorio_fatfs_unmount_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_is_mounted),
|
||||||
|
MP_ROM_PTR(&mod_trezorio_fatfs_is_mounted_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&mod_trezorio_fatfs_mkfs_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_setlabel),
|
{MP_ROM_QSTR(MP_QSTR_setlabel),
|
||||||
MP_ROM_PTR(&mod_trezorio_FatFS_setlabel_obj)},
|
MP_ROM_PTR(&mod_trezorio_fatfs_setlabel_obj)},
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_FatFS_locals_dict,
|
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_fatfs_globals,
|
||||||
mod_trezorio_FatFS_locals_dict_table);
|
mod_trezorio_fatfs_globals_table);
|
||||||
|
|
||||||
STATIC const mp_obj_type_t mod_trezorio_FatFS_type = {
|
STATIC const mp_obj_module_t mod_trezorio_fatfs_module = {
|
||||||
{&mp_type_type},
|
.base = {&mp_type_module},
|
||||||
.name = MP_QSTR_FatFS,
|
.globals = (mp_obj_dict_t *)&mod_trezorio_fatfs_globals,
|
||||||
.make_new = mod_trezorio_FatFS_make_new,
|
|
||||||
.locals_dict = (void *)&mod_trezorio_FatFS_locals_dict,
|
|
||||||
};
|
};
|
||||||
|
@ -56,6 +56,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_sdcard_power_on_obj,
|
|||||||
/// Power off the SD card interface.
|
/// Power off the SD card interface.
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_sdcard_power_off() {
|
STATIC mp_obj_t mod_trezorio_sdcard_power_off() {
|
||||||
|
/* XXX should this call happen inside sdcard_power_off()? */
|
||||||
|
_fatfs_unmount_instance();
|
||||||
sdcard_power_off();
|
sdcard_power_off();
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
@ -111,6 +113,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_sdcard_write_obj,
|
|||||||
mod_trezorio_sdcard_write);
|
mod_trezorio_sdcard_write);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t mod_trezorio_sdcard_globals_table[] = {
|
STATIC const mp_rom_map_elem_t mod_trezorio_sdcard_globals_table[] = {
|
||||||
|
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcard)},
|
||||||
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_is_present),
|
{MP_ROM_QSTR(MP_QSTR_is_present),
|
||||||
MP_ROM_PTR(&mod_trezorio_sdcard_is_present_obj)},
|
MP_ROM_PTR(&mod_trezorio_sdcard_is_present_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_power_on),
|
{MP_ROM_QSTR(MP_QSTR_power_on),
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = {
|
STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = {
|
||||||
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorio)},
|
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorio)},
|
||||||
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_FatFS), MP_ROM_PTR(&mod_trezorio_FatFS_type)},
|
{MP_ROM_QSTR(MP_QSTR_fatfs), MP_ROM_PTR(&mod_trezorio_fatfs_module)},
|
||||||
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type)},
|
{MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type)},
|
||||||
|
|
||||||
|
@ -1,131 +1,6 @@
|
|||||||
from typing import *
|
from typing import *
|
||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorio/modtrezorio-fatfs.h
|
|
||||||
class FatFSFile:
|
|
||||||
"""
|
|
||||||
Class encapsulating file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __enter__(self) -> FatFSFile:
|
|
||||||
"""
|
|
||||||
Return an open file object
|
|
||||||
"""
|
|
||||||
from types import TracebackType
|
|
||||||
|
|
||||||
def __exit__(
|
|
||||||
self, type: Optional[Type[BaseException]],
|
|
||||||
value: Optional[BaseException],
|
|
||||||
traceback: Optional[TracebackType],
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
Close an open file object
|
|
||||||
"""
|
|
||||||
|
|
||||||
def close(self) -> None:
|
|
||||||
"""
|
|
||||||
Close an open file object
|
|
||||||
"""
|
|
||||||
|
|
||||||
def read(self, data: bytearray) -> int:
|
|
||||||
"""
|
|
||||||
Read data from the file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def write(self, data: Union[bytes, bytearray]) -> int:
|
|
||||||
"""
|
|
||||||
Write data to the file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def seek(self, offset: int) -> None:
|
|
||||||
"""
|
|
||||||
Move file pointer of the file object
|
|
||||||
"""
|
|
||||||
|
|
||||||
def truncate(self) -> None:
|
|
||||||
"""
|
|
||||||
Truncate the file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def sync(self) -> None:
|
|
||||||
"""
|
|
||||||
Flush cached data of the writing file
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorio/modtrezorio-fatfs.h
|
|
||||||
class FatFSDir(Iterator[Tuple[int, str, str]]):
|
|
||||||
"""
|
|
||||||
Class encapsulating directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __next__(self) -> Tuple[int, str, str]:
|
|
||||||
"""
|
|
||||||
Read an entry in the directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorio/modtrezorio-fatfs.h
|
|
||||||
class FatFS:
|
|
||||||
"""
|
|
||||||
Class encapsulating FAT filesystem
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
def open(self, path: str, flags: str) -> FatFSFile:
|
|
||||||
"""
|
|
||||||
Open or create a file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def listdir(self, path: str) -> FatFSDir:
|
|
||||||
"""
|
|
||||||
List a directory (return generator)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def mkdir(self, path: str, exist_ok: bool=False) -> None:
|
|
||||||
"""
|
|
||||||
Create a sub directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
def unlink(self, path: str) -> None:
|
|
||||||
"""
|
|
||||||
Delete an existing file or directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
def stat(self, path: str) -> Tuple[int, str, str]:
|
|
||||||
"""
|
|
||||||
Get file status
|
|
||||||
"""
|
|
||||||
|
|
||||||
def rename(self, oldpath: str, newpath: str) -> None:
|
|
||||||
"""
|
|
||||||
Rename/Move a file or directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
def mount(self) -> None:
|
|
||||||
"""
|
|
||||||
Mount/Unmount a logical drive
|
|
||||||
"""
|
|
||||||
|
|
||||||
def unmount(self) -> None:
|
|
||||||
"""
|
|
||||||
Unmount a logical drive
|
|
||||||
"""
|
|
||||||
|
|
||||||
def mkfs(self) -> None:
|
|
||||||
"""
|
|
||||||
Create a FAT volume
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setlabel(self, label: str) -> None:
|
|
||||||
"""
|
|
||||||
Set volume label
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorio/modtrezorio-flash.h
|
# extmod/modtrezorio/modtrezorio-flash.h
|
||||||
class FlashOTP:
|
class FlashOTP:
|
||||||
"""
|
"""
|
||||||
|
142
core/mocks/generated/trezorio/fatfs.pyi
Normal file
142
core/mocks/generated/trezorio/fatfs.pyi
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
from typing import *
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
class FatFSFile:
|
||||||
|
"""
|
||||||
|
Class encapsulating file
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __enter__(self) -> FatFSFile:
|
||||||
|
"""
|
||||||
|
Return an open file object
|
||||||
|
"""
|
||||||
|
from types import TracebackType
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self, type: Optional[Type[BaseException]],
|
||||||
|
value: Optional[BaseException],
|
||||||
|
traceback: Optional[TracebackType],
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Close an open file object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""
|
||||||
|
Close an open file object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def read(self, data: bytearray) -> int:
|
||||||
|
"""
|
||||||
|
Read data from the file
|
||||||
|
"""
|
||||||
|
|
||||||
|
def write(self, data: Union[bytes, bytearray]) -> int:
|
||||||
|
"""
|
||||||
|
Write data to the file
|
||||||
|
"""
|
||||||
|
|
||||||
|
def seek(self, offset: int) -> None:
|
||||||
|
"""
|
||||||
|
Move file pointer of the file object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def truncate(self) -> None:
|
||||||
|
"""
|
||||||
|
Truncate the file
|
||||||
|
"""
|
||||||
|
|
||||||
|
def sync(self) -> None:
|
||||||
|
"""
|
||||||
|
Flush cached data of the writing file
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
class FatFSDir(Iterator[Tuple[int, str, str]]):
|
||||||
|
"""
|
||||||
|
Class encapsulating directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __next__(self) -> Tuple[int, str, str]:
|
||||||
|
"""
|
||||||
|
Read an entry in the directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def open(path: str, flags: str) -> FatFSFile:
|
||||||
|
"""
|
||||||
|
Open or create a file
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def listdir(path: str) -> FatFSDir:
|
||||||
|
"""
|
||||||
|
List a directory (return generator)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def mkdir(path: str, exist_ok: bool=False) -> None:
|
||||||
|
"""
|
||||||
|
Create a sub directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def unlink(path: str) -> None:
|
||||||
|
"""
|
||||||
|
Delete an existing file or directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def stat(path: str) -> Tuple[int, str, str]:
|
||||||
|
"""
|
||||||
|
Get file status
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def rename(oldpath: str, newpath: str) -> None:
|
||||||
|
"""
|
||||||
|
Rename/Move a file or directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def mount() -> None:
|
||||||
|
"""
|
||||||
|
Mount the SD card filesystem.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def unmount() -> None:
|
||||||
|
"""
|
||||||
|
Unmount the SD card filesystem.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def is_mounted() -> bool:
|
||||||
|
"""
|
||||||
|
Check if the filesystem is mounted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def mkfs() -> None:
|
||||||
|
"""
|
||||||
|
Create a FAT volume on the SD card,
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
|
def setlabel(label: str) -> None:
|
||||||
|
"""
|
||||||
|
Set volume label
|
||||||
|
"""
|
@ -1,6 +1,6 @@
|
|||||||
import storage.sd_salt
|
import storage.sd_salt
|
||||||
from storage.sd_salt import SD_CARD_HOT_SWAPPABLE
|
from storage.sd_salt import SD_CARD_HOT_SWAPPABLE
|
||||||
from trezor import sdcard, ui, wire
|
from trezor import fatfs, sdcard, ui, wire
|
||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
|
|
||||||
from apps.common.confirm import confirm, hold_to_confirm
|
from apps.common.confirm import confirm, hold_to_confirm
|
||||||
@ -91,8 +91,8 @@ async def ensure_sdcard(
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mount()
|
fatfs.mount()
|
||||||
# Mount succeeded, filesystem is OK
|
# Mount succeeded, filesystem is OK
|
||||||
return
|
return
|
||||||
except OSError:
|
except OSError:
|
||||||
@ -103,13 +103,18 @@ async def ensure_sdcard(
|
|||||||
raise SdCardUnavailable("SD card not formatted.")
|
raise SdCardUnavailable("SD card not formatted.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mkfs()
|
fatfs.mkfs()
|
||||||
# mkfs succeeded. Re-run loop to retry mounting.
|
fatfs.mount()
|
||||||
continue
|
fatfs.setlabel("TREZOR")
|
||||||
|
# mkfs and mount succeeded
|
||||||
|
return
|
||||||
except OSError:
|
except OSError:
|
||||||
if not await sd_problem_dialog(ctx):
|
pass
|
||||||
raise SdCardUnavailable("Problem formatting SD card.")
|
|
||||||
|
# allow retry if we get as far as here
|
||||||
|
if not await sd_problem_dialog(ctx):
|
||||||
|
raise SdCardUnavailable("Problem formatting SD card.")
|
||||||
|
|
||||||
|
|
||||||
async def request_sd_salt(
|
async def request_sd_salt(
|
||||||
|
@ -145,8 +145,7 @@ if __debug__:
|
|||||||
try:
|
try:
|
||||||
io.sdcard.power_on()
|
io.sdcard.power_on()
|
||||||
if msg.format:
|
if msg.format:
|
||||||
fs = io.FatFS()
|
io.fatfs.mkfs()
|
||||||
fs.mkfs()
|
|
||||||
else:
|
else:
|
||||||
# trash first 1 MB of data to destroy the FAT filesystem
|
# trash first 1 MB of data to destroy the FAT filesystem
|
||||||
assert io.sdcard.capacity() >= 1024 * 1024
|
assert io.sdcard.capacity() >= 1024 * 1024
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
|
|
||||||
import storage.device
|
import storage.device
|
||||||
|
from trezor import fatfs
|
||||||
from trezor.crypto import hmac
|
from trezor.crypto import hmac
|
||||||
from trezor.crypto.hashlib import sha256
|
from trezor.crypto.hashlib import sha256
|
||||||
from trezor.sdcard import get_filesystem
|
from trezor.sdcard import with_filesystem
|
||||||
from trezor.utils import consteq
|
from trezor.utils import consteq
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from trezor import io
|
|
||||||
from typing import Optional, TypeVar, Callable
|
from typing import Optional, TypeVar, Callable
|
||||||
|
|
||||||
T = TypeVar("T", bound=Callable)
|
T = TypeVar("T", bound=Callable)
|
||||||
@ -38,10 +38,11 @@ def _get_salt_path(new: bool = False) -> str:
|
|||||||
return "{}/salt{}".format(_get_device_dir(), ".new" if new else "")
|
return "{}/salt{}".format(_get_device_dir(), ".new" if new else "")
|
||||||
|
|
||||||
|
|
||||||
def _load_salt(fs: io.FatFS, auth_key: bytes, path: str) -> Optional[bytearray]:
|
@with_filesystem
|
||||||
|
def _load_salt(auth_key: bytes, path: str) -> Optional[bytearray]:
|
||||||
# Load the salt file if it exists.
|
# Load the salt file if it exists.
|
||||||
try:
|
try:
|
||||||
with fs.open(path, "r") as f:
|
with fatfs.open(path, "r") as f:
|
||||||
salt = bytearray(SD_SALT_LEN_BYTES)
|
salt = bytearray(SD_SALT_LEN_BYTES)
|
||||||
stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES)
|
stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES)
|
||||||
f.read(salt)
|
f.read(salt)
|
||||||
@ -57,6 +58,7 @@ def _load_salt(fs: io.FatFS, auth_key: bytes, path: str) -> Optional[bytearray]:
|
|||||||
return salt
|
return salt
|
||||||
|
|
||||||
|
|
||||||
|
@with_filesystem
|
||||||
def load_sd_salt() -> Optional[bytearray]:
|
def load_sd_salt() -> Optional[bytearray]:
|
||||||
salt_auth_key = storage.device.get_sd_salt_auth_key()
|
salt_auth_key = storage.device.get_sd_salt_auth_key()
|
||||||
if salt_auth_key is None:
|
if salt_auth_key is None:
|
||||||
@ -65,55 +67,54 @@ def load_sd_salt() -> Optional[bytearray]:
|
|||||||
salt_path = _get_salt_path()
|
salt_path = _get_salt_path()
|
||||||
new_salt_path = _get_salt_path(new=True)
|
new_salt_path = _get_salt_path(new=True)
|
||||||
|
|
||||||
with get_filesystem() as fs:
|
salt = _load_salt(salt_auth_key, salt_path)
|
||||||
salt = _load_salt(fs, salt_auth_key, salt_path)
|
if salt is not None:
|
||||||
if salt is not None:
|
|
||||||
return salt
|
|
||||||
|
|
||||||
# Check if there is a new salt.
|
|
||||||
salt = _load_salt(fs, salt_auth_key, new_salt_path)
|
|
||||||
if salt is None:
|
|
||||||
# No valid salt file on this SD card.
|
|
||||||
raise WrongSdCard
|
|
||||||
|
|
||||||
# Normal salt file does not exist, but new salt file exists. That means that
|
|
||||||
# SD salt regeneration was interrupted earlier. Bring into consistent state.
|
|
||||||
# TODO Possibly overwrite salt file with random data.
|
|
||||||
try:
|
|
||||||
fs.unlink(salt_path)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# fs.rename can fail with a write error, which falls through as an OSError.
|
|
||||||
# This should be handled in calling code, by allowing the user to retry.
|
|
||||||
fs.rename(new_salt_path, salt_path)
|
|
||||||
return salt
|
return salt
|
||||||
|
|
||||||
|
# Check if there is a new salt.
|
||||||
|
salt = _load_salt(salt_auth_key, new_salt_path)
|
||||||
|
if salt is None:
|
||||||
|
# No valid salt file on this SD card.
|
||||||
|
raise WrongSdCard
|
||||||
|
|
||||||
|
# Normal salt file does not exist, but new salt file exists. That means that
|
||||||
|
# SD salt regeneration was interrupted earlier. Bring into consistent state.
|
||||||
|
# TODO Possibly overwrite salt file with random data.
|
||||||
|
try:
|
||||||
|
fatfs.unlink(salt_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# fatfs.rename can fail with a write error, which falls through as an OSError.
|
||||||
|
# This should be handled in calling code, by allowing the user to retry.
|
||||||
|
fatfs.rename(new_salt_path, salt_path)
|
||||||
|
return salt
|
||||||
|
|
||||||
|
|
||||||
|
@with_filesystem
|
||||||
def set_sd_salt(salt: bytes, salt_tag: bytes, stage: bool = False) -> None:
|
def set_sd_salt(salt: bytes, salt_tag: bytes, stage: bool = False) -> None:
|
||||||
salt_path = _get_salt_path(stage)
|
salt_path = _get_salt_path(stage)
|
||||||
with get_filesystem() as fs:
|
fatfs.mkdir("/trezor", True)
|
||||||
fs.mkdir("/trezor", True)
|
fatfs.mkdir(_get_device_dir(), True)
|
||||||
fs.mkdir(_get_device_dir(), True)
|
with fatfs.open(salt_path, "w") as f:
|
||||||
with fs.open(salt_path, "w") as f:
|
f.write(salt)
|
||||||
f.write(salt)
|
f.write(salt_tag)
|
||||||
f.write(salt_tag)
|
|
||||||
|
|
||||||
|
|
||||||
|
@with_filesystem
|
||||||
def commit_sd_salt() -> None:
|
def commit_sd_salt() -> None:
|
||||||
salt_path = _get_salt_path(new=False)
|
salt_path = _get_salt_path(new=False)
|
||||||
new_salt_path = _get_salt_path(new=True)
|
new_salt_path = _get_salt_path(new=True)
|
||||||
|
|
||||||
with get_filesystem() as fs:
|
try:
|
||||||
try:
|
fatfs.unlink(salt_path)
|
||||||
fs.unlink(salt_path)
|
except OSError:
|
||||||
except OSError:
|
pass
|
||||||
pass
|
fatfs.rename(new_salt_path, salt_path)
|
||||||
fs.rename(new_salt_path, salt_path)
|
|
||||||
|
|
||||||
|
|
||||||
|
@with_filesystem
|
||||||
def remove_sd_salt() -> None:
|
def remove_sd_salt() -> None:
|
||||||
salt_path = _get_salt_path()
|
salt_path = _get_salt_path()
|
||||||
with get_filesystem() as fs:
|
# TODO Possibly overwrite salt file with random data.
|
||||||
# TODO Possibly overwrite salt file with random data.
|
fatfs.unlink(salt_path)
|
||||||
fs.unlink(salt_path)
|
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
import trezorconfig as config # noqa: F401
|
import trezorconfig as config # noqa: F401
|
||||||
import trezorio as io # noqa: F401
|
import trezorio as io # noqa: F401
|
||||||
|
|
||||||
|
fatfs = io.fatfs
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
from trezorio import FatFS, sdcard
|
from trezorio import fatfs, sdcard
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Any, Optional
|
from typing import Any, Callable, Optional, TypeVar
|
||||||
|
|
||||||
|
T = TypeVar("T", bound=Callable)
|
||||||
|
|
||||||
|
|
||||||
class FilesystemWrapper:
|
class FilesystemWrapper:
|
||||||
_INSTANCE = None # type: Optional[FilesystemWrapper]
|
_INSTANCE = None # type: Optional[FilesystemWrapper]
|
||||||
|
|
||||||
def __init__(self, mounted: bool) -> None:
|
def __init__(self, mounted: bool) -> None:
|
||||||
self.fs = FatFS()
|
|
||||||
self.mounted = mounted
|
self.mounted = mounted
|
||||||
self.counter = 0
|
self.counter = 0
|
||||||
|
|
||||||
@ -21,20 +22,18 @@ class FilesystemWrapper:
|
|||||||
return cls._INSTANCE
|
return cls._INSTANCE
|
||||||
|
|
||||||
def _deinit_instance(self) -> None:
|
def _deinit_instance(self) -> None:
|
||||||
if self.mounted:
|
fatfs.unmount()
|
||||||
self.fs.unmount()
|
|
||||||
sdcard.power_off()
|
sdcard.power_off()
|
||||||
FilesystemWrapper._INSTANCE = None
|
FilesystemWrapper._INSTANCE = None
|
||||||
|
|
||||||
def __enter__(self) -> "FatFS":
|
def __enter__(self) -> None:
|
||||||
try:
|
try:
|
||||||
if self.counter <= 0:
|
if self.counter <= 0:
|
||||||
self.counter = 0
|
self.counter = 0
|
||||||
sdcard.power_on()
|
sdcard.power_on()
|
||||||
if self.mounted:
|
if self.mounted:
|
||||||
self.fs.mount()
|
fatfs.mount()
|
||||||
self.counter += 1
|
self.counter += 1
|
||||||
return self.fs
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self._deinit_instance()
|
self._deinit_instance()
|
||||||
raise
|
raise
|
||||||
@ -46,8 +45,17 @@ class FilesystemWrapper:
|
|||||||
self._deinit_instance()
|
self._deinit_instance()
|
||||||
|
|
||||||
|
|
||||||
def get_filesystem(mounted: bool = True) -> FilesystemWrapper:
|
def filesystem(mounted: bool = True) -> FilesystemWrapper:
|
||||||
return FilesystemWrapper.get_instance(mounted=mounted)
|
return FilesystemWrapper.get_instance(mounted=mounted)
|
||||||
|
|
||||||
|
|
||||||
|
def with_filesystem(func: T) -> T:
|
||||||
|
def wrapped_func(*args, **kwargs) -> Any: # type: ignore
|
||||||
|
with filesystem():
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapped_func # type: ignore
|
||||||
|
|
||||||
|
|
||||||
is_present = sdcard.is_present
|
is_present = sdcard.is_present
|
||||||
|
capacity = sdcard.capacity
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
from common import *
|
from common import *
|
||||||
|
|
||||||
from trezor import io
|
from trezorio import sdcard, fatfs
|
||||||
|
|
||||||
|
|
||||||
class TestTrezorIoFatfs(unittest.TestCase):
|
class TestTrezorIoFatfs(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
io.sdcard.power_on()
|
sdcard.power_on()
|
||||||
self.fs = io.FatFS()
|
fatfs.mkfs()
|
||||||
self.fs.mkfs()
|
fatfs.mount()
|
||||||
self.fs.mount()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.fs.unmount()
|
fatfs.unmount()
|
||||||
io.sdcard.power_off()
|
sdcard.power_off()
|
||||||
|
|
||||||
def _filename(self, suffix=""):
|
def _filename(self, suffix=""):
|
||||||
return "FILE%s.TXT" % suffix
|
return "FILE%s.TXT" % suffix
|
||||||
@ -26,78 +24,80 @@ class TestTrezorIoFatfs(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def test_mkdir(self):
|
def test_mkdir(self):
|
||||||
self.fs.mkdir("/%s" % self._dirname())
|
fatfs.mkdir("/%s" % self._dirname())
|
||||||
s = self.fs.stat("/%s" % self._dirname())
|
s = fatfs.stat("/%s" % self._dirname())
|
||||||
self.assertEqual(s, (0, "---d-", self._dirname()))
|
self.assertEqual(s, (0, "---d-", self._dirname()))
|
||||||
|
|
||||||
def test_listdir(self):
|
def test_listdir(self):
|
||||||
self.fs.mkdir("/%s" % self._dirname())
|
fatfs.mkdir("/%s" % self._dirname())
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test"))
|
f.write(bytearray(b"test"))
|
||||||
with self.fs.open("/%s/%s" % (self._dirname(), self._filename("2")), "w") as f:
|
with fatfs.open("/%s/%s" % (self._dirname(), self._filename("2")), "w") as f:
|
||||||
f.write(bytearray(b"testtest"))
|
f.write(bytearray(b"testtest"))
|
||||||
l = [e for e in self.fs.listdir("/")]
|
l = [e for e in fatfs.listdir("/")]
|
||||||
self.assertEqual(l, [(0, "---d-", self._dirname()), (4, "----a", self._filename())])
|
self.assertEqual(
|
||||||
l = [e for e in self.fs.listdir("/%s" % self._dirname())]
|
l, [(0, "---d-", self._dirname()), (4, "----a", self._filename())]
|
||||||
|
)
|
||||||
|
l = [e for e in fatfs.listdir("/%s" % self._dirname())]
|
||||||
self.assertEqual(l, [(8, "----a", self._filename("2"))])
|
self.assertEqual(l, [(8, "----a", self._filename("2"))])
|
||||||
|
|
||||||
def test_unlink(self):
|
def test_unlink(self):
|
||||||
self.fs.mkdir("/%s" % self._dirname())
|
fatfs.mkdir("/%s" % self._dirname())
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test"))
|
f.write(bytearray(b"test"))
|
||||||
s = self.fs.stat("/%s" % self._dirname())
|
s = fatfs.stat("/%s" % self._dirname())
|
||||||
self.assertEqual(s, (0, "---d-", self._dirname()))
|
self.assertEqual(s, (0, "---d-", self._dirname()))
|
||||||
s = self.fs.stat("/%s" % self._filename())
|
s = fatfs.stat("/%s" % self._filename())
|
||||||
self.assertEqual(s, (4, "----a", self._filename()))
|
self.assertEqual(s, (4, "----a", self._filename()))
|
||||||
self.fs.unlink("/%s" % self._dirname())
|
fatfs.unlink("/%s" % self._dirname())
|
||||||
self.fs.unlink("/%s" % self._filename())
|
fatfs.unlink("/%s" % self._filename())
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
self.fs.stat("/%s" % self._dirname())
|
fatfs.stat("/%s" % self._dirname())
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
self.assertRaises(self.fs.stat("/%s" % self._filename()))
|
self.assertRaises(fatfs.stat("/%s" % self._filename()))
|
||||||
|
|
||||||
def test_rename(self):
|
def test_rename(self):
|
||||||
self.fs.mkdir("/%s" % self._dirname())
|
fatfs.mkdir("/%s" % self._dirname())
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test"))
|
f.write(bytearray(b"test"))
|
||||||
s = self.fs.stat("/%s" % self._dirname())
|
s = fatfs.stat("/%s" % self._dirname())
|
||||||
self.assertEqual(s, (0, "---d-", self._dirname()))
|
self.assertEqual(s, (0, "---d-", self._dirname()))
|
||||||
s = self.fs.stat("/%s" % self._filename())
|
s = fatfs.stat("/%s" % self._filename())
|
||||||
self.assertEqual(s, (4, "----a", self._filename()))
|
self.assertEqual(s, (4, "----a", self._filename()))
|
||||||
self.fs.rename("/%s" % self._dirname(), "/%s" % self._dirname("2"))
|
fatfs.rename("/%s" % self._dirname(), "/%s" % self._dirname("2"))
|
||||||
self.fs.rename("/%s" % self._filename(), "/%s" % self._filename("2"))
|
fatfs.rename("/%s" % self._filename(), "/%s" % self._filename("2"))
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
self.fs.stat("/%s" % self._dirname())
|
fatfs.stat("/%s" % self._dirname())
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
self.assertRaises(self.fs.stat("/%s" % self._filename()))
|
self.assertRaises(fatfs.stat("/%s" % self._filename()))
|
||||||
s = self.fs.stat("/%s" % self._dirname("2"))
|
s = fatfs.stat("/%s" % self._dirname("2"))
|
||||||
self.assertEqual(s, (0, "---d-", self._dirname("2")))
|
self.assertEqual(s, (0, "---d-", self._dirname("2")))
|
||||||
s = self.fs.stat("/%s" % self._filename("2"))
|
s = fatfs.stat("/%s" % self._filename("2"))
|
||||||
self.assertEqual(s, (4, "----a", self._filename("2")))
|
self.assertEqual(s, (4, "----a", self._filename("2")))
|
||||||
|
|
||||||
def test_open_rw(self):
|
def test_open_rw(self):
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test"))
|
f.write(bytearray(b"test"))
|
||||||
with self.fs.open("/%s" % self._filename(), "r") as f:
|
with fatfs.open("/%s" % self._filename(), "r") as f:
|
||||||
b = bytearray(100)
|
b = bytearray(100)
|
||||||
r = f.read(b)
|
r = f.read(b)
|
||||||
self.assertEqual(r, 4)
|
self.assertEqual(r, 4)
|
||||||
self.assertEqual(bytes(b[:4]), b"test")
|
self.assertEqual(bytes(b[:4]), b"test")
|
||||||
|
|
||||||
def test_open_a(self):
|
def test_open_a(self):
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test" * 200))
|
f.write(bytearray(b"test" * 200))
|
||||||
with self.fs.open("/%s" % self._filename(), "a") as f:
|
with fatfs.open("/%s" % self._filename(), "a") as f:
|
||||||
f.seek(800)
|
f.seek(800)
|
||||||
f.write(bytearray(b"TEST" * 200))
|
f.write(bytearray(b"TEST" * 200))
|
||||||
with self.fs.open("/%s" % self._filename(), "r") as f:
|
with fatfs.open("/%s" % self._filename(), "r") as f:
|
||||||
b = bytearray(2000)
|
b = bytearray(2000)
|
||||||
r = f.read(b)
|
r = f.read(b)
|
||||||
self.assertEqual(r, 1600)
|
self.assertEqual(r, 1600)
|
||||||
self.assertEqual(bytes(b[:1600]), b"test" * 200 + b"TEST" * 200)
|
self.assertEqual(bytes(b[:1600]), b"test" * 200 + b"TEST" * 200)
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek(self):
|
||||||
with self.fs.open("/%s" % self._filename(), "w+") as f:
|
with fatfs.open("/%s" % self._filename(), "w+") as f:
|
||||||
f.write(bytearray(b"test" * 10))
|
f.write(bytearray(b"test" * 10))
|
||||||
f.seek(2)
|
f.seek(2)
|
||||||
b = bytearray(8)
|
b = bytearray(8)
|
||||||
@ -106,19 +106,18 @@ class TestTrezorIoFatfs(unittest.TestCase):
|
|||||||
self.assertEqual(bytes(b[:8]), b"sttestte")
|
self.assertEqual(bytes(b[:8]), b"sttestte")
|
||||||
|
|
||||||
def test_truncate(self):
|
def test_truncate(self):
|
||||||
with self.fs.open("/%s" % self._filename(), "w") as f:
|
with fatfs.open("/%s" % self._filename(), "w") as f:
|
||||||
f.write(bytearray(b"test" * 100))
|
f.write(bytearray(b"test" * 100))
|
||||||
s = self.fs.stat("/%s" % self._filename())
|
s = fatfs.stat("/%s" % self._filename())
|
||||||
self.assertEqual(s, (400, "----a", self._filename()))
|
self.assertEqual(s, (400, "----a", self._filename()))
|
||||||
with self.fs.open("/%s" % self._filename(), "a") as f:
|
with fatfs.open("/%s" % self._filename(), "a") as f:
|
||||||
f.seek(111)
|
f.seek(111)
|
||||||
f.truncate()
|
f.truncate()
|
||||||
s = self.fs.stat("/%s" % self._filename())
|
s = fatfs.stat("/%s" % self._filename())
|
||||||
self.assertEqual(s, (111, "----a", self._filename()))
|
self.assertEqual(s, (111, "----a", self._filename()))
|
||||||
|
|
||||||
|
|
||||||
class TestTrezorIoFatfsLfn(TestTrezorIoFatfs):
|
class TestTrezorIoFatfsLfn(TestTrezorIoFatfs):
|
||||||
|
|
||||||
def _filename(self, suffix=""):
|
def _filename(self, suffix=""):
|
||||||
return "reallylongfilename%s.textfile" % suffix
|
return "reallylongfilename%s.textfile" % suffix
|
||||||
|
|
||||||
@ -126,5 +125,116 @@ class TestTrezorIoFatfsLfn(TestTrezorIoFatfs):
|
|||||||
return "reallylongdirname%s" % suffix
|
return "reallylongdirname%s" % suffix
|
||||||
|
|
||||||
|
|
||||||
|
class TestTrezorIoFatfsMounting(unittest.TestCase):
|
||||||
|
MOUNTED_METHODS = [
|
||||||
|
("open", ("hello.txt", "w")),
|
||||||
|
("listdir", ("",)),
|
||||||
|
("mkdir", ("testdir",)),
|
||||||
|
("unlink", ("hello.txt",)),
|
||||||
|
("stat", ("testdir",)),
|
||||||
|
("rename", ("testdir", "newdir")),
|
||||||
|
("setlabel", ("label",)),
|
||||||
|
]
|
||||||
|
UNMOUNTED_METHODS = [
|
||||||
|
("mkfs", ()),
|
||||||
|
]
|
||||||
|
OTHER = {
|
||||||
|
"__name__",
|
||||||
|
"__class__",
|
||||||
|
"mount",
|
||||||
|
"unmount",
|
||||||
|
"is_mounted",
|
||||||
|
"FatFSFile",
|
||||||
|
"FatFSDir",
|
||||||
|
}
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
sdcard.power_on()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
sdcard.power_off()
|
||||||
|
|
||||||
|
def test_mount_unmount(self):
|
||||||
|
fatfs.mkfs()
|
||||||
|
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
fatfs.mount()
|
||||||
|
self.assertTrue(fatfs.is_mounted())
|
||||||
|
fatfs.mount()
|
||||||
|
self.assertTrue(fatfs.is_mounted())
|
||||||
|
fatfs.unmount()
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
|
def test_no_filesystem(self):
|
||||||
|
# trash FAT table
|
||||||
|
sdcard.write(0, bytes([0xFF] * sdcard.BLOCK_SIZE))
|
||||||
|
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
try:
|
||||||
|
fatfs.mount()
|
||||||
|
self.fail("should have raised")
|
||||||
|
except OSError as e:
|
||||||
|
self.assertEqual(e.args[0], 19) # ENODEV
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
|
def test_exhaustive(self):
|
||||||
|
all_symbols = (
|
||||||
|
set(name for name, call in (self.MOUNTED_METHODS + self.UNMOUNTED_METHODS))
|
||||||
|
| self.OTHER
|
||||||
|
)
|
||||||
|
self.assertEqual(set(dir(fatfs)), all_symbols)
|
||||||
|
|
||||||
|
def test_mounted(self):
|
||||||
|
fatfs.mkfs()
|
||||||
|
fatfs.mount()
|
||||||
|
self.assertTrue(fatfs.is_mounted())
|
||||||
|
|
||||||
|
for name, call in self.MOUNTED_METHODS:
|
||||||
|
function = getattr(fatfs, name)
|
||||||
|
function(*call)
|
||||||
|
|
||||||
|
for name, call in self.UNMOUNTED_METHODS:
|
||||||
|
function = getattr(fatfs, name)
|
||||||
|
try:
|
||||||
|
function(*call)
|
||||||
|
self.fail("should have raised")
|
||||||
|
except OSError as e:
|
||||||
|
self.assertEqual(e.args[0], 16) # EBUSY
|
||||||
|
|
||||||
|
def test_unmounted(self):
|
||||||
|
fatfs.unmount()
|
||||||
|
fatfs.mkfs()
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
|
for name, call in self.UNMOUNTED_METHODS:
|
||||||
|
function = getattr(fatfs, name)
|
||||||
|
function(*call)
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
|
for name, call in self.MOUNTED_METHODS:
|
||||||
|
function = getattr(fatfs, name)
|
||||||
|
try:
|
||||||
|
function(*call)
|
||||||
|
self.fail("should have raised")
|
||||||
|
except OSError as e:
|
||||||
|
self.assertEqual(e.args[0], 19) # ENODEV
|
||||||
|
|
||||||
|
|
||||||
|
class TestTrezorIoFatfsAndSdcard(unittest.TestCase):
|
||||||
|
def test_sd_power(self):
|
||||||
|
sdcard.power_off()
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
self.assertRaises(OSError, fatfs.mount)
|
||||||
|
|
||||||
|
sdcard.power_on()
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
fatfs.mkfs()
|
||||||
|
fatfs.mount()
|
||||||
|
self.assertTrue(fatfs.is_mounted())
|
||||||
|
|
||||||
|
sdcard.power_off()
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -1,75 +1,68 @@
|
|||||||
from common import *
|
from common import *
|
||||||
|
|
||||||
from trezor import io, sdcard
|
from trezor import io, fatfs, sdcard
|
||||||
|
|
||||||
|
|
||||||
class TestTrezorSdcard(unittest.TestCase):
|
class TestTrezorSdcard(unittest.TestCase):
|
||||||
def test_power(self):
|
def test_power(self):
|
||||||
# io.sdcard.capacity() will return 0 if the card is not powered,
|
# sdcard.capacity() will return 0 if the card is not powered,
|
||||||
# non-zero value otherwise
|
# non-zero value otherwise
|
||||||
self.assertEqual(io.sdcard.capacity(), 0)
|
self.assertEqual(sdcard.capacity(), 0)
|
||||||
with sdcard.get_filesystem(mounted=False):
|
with sdcard.filesystem(mounted=False):
|
||||||
self.assertTrue(io.sdcard.capacity() > 0)
|
self.assertTrue(sdcard.capacity() > 0)
|
||||||
self.assertEqual(io.sdcard.capacity(), 0)
|
self.assertEqual(sdcard.capacity(), 0)
|
||||||
|
|
||||||
def test_nomount(self):
|
def test_nomount(self):
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
with self.assertRaises(OSError):
|
self.assertFalse(fatfs.is_mounted())
|
||||||
fs.listdir("/")
|
|
||||||
|
|
||||||
def test_mount(self):
|
def test_mount(self):
|
||||||
# set up a filesystem first
|
# set up a filesystem first
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mkfs()
|
fatfs.mkfs()
|
||||||
|
|
||||||
with sdcard.get_filesystem() as fs:
|
with sdcard.filesystem():
|
||||||
# the following should succeed
|
self.assertTrue(fatfs.is_mounted())
|
||||||
fs.listdir("/")
|
|
||||||
|
|
||||||
# filesystem should not be available
|
self.assertFalse(fatfs.is_mounted())
|
||||||
with self.assertRaises(OSError):
|
|
||||||
fs.listdir("/")
|
|
||||||
|
|
||||||
def test_nesting(self):
|
def test_nesting(self):
|
||||||
# set up a filesystem first
|
# set up a filesystem first
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mkfs()
|
fatfs.mkfs()
|
||||||
|
|
||||||
self.assertEqual(io.sdcard.capacity(), 0)
|
self.assertEqual(sdcard.capacity(), 0)
|
||||||
with sdcard.get_filesystem() as fs_a:
|
with sdcard.filesystem():
|
||||||
self.assertTrue(io.sdcard.capacity() > 0)
|
self.assertTrue(sdcard.capacity() > 0)
|
||||||
with sdcard.get_filesystem() as fs_b:
|
self.assertTrue(fatfs.is_mounted())
|
||||||
self.assertTrue(io.sdcard.capacity() > 0)
|
with sdcard.filesystem():
|
||||||
self.assertIs(fs_a, fs_b)
|
self.assertTrue(sdcard.capacity() > 0)
|
||||||
fs_b.listdir("/")
|
self.assertTrue(fatfs.is_mounted())
|
||||||
self.assertTrue(io.sdcard.capacity() > 0)
|
|
||||||
# filesystem should still be mounted
|
|
||||||
fs_a.listdir("/")
|
|
||||||
|
|
||||||
self.assertEqual(io.sdcard.capacity(), 0)
|
self.assertTrue(sdcard.capacity() > 0)
|
||||||
# filesystem should not be available
|
self.assertTrue(fatfs.is_mounted())
|
||||||
with self.assertRaises(OSError):
|
|
||||||
fs_a.listdir("/")
|
self.assertEqual(sdcard.capacity(), 0)
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
def test_mount_nomount(self):
|
def test_mount_nomount(self):
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
with sdcard.get_filesystem(mounted=True):
|
with sdcard.filesystem(mounted=True):
|
||||||
with sdcard.get_filesystem(mounted=False):
|
with sdcard.filesystem(mounted=False):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
with sdcard.get_filesystem(mounted=False):
|
with sdcard.filesystem(mounted=False):
|
||||||
with sdcard.get_filesystem(mounted=True):
|
with sdcard.filesystem(mounted=True):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_failed_mount(self):
|
def test_failed_mount(self):
|
||||||
# set up a filesystem first
|
# set up a filesystem first
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mkfs()
|
fatfs.mkfs()
|
||||||
|
|
||||||
with sdcard.get_filesystem() as fs:
|
with sdcard.filesystem():
|
||||||
# the following should succeed
|
self.assertTrue(fatfs.is_mounted())
|
||||||
fs.listdir("/")
|
|
||||||
|
|
||||||
# trash filesystem
|
# trash filesystem
|
||||||
io.sdcard.power_on()
|
io.sdcard.power_on()
|
||||||
@ -78,17 +71,18 @@ class TestTrezorSdcard(unittest.TestCase):
|
|||||||
|
|
||||||
# mounting should now fail
|
# mounting should now fail
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
with sdcard.get_filesystem() as fs:
|
with sdcard.filesystem():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
self.assertFalse(fatfs.is_mounted())
|
||||||
|
|
||||||
# it should be possible to create an unmounted instance
|
# it should be possible to create an unmounted instance
|
||||||
with sdcard.get_filesystem(mounted=False) as fs:
|
with sdcard.filesystem(mounted=False):
|
||||||
fs.mkfs()
|
fatfs.mkfs()
|
||||||
|
|
||||||
# mounting should now succeed
|
# mounting should now succeed
|
||||||
with sdcard.get_filesystem() as fs:
|
with sdcard.filesystem():
|
||||||
fs.listdir("/")
|
self.assertTrue(fatfs.is_mounted())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
Reference in New Issue
Block a user