core: update Python facing APIs

pull/878/head
matejcik 4 years ago
parent 9ab84d2455
commit 18ac4fc9ca

@ -1,6 +1,6 @@
import storage.sd_salt
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 apps.common.confirm import confirm, hold_to_confirm
@ -91,8 +91,8 @@ async def ensure_sdcard(
while True:
try:
with sdcard.get_filesystem(mounted=False) as fs:
fs.mount()
with sdcard.filesystem(mounted=False):
fatfs.mount()
# Mount succeeded, filesystem is OK
return
except OSError:
@ -103,13 +103,18 @@ async def ensure_sdcard(
raise SdCardUnavailable("SD card not formatted.")
try:
with sdcard.get_filesystem(mounted=False) as fs:
fs.mkfs()
# mkfs succeeded. Re-run loop to retry mounting.
continue
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
fatfs.mount()
fatfs.setlabel("TREZOR")
# mkfs and mount succeeded
return
except OSError:
if not await sd_problem_dialog(ctx):
raise SdCardUnavailable("Problem formatting SD card.")
pass
# 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(

@ -145,8 +145,7 @@ if __debug__:
try:
io.sdcard.power_on()
if msg.format:
fs = io.FatFS()
fs.mkfs()
io.fatfs.mkfs()
else:
# trash first 1 MB of data to destroy the FAT filesystem
assert io.sdcard.capacity() >= 1024 * 1024

@ -1,13 +1,13 @@
from micropython import const
import storage.device
from trezor import fatfs
from trezor.crypto import hmac
from trezor.crypto.hashlib import sha256
from trezor.sdcard import get_filesystem
from trezor.sdcard import with_filesystem
from trezor.utils import consteq
if False:
from trezor import io
from typing import Optional, TypeVar, 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 "")
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.
try:
with fs.open(path, "r") as f:
with fatfs.open(path, "r") as f:
salt = bytearray(SD_SALT_LEN_BYTES)
stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES)
f.read(salt)
@ -57,6 +58,7 @@ def _load_salt(fs: io.FatFS, auth_key: bytes, path: str) -> Optional[bytearray]:
return salt
@with_filesystem
def load_sd_salt() -> Optional[bytearray]:
salt_auth_key = storage.device.get_sd_salt_auth_key()
if salt_auth_key is None:
@ -65,55 +67,54 @@ def load_sd_salt() -> Optional[bytearray]:
salt_path = _get_salt_path()
new_salt_path = _get_salt_path(new=True)
with get_filesystem() as fs:
salt = _load_salt(fs, salt_auth_key, salt_path)
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)
salt = _load_salt(salt_auth_key, salt_path)
if salt is not None:
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:
salt_path = _get_salt_path(stage)
with get_filesystem() as fs:
fs.mkdir("/trezor", True)
fs.mkdir(_get_device_dir(), True)
with fs.open(salt_path, "w") as f:
f.write(salt)
f.write(salt_tag)
fatfs.mkdir("/trezor", True)
fatfs.mkdir(_get_device_dir(), True)
with fatfs.open(salt_path, "w") as f:
f.write(salt)
f.write(salt_tag)
@with_filesystem
def commit_sd_salt() -> None:
salt_path = _get_salt_path(new=False)
new_salt_path = _get_salt_path(new=True)
with get_filesystem() as fs:
try:
fs.unlink(salt_path)
except OSError:
pass
fs.rename(new_salt_path, salt_path)
try:
fatfs.unlink(salt_path)
except OSError:
pass
fatfs.rename(new_salt_path, salt_path)
@with_filesystem
def remove_sd_salt() -> None:
salt_path = _get_salt_path()
with get_filesystem() as fs:
# TODO Possibly overwrite salt file with random data.
fs.unlink(salt_path)
# TODO Possibly overwrite salt file with random data.
fatfs.unlink(salt_path)

@ -1,2 +1,4 @@
import trezorconfig as config # 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:
from typing import Any, Optional
from typing import Any, Callable, Optional, TypeVar
T = TypeVar("T", bound=Callable)
class FilesystemWrapper:
_INSTANCE = None # type: Optional[FilesystemWrapper]
def __init__(self, mounted: bool) -> None:
self.fs = FatFS()
self.mounted = mounted
self.counter = 0
@ -21,20 +22,18 @@ class FilesystemWrapper:
return cls._INSTANCE
def _deinit_instance(self) -> None:
if self.mounted:
self.fs.unmount()
fatfs.unmount()
sdcard.power_off()
FilesystemWrapper._INSTANCE = None
def __enter__(self) -> "FatFS":
def __enter__(self) -> None:
try:
if self.counter <= 0:
self.counter = 0
sdcard.power_on()
if self.mounted:
self.fs.mount()
fatfs.mount()
self.counter += 1
return self.fs
except Exception:
self._deinit_instance()
raise
@ -46,8 +45,17 @@ class FilesystemWrapper:
self._deinit_instance()
def get_filesystem(mounted: bool = True) -> FilesystemWrapper:
def filesystem(mounted: bool = True) -> FilesystemWrapper:
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
capacity = sdcard.capacity

