1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-12 10:39:00 +00:00
trezor-firmware/core/src/apps/common/sdcard.py

142 lines
4.8 KiB
Python

import storage.sd_salt
from storage.sd_salt import SD_CARD_HOT_SWAPPABLE
from trezor import fatfs, sdcard, ui, wire
from trezor.ui.text import Text
from apps.common.confirm import confirm, hold_to_confirm
if False:
from typing import Optional
class SdCardUnavailable(wire.ProcessError):
pass
async def _wrong_card_dialog(ctx: wire.GenericContext) -> bool:
text = Text("SD card protection", ui.ICON_WRONG)
text.bold("Wrong SD card.")
text.br_half()
if SD_CARD_HOT_SWAPPABLE:
text.normal("Please insert the", "correct SD card for", "this device.")
btn_confirm = "Retry" # type: Optional[str]
btn_cancel = "Abort"
else:
text.normal("Please unplug the", "device and insert the", "correct SD card.")
btn_confirm = None
btn_cancel = "Close"
return await confirm(ctx, text, confirm=btn_confirm, cancel=btn_cancel)
async def insert_card_dialog(ctx: wire.GenericContext) -> bool:
text = Text("SD card protection", ui.ICON_WRONG)
text.bold("SD card required.")
text.br_half()
if SD_CARD_HOT_SWAPPABLE:
text.normal("Please insert your", "SD card.")
btn_confirm = "Retry" # type: Optional[str]
btn_cancel = "Abort"
else:
text.normal("Please unplug the", "device and insert your", "SD card.")
btn_confirm = None
btn_cancel = "Close"
return await confirm(ctx, text, confirm=btn_confirm, cancel=btn_cancel)
async def format_card_dialog(ctx: wire.GenericContext) -> bool:
# Format card? yes/no
text = Text("SD card error", ui.ICON_WRONG, ui.RED)
text.bold("Unknown filesystem.")
text.br_half()
text.normal("Use a different card or")
text.normal("format the SD card to")
text.normal("the FAT32 filesystem.")
if not await confirm(ctx, text, confirm="Format", cancel="Cancel"):
return False
# Confirm formatting
text = Text("Format SD card", ui.ICON_WIPE, ui.RED)
text.normal("Do you really want to", "format the SD card?")
text.br_half()
text.bold("All data on the SD card", "will be lost.")
return await hold_to_confirm(ctx, text, confirm="Format SD card")
async def sd_problem_dialog(ctx: wire.GenericContext) -> bool:
text = Text("SD card problem", ui.ICON_WRONG, ui.RED)
text.normal("There was a problem", "accessing the SD card.")
return await confirm(ctx, text, confirm="Retry", cancel="Abort")
async def ensure_sdcard(
ctx: wire.GenericContext, ensure_filesystem: bool = True
) -> None:
"""Ensure a SD card is ready for use.
This function runs the UI flow needed to ask the user to insert a SD card if there
isn't one.
If `ensure_filesystem` is True (the default), it also tries to mount the SD card
filesystem, and allows the user to format the card if a filesystem cannot be
mounted.
"""
while not sdcard.is_present():
if not await insert_card_dialog(ctx):
raise SdCardUnavailable("SD card required.")
if not ensure_filesystem:
return
while True:
try:
try:
with sdcard.filesystem(mounted=False):
fatfs.mount()
except fatfs.NoFilesystem:
# card not formatted. proceed out of the except clause
pass
else:
# no error when mounting
return
if not await format_card_dialog(ctx):
raise SdCardUnavailable("SD card not formatted.")
# Proceed to formatting. Failure is caught by the outside OSError handler
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
fatfs.mount()
fatfs.setlabel("TREZOR")
# format and mount succeeded
return
except OSError:
# formatting failed, or generic I/O error (SD card power-on failed)
if not await sd_problem_dialog(ctx):
raise SdCardUnavailable("Error accessing SD card.")
async def request_sd_salt(
ctx: wire.GenericContext = wire.DUMMY_CONTEXT,
) -> Optional[bytearray]:
if not storage.sd_salt.is_enabled():
return None
while True:
await ensure_sdcard(ctx, ensure_filesystem=False)
try:
return storage.sd_salt.load_sd_salt()
except (storage.sd_salt.WrongSdCard, fatfs.NoFilesystem):
if not await _wrong_card_dialog(ctx):
raise SdCardUnavailable("Wrong SD card.")
except OSError:
# Generic problem with loading the SD salt (hardware problem, or we could
# not read the file, or there is a staged salt which cannot be committed).
# In either case, there is no good way to recover. If the user clicks Retry,
# we will try again.
if not await sd_problem_dialog(ctx):
raise SdCardUnavailable("Error accessing SD card.")