vfs — керування віртуальною файловою системою

Модуль vfs містить функції для створення об’єктів файлової системи та монтування/демонтування їх у Віртуальній файловій системі.

Монтування файлових систем

Деякі порти надають Віртуальну файлову систему (VFS) та можливість монтування кількох «реальних» файлових систем у цій VFS. Об’єкти файлових систем можна монтувати або в кореневий каталог VFS, або в підкаталог кореневого каталогу. Це дозволяє динамічно та гнучко налаштовувати файлову систему, яку бачать програми Python. Порти з такою функціональністю надають функції mount() і umount(), а також, можливо, різні реалізації файлових систем, представлені класами VFS.

vfs.mount(fsobj: Any, mount_point: str, *, readonly: bool = False) None

Монтує об’єкт файлової системи fsobj у місце VFS, задане рядком mount_point. fsobj може бути об’єктом VFS, що має метод mount(), або блоковим пристроєм. Якщо це блоковий пристрій, тип файлової системи визначається автоматично (якщо файлова система не розпізнана, генерується виняток). mount_point може бути '/' для монтування fsobj у кореневий каталог, або '/<name>' для монтування в підкаталог кореневого каталогу.

Якщо readonly дорівнює True, файлова система монтується лише для читання.

Під час монтування на об’єкті файлової системи викликається метод mount().

Генерує OSError(EPERM), якщо mount_point вже змонтований.

vfs.mount() List[Tuple[Any, str]]

Без аргументів до mount() повертає список кортежів, що представляють усі активні точки монтування.

Повернутий список має вигляд [(fsobj, mount_point), …].

vfs.umount(mount_point: str | Any) None

Демонтує файлову систему. mount_point може бути рядком із назвою точки монтування або раніше змонтованим об’єктом файлової системи. Під час демонтування на об’єкті файлової системи викликається метод umount().

Генерує OSError(EINVAL), якщо mount_point не знайдений.

class vfs.VfsFat(block_dev: AbstractBlockDev)

Створює об’єкт файлової системи, що використовує формат FAT. Сховище для файлової системи FAT надається через block_dev. Об’єкти, створені цим конструктором, можна монтувати за допомогою mount().

static mkfs(block_dev: AbstractBlockDev) None

Будує файлову систему FAT на block_dev.

class vfs.VfsRom(buffer: bytes | bytearray | memoryview)

Створює об’єкт файлової системи, що використовує формат файлової системи лише для читання ROMFS. buffer має бути об’єктом, що підтримує протокол буфера (bytes, bytearray або memoryview) і містить коректний образ ROMFS.

Об’єкти, створені цим конструктором, можна монтувати за допомогою mount().

Дивіться Робота з ROMFS для повних деталей, включаючи інструкції зі збирання та розгортання образів ROMFS за допомогою mpremote.

vfs.rom_ioctl(op: int, *args: Any) Any

Низькорівневий інтерфейс для доступу до розділу(ів) пам’яті лише для читання (ROM) пристрою. Підтримувані операції:

Виклик

Поведінка

rom_ioctl(1)

Повернути кількість доступних розділів ROM.

rom_ioctl(2, id)

Повернути розділ id як memoryview.

rom_ioctl(3, id, length)

Стерти перші length байтів розділу id для підготовки до запису. Повертає мінімальне вирівнювання запису в байтах.

rom_ioctl(4, id, offset, buf)

Записати buf у розділ id зі зміщенням offset байтів.

rom_ioctl(5, id)

Завершити послідовність запису в розділ id (скидає кеші тощо).

Ці операції зазвичай викликаються опосередковано через mpremote при розгортанні образу ROMFS; більшості застосунків не потрібно викликати їх напряму.

class vfs.VfsPosix(root: str | None = None)

Створює об’єкт файлової системи, що надає доступ до файлової системи POSIX хоста. Якщо вказано root, він має бути шляхом у файловій системі хоста, що використовується як корінь об’єкта VfsPosix. В іншому разі використовується поточний каталог файлової системи хоста.

Примітка

VfsPosix доступний лише для Unix-порту MicroPython; він відсутній у мікропрограмі OpenMV Cam.

Блокові пристрої

Блоковий пристрій — це об’єкт, що реалізує блоковий протокол. Це дозволяє пристрою підтримувати файлові системи MicroPython. Фізичне обладнання представлене класом, визначеним користувачем. Клас AbstractBlockDev є шаблоном для проектування такого класу: MicroPython насправді не надає цей клас, але фактичний клас блокового пристрою повинен реалізовувати методи, описані нижче.