@ -1,75 +1,68 @@
from common import *
from trezor import io, sdcard
from trezor import io, fatfs, sdcard
class TestTrezorSdcard(unittest.TestCase):
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
self.assertEqual(io.sdcard.capacity(), 0)
with sdcard.get_filesystem(mounted=False):
self.assertTrue(io.sdcard.capacity() > 0)
self.assertEqual(io.sdcard.capacity(), 0)
self.assertEqual(sdcard.capacity(), 0)
with sdcard.filesystem(mounted=False):
self.assertTrue(sdcard.capacity() > 0)
self.assertEqual(sdcard.capacity(), 0)
def test_nomount(self):
with sdcard.get_filesystem(mounted=False) as fs:
with self.assertRaises(OSError):
fs.listdir("/")
with sdcard.filesystem(mounted=False):
self.assertFalse(fatfs.is_mounted())
def test_mount(self):
# set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs:
fs.mkfs()
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
with sdcard.get_filesystem() as fs:
# the following should succeed
fs.listdir("/")
with sdcard.filesystem():
self.assertTrue(fatfs.is_mounted())
# filesystem should not be available
with self.assertRaises(OSError):
fs.listdir("/")
self.assertFalse(fatfs.is_mounted())
def test_nesting(self):
# set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs:
fs.mkfs()
self.assertEqual(io.sdcard.capacity(), 0)
with sdcard.get_filesystem() as fs_a:
self.assertTrue(io.sdcard.capacity() > 0)
with sdcard.get_filesystem() as fs_b:
self.assertTrue(io.sdcard.capacity() > 0)
self.assertIs(fs_a, fs_b)
fs_b.listdir("/")
self.assertTrue(io.sdcard.capacity() > 0)
# filesystem should still be mounted
fs_a.listdir("/")
self.assertEqual(io.sdcard.capacity(), 0)
# filesystem should not be available
with self.assertRaises(OSError):
fs_a.listdir("/")
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
self.assertEqual(sdcard.capacity(), 0)
with sdcard.filesystem():
self.assertTrue(sdcard.capacity() > 0)
self.assertTrue(fatfs.is_mounted())
with sdcard.filesystem():
self.assertTrue(sdcard.capacity() > 0)
self.assertTrue(fatfs.is_mounted())
self.assertTrue(sdcard.capacity() > 0)
self.assertTrue(fatfs.is_mounted())
self.assertEqual(sdcard.capacity(), 0)
self.assertFalse(fatfs.is_mounted())
def test_mount_nomount(self):
with self.assertRaises(RuntimeError):
with sdcard.get_filesystem(mounted=True):
with sdcard.get_filesystem(mounted=False):
with sdcard.filesystem(mounted=True):
with sdcard.filesystem(mounted=False):
pass
with self.assertRaises(RuntimeError):
with sdcard.get_filesystem(mounted=False):
with sdcard.get_filesystem(mounted=True):
with sdcard.filesystem(mounted=False):
with sdcard.filesystem(mounted=True):
pass
def test_failed_mount(self):
# set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs:
fs.mkfs()
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
with sdcard.get_filesystem() as fs:
# the following should succeed
fs.listdir("/")
with sdcard.filesystem():
self.assertTrue(fatfs.is_mounted())
# trash filesystem
io.sdcard.power_on()
@ -78,17 +71,18 @@ class TestTrezorSdcard(unittest.TestCase):
# mounting should now fail
with self.assertRaises(OSError):
with sdcard.get_filesystem() as fs:
with sdcard.filesystem():
pass
self.assertFalse(fatfs.is_mounted())
# it should be possible to create an unmounted instance
with sdcard.get_filesystem(mounted=False) as fs:
fs.mkfs()
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
# mounting should now succeed
with sdcard.get_filesystem() as fs:
fs.listdir("/")
with sdcard.filesystem():
self.assertTrue(fatfs.is_mounted())
if __name__ == "__main__":

Loading…
Cancel
Save