1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 23:48:12 +00:00

core/sdcard: modify exception handling in fatfs

expose ff.c constants, raise them as arguments to FatFSError

introduce NotMounted and NoFilesystem as subclasses of FatFSError with
the appropriate error code set
This commit is contained in:
matejcik 2020-03-05 12:24:26 +01:00 committed by matejcik
parent 8ee0026637
commit 3789a3372b
5 changed files with 162 additions and 82 deletions

View File

@ -29,15 +29,61 @@
/// package: trezorio.fatfs
// clang-format off
/// FR_OK: int # (0) Succeeded
/// FR_DISK_ERR: int # (1) A hard error occurred in the low level disk I/O layer
/// FR_INT_ERR: int # (2) Assertion failed
/// FR_NOT_READY: int # (3) The physical drive cannot work
/// FR_NO_FILE: int # (4) Could not find the file
/// FR_NO_PATH: int # (5) Could not find the path
/// FR_INVALID_NAME: int # (6) The path name format is invalid
/// FR_DENIED: int # (7) Access denied due to prohibited access or directory full
/// FR_EXIST: int # (8) Access denied due to prohibited access
/// FR_INVALID_OBJECT: int # (9) The file/directory object is invalid
/// FR_WRITE_PROTECTED: int # (10) The physical drive is write protected
/// FR_INVALID_DRIVE: int # (11) The logical drive number is invalid
/// FR_NOT_ENABLED: int # (12) The volume has no work area
/// FR_NO_FILESYSTEM: int # (13) There is no valid FAT volume
/// FR_MKFS_ABORTED: int # (14) The f_mkfs() aborted due to any problem
/// FR_TIMEOUT: int # (15) Could not get a grant to access the volume within defined period
/// FR_LOCKED: int # (16) The operation is rejected according to the file sharing policy
/// FR_NOT_ENOUGH_CORE: int # (17) LFN working buffer could not be allocated
/// FR_TOO_MANY_OPEN_FILES: int # (18) Number of open files > FF_FS_LOCK
/// FR_INVALID_PARAMETER: int # (19) Given parameter is invalid
#define FR_NO_SPACE 64
/// # nonstandard value:
/// FR_NO_SPACE: int # (64) No space left on device
// clang-format on
static FATFS fs_instance;
bool _fatfs_instance_is_mounted() { return fs_instance.fs_type != 0; }
void _fatfs_unmount_instance() { fs_instance.fs_type = 0; }
/// class FatFSError(OSError):
/// pass
MP_DEFINE_EXCEPTION(FatFSError, OSError)
/// class NotMounted(FatFSError):
/// pass
MP_DEFINE_EXCEPTION(NotMounted, FatFSError)
/// class NoFilesystem(FatFSError):
/// pass
MP_DEFINE_EXCEPTION(NoFilesystem, FatFSError)
// to avoid collisions with POSIX errno values, we add 0xFF to FR_* error codes
#define FATFS_ERROR_CODE(n) (n + 0xFF)
#define FATFS_ROM_INT(n) MP_ROM_INT(FATFS_ERROR_CODE(n))
#define FATFS_RAISE(exc_type, num) \
{ \
nlr_raise(mp_obj_new_exception_arg1( \
&mp_type_##exc_type, MP_OBJ_NEW_SMALL_INT(FATFS_ERROR_CODE(num)))); \
}
#define FATFS_ONLY_MOUNTED \
{ \
if (!_fatfs_instance_is_mounted()) { \
mp_raise_OSError(MP_ENODEV); \
FATFS_RAISE(NotMounted, FR_NOT_READY); \
} \
}
@ -84,30 +130,6 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) {
}
}
// this table converts from FRESULT to POSIX errno
const uint8_t fresult_to_errno_table[20] = {
[FR_OK] = 0,
[FR_DISK_ERR] = MP_EIO,
[FR_INT_ERR] = MP_EIO,
[FR_NOT_READY] = MP_EBUSY,
[FR_NO_FILE] = MP_ENOENT,
[FR_NO_PATH] = MP_ENOENT,
[FR_INVALID_NAME] = MP_EINVAL,
[FR_DENIED] = MP_EACCES,
[FR_EXIST] = MP_EEXIST,
[FR_INVALID_OBJECT] = MP_EINVAL,
[FR_WRITE_PROTECTED] = MP_EROFS,
[FR_INVALID_DRIVE] = MP_ENODEV,
[FR_NOT_ENABLED] = MP_ENODEV,
[FR_NO_FILESYSTEM] = MP_ENODEV,
[FR_MKFS_ABORTED] = MP_EIO,
[FR_TIMEOUT] = MP_EIO,
[FR_LOCKED] = MP_EIO,
[FR_NOT_ENOUGH_CORE] = MP_ENOMEM,
[FR_TOO_MANY_OPEN_FILES] = MP_EMFILE,
[FR_INVALID_PARAMETER] = MP_EINVAL,
};
STATIC mp_obj_t filinfo_to_tuple(const FILINFO *info) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
tuple->items[0] = mp_obj_new_int_from_uint(info->fsize);
@ -160,7 +182,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile___exit__(size_t n_args,
mp_obj_FatFSFile_t *o = MP_OBJ_TO_PTR(args[0]);
FRESULT res = f_close(&(o->fp));
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -176,7 +198,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_close(mp_obj_t self) {
mp_obj_FatFSFile_t *o = MP_OBJ_TO_PTR(self);
FRESULT res = f_close(&(o->fp));
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -194,7 +216,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_read(mp_obj_t self, mp_obj_t data) {
UINT read;
FRESULT res = f_read(&(o->fp), buf.buf, buf.len, &read);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_obj_new_int_from_uint(read);
}
@ -212,11 +234,11 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_write(mp_obj_t self, mp_obj_t data) {
UINT written;
FRESULT res = f_write(&(o->fp), buf.buf, buf.len, &written);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
if (written != buf.len) {
/* no space left on device or free clusters recorded in FSInfo fell to 0 */
mp_raise_OSError(MP_ENOSPC);
FATFS_RAISE(FatFSError, FR_NO_SPACE);
}
return mp_obj_new_int_from_uint(written);
}
@ -232,7 +254,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_seek(mp_obj_t self, mp_obj_t offset) {
FSIZE_t ofs = trezor_obj_get_uint(offset);
FRESULT res = f_lseek(&(o->fp), ofs);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -247,7 +269,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_truncate(mp_obj_t self) {
mp_obj_FatFSFile_t *o = MP_OBJ_TO_PTR(self);
FRESULT res = f_truncate(&(o->fp));
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -262,7 +284,7 @@ STATIC mp_obj_t mod_trezorio_FatFSFile_sync(mp_obj_t self) {
mp_obj_FatFSFile_t *o = MP_OBJ_TO_PTR(self);
FRESULT res = f_sync(&(o->fp));
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -309,7 +331,7 @@ STATIC mp_obj_t mod_trezorio_FatFSDir_iternext(mp_obj_t self) {
FRESULT res = f_readdir(&(o->dp), &info);
if (res != FR_OK) {
f_closedir(&(o->dp));
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
if (info.fname[0] == 0) { // stop on end of dir
f_closedir(&(o->dp));
@ -362,7 +384,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_open(mp_obj_t path, mp_obj_t flags) {
FIL fp;
FRESULT res = f_open(&fp, _path.buf, mode);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
mp_obj_FatFSFile_t *f = m_new_obj(mp_obj_FatFSFile_t);
f->base.type = &mod_trezorio_FatFSFile_type;
@ -383,7 +405,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_listdir(mp_obj_t path) {
DIR dp;
FRESULT res = f_opendir(&dp, _path.buf);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
mp_obj_FatFSDir_t *d = m_new_obj(mp_obj_FatFSDir_t);
d->base.type = &mod_trezorio_FatFSDir_type;
@ -407,7 +429,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_mkdir(size_t n_args, const mp_obj_t *args) {
return mp_const_none;
}
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -424,7 +446,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_unlink(mp_obj_t path) {
mp_get_buffer_raise(path, &_path, MP_BUFFER_READ);
FRESULT res = f_unlink(_path.buf);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -442,7 +464,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_stat(mp_obj_t path) {
FILINFO info;
FRESULT res = f_stat(_path.buf, &info);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return filinfo_to_tuple(&info);
}
@ -460,7 +482,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_rename(mp_obj_t oldpath, mp_obj_t newpath) {
mp_get_buffer_raise(newpath, &_newpath, MP_BUFFER_READ);
FRESULT res = f_rename(_oldpath.buf, _newpath.buf);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -474,7 +496,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_fatfs_rename_obj,
STATIC mp_obj_t mod_trezorio_fatfs_mount() {
FRESULT res = f_mount(&fs_instance, "", 1);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
if (res == FR_NO_FILESYSTEM) {
FATFS_RAISE(NoFilesystem, FR_NO_FILESYSTEM);
} else {
FATFS_RAISE(FatFSError, res);
}
}
return mp_const_none;
}
@ -508,13 +534,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj,
/// """
STATIC mp_obj_t mod_trezorio_fatfs_mkfs() {
if (_fatfs_instance_is_mounted()) {
mp_raise_OSError(MP_EBUSY);
FATFS_RAISE(FatFSError, FR_LOCKED);
}
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
uint8_t working_buf[FF_MAX_SS];
FRESULT res = f_mkfs("", &params, working_buf, sizeof(working_buf));
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -534,7 +560,7 @@ STATIC mp_obj_t mod_trezorio_fatfs_setlabel(mp_obj_t label) {
mp_get_buffer_raise(label, &_label, MP_BUFFER_READ);
FRESULT res = f_setlabel(_label.buf);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
@ -545,6 +571,9 @@ STATIC const mp_rom_map_elem_t mod_trezorio_fatfs_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fatfs)},
{MP_ROM_QSTR(MP_QSTR_FatFSFile), MP_ROM_PTR(&mod_trezorio_FatFSFile_type)},
{MP_ROM_QSTR(MP_QSTR_FatFSDir), MP_ROM_PTR(&mod_trezorio_FatFSDir_type)},
{MP_ROM_QSTR(MP_QSTR_FatFSError), MP_ROM_PTR(&mp_type_FatFSError)},
{MP_ROM_QSTR(MP_QSTR_NotMounted), MP_ROM_PTR(&mp_type_NotMounted)},
{MP_ROM_QSTR(MP_QSTR_NoFilesystem), MP_ROM_PTR(&mp_type_NoFilesystem)},
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_fatfs_open_obj)},
{MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mod_trezorio_fatfs_listdir_obj)},
@ -559,6 +588,32 @@ STATIC const mp_rom_map_elem_t mod_trezorio_fatfs_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&mod_trezorio_fatfs_mkfs_obj)},
{MP_ROM_QSTR(MP_QSTR_setlabel),
MP_ROM_PTR(&mod_trezorio_fatfs_setlabel_obj)},
{MP_ROM_QSTR(MP_QSTR_FR_OK), FATFS_ROM_INT(FR_OK)},
{MP_ROM_QSTR(MP_QSTR_FR_DISK_ERR), FATFS_ROM_INT(FR_DISK_ERR)},
{MP_ROM_QSTR(MP_QSTR_FR_INT_ERR), FATFS_ROM_INT(FR_INT_ERR)},
{MP_ROM_QSTR(MP_QSTR_FR_NOT_READY), FATFS_ROM_INT(FR_NOT_READY)},
{MP_ROM_QSTR(MP_QSTR_FR_NO_FILE), FATFS_ROM_INT(FR_NO_FILE)},
{MP_ROM_QSTR(MP_QSTR_FR_NO_PATH), FATFS_ROM_INT(FR_NO_PATH)},
{MP_ROM_QSTR(MP_QSTR_FR_INVALID_NAME), FATFS_ROM_INT(FR_INVALID_NAME)},
{MP_ROM_QSTR(MP_QSTR_FR_DENIED), FATFS_ROM_INT(FR_DENIED)},
{MP_ROM_QSTR(MP_QSTR_FR_EXIST), FATFS_ROM_INT(FR_EXIST)},
{MP_ROM_QSTR(MP_QSTR_FR_INVALID_OBJECT), FATFS_ROM_INT(FR_INVALID_OBJECT)},
{MP_ROM_QSTR(MP_QSTR_FR_WRITE_PROTECTED),
FATFS_ROM_INT(FR_WRITE_PROTECTED)},
{MP_ROM_QSTR(MP_QSTR_FR_INVALID_DRIVE), FATFS_ROM_INT(FR_INVALID_DRIVE)},
{MP_ROM_QSTR(MP_QSTR_FR_NOT_ENABLED), FATFS_ROM_INT(FR_NOT_ENABLED)},
{MP_ROM_QSTR(MP_QSTR_FR_NO_FILESYSTEM), FATFS_ROM_INT(FR_NO_FILESYSTEM)},
{MP_ROM_QSTR(MP_QSTR_FR_MKFS_ABORTED), FATFS_ROM_INT(FR_MKFS_ABORTED)},
{MP_ROM_QSTR(MP_QSTR_FR_TIMEOUT), FATFS_ROM_INT(FR_TIMEOUT)},
{MP_ROM_QSTR(MP_QSTR_FR_LOCKED), FATFS_ROM_INT(FR_LOCKED)},
{MP_ROM_QSTR(MP_QSTR_FR_NOT_ENOUGH_CORE),
FATFS_ROM_INT(FR_NOT_ENOUGH_CORE)},
{MP_ROM_QSTR(MP_QSTR_FR_TOO_MANY_OPEN_FILES),
FATFS_ROM_INT(FR_TOO_MANY_OPEN_FILES)},
{MP_ROM_QSTR(MP_QSTR_FR_INVALID_PARAMETER),
FATFS_ROM_INT(FR_INVALID_PARAMETER)},
{MP_ROM_QSTR(MP_QSTR_FR_NO_SPACE), FATFS_ROM_INT(FR_NO_SPACE)},
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_fatfs_globals,
mod_trezorio_fatfs_globals_table);

View File

@ -1,4 +1,41 @@
from typing import *
FR_OK: int # (0) Succeeded
FR_DISK_ERR: int # (1) A hard error occurred in the low level disk I/O layer
FR_INT_ERR: int # (2) Assertion failed
FR_NOT_READY: int # (3) The physical drive cannot work
FR_NO_FILE: int # (4) Could not find the file
FR_NO_PATH: int # (5) Could not find the path
FR_INVALID_NAME: int # (6) The path name format is invalid
FR_DENIED: int # (7) Access denied due to prohibited access or directory full
FR_EXIST: int # (8) Access denied due to prohibited access
FR_INVALID_OBJECT: int # (9) The file/directory object is invalid
FR_WRITE_PROTECTED: int # (10) The physical drive is write protected
FR_INVALID_DRIVE: int # (11) The logical drive number is invalid
FR_NOT_ENABLED: int # (12) The volume has no work area
FR_NO_FILESYSTEM: int # (13) There is no valid FAT volume
FR_MKFS_ABORTED: int # (14) The f_mkfs() aborted due to any problem
FR_TIMEOUT: int # (15) Could not get a grant to access the volume within defined period
FR_LOCKED: int # (16) The operation is rejected according to the file sharing policy
FR_NOT_ENOUGH_CORE: int # (17) LFN working buffer could not be allocated
FR_TOO_MANY_OPEN_FILES: int # (18) Number of open files > FF_FS_LOCK
FR_INVALID_PARAMETER: int # (19) Given parameter is invalid
# nonstandard value:
FR_NO_SPACE: int # (64) No space left on device
# extmod/modtrezorio/modtrezorio-fatfs.h
class FatFSError(OSError):
pass
# extmod/modtrezorio/modtrezorio-fatfs.h
class NotMounted(FatFSError):
pass
# extmod/modtrezorio/modtrezorio-fatfs.h
class NoFilesystem(FatFSError):
pass
# extmod/modtrezorio/modtrezorio-fatfs.h

View File

@ -95,8 +95,8 @@ async def ensure_sdcard(
fatfs.mount()
# Mount succeeded, filesystem is OK
return
except OSError:
# Mount failed. Handle the problem outside except-clause
except fatfs.FatFSError:
# Mount failed. Handle problem outside except clause.
pass
if not await format_card_dialog(ctx):
@ -109,7 +109,7 @@ async def ensure_sdcard(
fatfs.setlabel("TREZOR")
# mkfs and mount succeeded
return
except OSError:
except fatfs.FatFSError:
pass
# allow retry if we get as far as here

View File

@ -47,7 +47,7 @@ def _load_salt(auth_key: bytes, path: str) -> Optional[bytearray]:
stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES)
f.read(salt)
f.read(stored_tag)
except OSError:
except fatfs.FatFSError:
return None
# Check the salt's authentication tag.
@ -82,10 +82,10 @@ def load_sd_salt() -> Optional[bytearray]:
# TODO Possibly overwrite salt file with random data.
try:
fatfs.unlink(salt_path)
except OSError:
except fatfs.FatFSError:
pass
# fatfs.rename can fail with a write error, which falls through as an OSError.
# fatfs.rename can fail with a write error, which falls through as an FatFSError.
# This should be handled in calling code, by allowing the user to retry.
fatfs.rename(new_salt_path, salt_path)
return salt
@ -108,7 +108,7 @@ def commit_sd_salt() -> None:
try:
fatfs.unlink(salt_path)
except OSError:
except fatfs.FatFSError:
pass
fatfs.rename(new_salt_path, salt_path)

View File

@ -51,9 +51,9 @@ class TestTrezorIoFatfs(unittest.TestCase):
self.assertEqual(s, (4, "----a", self._filename()))
fatfs.unlink("/%s" % self._dirname())
fatfs.unlink("/%s" % self._filename())
with self.assertRaises(OSError):
with self.assertRaises(fatfs.FatFSError):
fatfs.stat("/%s" % self._dirname())
with self.assertRaises(OSError):
with self.assertRaises(fatfs.FatFSError):
self.assertRaises(fatfs.stat("/%s" % self._filename()))
def test_rename(self):
@ -66,9 +66,9 @@ class TestTrezorIoFatfs(unittest.TestCase):
self.assertEqual(s, (4, "----a", self._filename()))
fatfs.rename("/%s" % self._dirname(), "/%s" % self._dirname("2"))
fatfs.rename("/%s" % self._filename(), "/%s" % self._filename("2"))
with self.assertRaises(OSError):
with self.assertRaises(fatfs.FatFSError):
fatfs.stat("/%s" % self._dirname())
with self.assertRaises(OSError):
with self.assertRaises(fatfs.FatFSError):
self.assertRaises(fatfs.stat("/%s" % self._filename()))
s = fatfs.stat("/%s" % self._dirname("2"))
self.assertEqual(s, (0, "---d-", self._dirname("2")))
@ -138,15 +138,6 @@ class TestTrezorIoFatfsMounting(unittest.TestCase):
UNMOUNTED_METHODS = [
("mkfs", ()),
]
OTHER = {
"__name__",
"__class__",
"mount",
"unmount",
"is_mounted",
"FatFSFile",
"FatFSDir",
}
def setUp(self):
sdcard.power_on()
@ -173,17 +164,12 @@ class TestTrezorIoFatfsMounting(unittest.TestCase):
try:
fatfs.mount()
self.fail("should have raised")
except OSError as e:
self.assertEqual(e.args[0], 19) # ENODEV
except fatfs.FatFSError as e:
self.assertIsInstance(e, fatfs.NoFilesystem)
# check that the proper error code is set on the NoFilesystem subclass
self.assertEqual(e.args[0], fatfs.FR_NO_FILESYSTEM)
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()
@ -198,8 +184,8 @@ class TestTrezorIoFatfsMounting(unittest.TestCase):
try:
function(*call)
self.fail("should have raised")
except OSError as e:
self.assertEqual(e.args[0], 16) # EBUSY
except fatfs.FatFSError as e:
self.assertEqual(e.args[0], fatfs.FR_LOCKED)
def test_unmounted(self):
fatfs.unmount()
@ -216,15 +202,17 @@ class TestTrezorIoFatfsMounting(unittest.TestCase):
try:
function(*call)
self.fail("should have raised")
except OSError as e:
self.assertEqual(e.args[0], 19) # ENODEV
except fatfs.FatFSError as e:
self.assertIsInstance(e, fatfs.NotMounted)
# check that the proper error code is set on the NotMounted subclass
self.assertEqual(e.args[0], fatfs.FR_NOT_READY)
class TestTrezorIoFatfsAndSdcard(unittest.TestCase):
def test_sd_power(self):
sdcard.power_off()
self.assertFalse(fatfs.is_mounted())
self.assertRaises(OSError, fatfs.mount)
self.assertRaises(fatfs.FatFSError, fatfs.mount)
sdcard.power_on()
self.assertFalse(fatfs.is_mounted())