Конкретна реалізація цього класу зазвичай забезпечує доступ до пам’ятеподібної функціональності частини обладнання (наприклад, флеш-пам’яті). Блоковий пристрій можна відформатувати для будь-якої підтримуваної файлової системи та змонтувати за допомогою методів os.

Дивіться Робота з файловими системами для прикладів реалізацій блокових пристроїв з використанням двох варіантів блокового протоколу, описаних нижче.

Простий та розширений інтерфейс

Для методів readblocks та writeblocks існують дві сумісні сигнатури (см. нижче), щоб підтримувати різноманітні варіанти використання. Конкретний блоковий пристрій може реалізовувати одну форму або іншу, або обидві одночасно. Друга форма (з параметром offset) називається «розширеним інтерфейсом».

Деякі файлові системи потребують більшого контролю над операціями запису — наприклад, запис у підблокові регіони без стирання — і вимагають від блокового пристрою підтримки розширеного інтерфейсу.

class vfs.AbstractBlockDev

Шаблон документації для протоколу блокового пристрою. MicroPython насправді не надає цей клас — він показаний тут лише для документування методів, які повинен реалізовувати клас блокового пристрою, визначений користувачем. Аргументи конструктора повністю залежать від реалізації (зазвичай такі речі, як шина флеш-пам’яті, вивід вибору мікросхеми, розмір сектора тощо).

readblocks(block_num: int, buf: bytearray) None
readblocks(block_num: int, buf: bytearray, offset: int) None

Читає байти з пристрою в buf. Два перевантаження надають простий і розширений інтерфейси.

Проста форма (readblocks(block_num, buf)): читає цілі блоки починаючи з індексу блоку block_num. len(buf) повинно бути кратним розміру блоку, а кількість прочитаних блоків дорівнює len(buf) // block_size.

Розширена форма (readblocks(block_num, buf, offset)): читає len(buf) байтів — не обов’язково цілу кількість блоків — починаючи з байтового offset у блоці block_num. Використовуйте цю форму, коли файловій системі потрібен доступ для читання на рівні підблоків.

writeblocks(block_num: int, buf: bytes) None
writeblocks(block_num: int, buf: bytes, offset: int) None

Записує байти з buf на пристрій.

Проста форма (writeblocks(block_num, buf)): записує цілі блоки починаючи з індексу блоку block_num. len(buf) повинно бути кратним розміру блоку, а кількість записаних блоків дорівнює len(buf) // block_size. Реалізація відповідає за стирання кожного цільового блоку перед записом, якщо цього вимагає апаратне забезпечення.

Розширена форма (writeblocks(block_num, buf, offset)): записує len(buf) байтів — не обов’язково цілу кількість блоків — починаючи з байтового offset у блоці block_num. Змінюватися можуть лише ті байти, що записуються; відповідальність за те, щоб відповідні блоки були заздалегідь стерті через попередній виклик ioctl(6, block_num), покладається на того, хто викликає. Реалізації цієї форми не повинні ніколи неявно стирати блок, навіть якщо offset дорівнює нулю.

ioctl(op: int, arg: int) int | None

Керує блоковим пристроєм та запитує його параметри. Операція задається через op, який є одним з таких цілих чисел:

  • 1 — ініціалізувати пристрій (arg не використовується)

  • 2 — вимкнути пристрій (arg не використовується)

  • 3 — синхронізувати пристрій (arg не використовується)

  • 4 — отримати кількість блоків, повинно повертати ціле число (arg не використовується)

  • 5 — отримати кількість байтів у блоці, повинно повертати ціле число, або None, у разі чого використовується значення за замовчуванням 512 (arg не використовується)

  • 6 — стерти блок, arg є номером блоку для стирання

Як мінімум ioctl(4, ...) повинен оброблятися; файлові системи, що використовують розширений інтерфейс, додатково вимагають ioctl(6, ...). Необхідність в інших операціях залежить від апаратного забезпечення.

Перед будь-яким викликом writeblocks(block, ...) файлова система, що використовує розширений інтерфейс, видає ioctl(6, block), щоб драйвер міг за потреби спочатку стерти блок. Натомість драйвер може перехопити ioctl(6, block) і повернути 0 (успіх), взявши на себе відповідальність за визначення, коли необхідне стирання.

Якщо не зазначено інше, ioctl(op, arg) може повертати None. Отже, реалізація може ігнорувати невикористовувані значення op. Якщо op перехоплено, повернуті значення для операцій 4 та 5 відповідають наведеним вище. Інші операції повинні повертати 0 у разі успіху і ненульове значення у разі помилки, де значення, що повертається, є кодом errno OSError.