mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 09:28:13 +00:00
core: update Python facing APIs
This commit is contained in:
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()
|
||||
with sdcard.filesystem(mounted=False):
|
||||
fatfs.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(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.assertEqual(io.sdcard.capacity(), 0)
|
||||
# filesystem should not be available
|
||||
with self.assertRaises(OSError):
|
||||
fs_a.listdir("/")
|
||||
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…
Reference in New Issue
Block a user