vfs — control del sistema de archivos virtual

El módulo vfs contiene funciones para crear objetos de sistema de archivos y montarlos/desmontarlos en el sistema de archivos virtual.

Montaje de sistemas de archivos

Algunos puertos proporcionan un sistema de archivos virtual (VFS) y la capacidad de montar varios sistemas de archivos «reales» dentro de este VFS. Los objetos de sistema de archivos pueden montarse en la raíz del VFS o en un subdirectorio ubicado en la raíz. Esto permite una configuración dinámica y flexible del sistema de archivos que ven los programas de Python. Los puertos que disponen de esta funcionalidad proporcionan las funciones mount() y umount(), y posiblemente diversas implementaciones de sistemas de archivos representadas por clases VFS.

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

Monta el objeto de sistema de archivos fsobj en la ubicación del VFS indicada por la cadena mount_point. fsobj puede ser un objeto VFS que tenga un método mount(), o un dispositivo de bloques. Si es un dispositivo de bloques, el tipo de sistema de archivos se detecta automáticamente (se lanza una excepción si no se reconoce ningún sistema de archivos). mount_point puede ser '/' para montar fsobj en la raíz, o '/<name>' para montarlo en un subdirectorio bajo la raíz.

Si readonly es True, el sistema de archivos se monta en modo de solo lectura.

Durante el proceso de montaje se llama al método mount() del objeto de sistema de archivos.

Lanza OSError(EPERM) si mount_point ya está montado.

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

Sin argumentos para mount(), devuelve una lista de tuplas que representan todos los puntos de montaje activos.

La lista devuelta tiene la forma [(fsobj, mount_point), …].

vfs.umount(mount_point: str | Any) None

Desmonta un sistema de archivos. mount_point puede ser una cadena que nombre la ubicación de montaje, o un objeto de sistema de archivos montado previamente. Durante el proceso de desmontaje se llama al método umount() del objeto de sistema de archivos.

Lanza OSError(EINVAL) si no se encuentra mount_point.

class vfs.VfsFat(block_dev: AbstractBlockDev)

Crea un objeto de sistema de archivos que utiliza el formato de sistema de archivos FAT. El almacenamiento del sistema de archivos FAT lo proporciona block_dev. Los objetos creados por este constructor pueden montarse mediante mount().

static mkfs(block_dev: AbstractBlockDev) None

Construye un sistema de archivos FAT en block_dev.

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

Crea un objeto de sistema de archivos que utiliza el formato de sistema de archivos de solo lectura ROMFS. buffer debe ser un objeto que admita el protocolo de búfer (bytes, bytearray o memoryview) y que contenga una imagen ROMFS válida.

Los objetos creados por este constructor pueden montarse mediante mount().

Consulta Trabajar con ROMFS para conocer todos los detalles, incluido cómo construir y desplegar imágenes ROMFS con mpremote.

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

Interfaz de bajo nivel para acceder a las particiones de memoria de solo lectura (ROM) del dispositivo. Las operaciones admitidas son:

Llamada

Comportamiento

rom_ioctl(1)

Devuelve el número de particiones ROM disponibles.

rom_ioctl(2, id)

Devuelve la partición id como un memoryview.

rom_ioctl(3, id, length)

Borra los primeros length bytes de la partición id como preparación para la escritura. Devuelve la alineación mínima de escritura en bytes.

rom_ioctl(4, id, offset, buf)

Escribe buf en la partición id en el byte offset.

rom_ioctl(5, id)

Finaliza una secuencia de escritura en la partición id (vacía las cachés, etc.).

Estas operaciones normalmente las invoca de forma indirecta mpremote al desplegar una imagen ROMFS; la mayoría de las aplicaciones no necesitan llamarlas directamente.

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

Crea un objeto de sistema de archivos que accede al sistema de archivos POSIX del host. Si se especifica root, debe ser una ruta del sistema de archivos del host que se usará como raíz del objeto VfsPosix. De lo contrario, se utiliza el directorio actual del sistema de archivos del host.

Nota

VfsPosix solo está disponible en el puerto Unix de MicroPython; no está presente en el firmware de la OpenMV Cam.

Dispositivos de bloques

Un dispositivo de bloques es un objeto que implementa el protocolo de bloques. Esto permite que un dispositivo admita los sistemas de archivos de MicroPython. El hardware físico se representa mediante una clase definida por el usuario. La clase AbstractBlockDev es una plantilla para el diseño de dicha clase: MicroPython no proporciona realmente esa clase, pero una clase de dispositivo de bloques real debe implementar los métodos descritos a continuación.

Una implementación concreta de esta clase normalmente permitirá acceder a la funcionalidad de tipo memoria de un componente de hardware (como la memoria flash). Un dispositivo de bloques puede formatearse con cualquier sistema de archivos admitido y montarse mediante los métodos de os.

Consulta Trabajar con sistemas de archivos para ver ejemplos de implementaciones de dispositivos de bloques que utilizan las dos variantes del protocolo de bloques descritas a continuación.

Interfaz simple y extendida

Existen dos firmas compatibles para los métodos readblocks y writeblocks (véase más abajo), con el fin de admitir diversos casos de uso. Un dispositivo de bloques determinado puede implementar una u otra forma, o ambas a la vez. La segunda forma (con el parámetro de desplazamiento) se denomina «interfaz extendida».

Algunos sistemas de archivos requieren más control sobre las operaciones de escritura – por ejemplo, escribir en regiones de subbloques sin borrar – y necesitan que el dispositivo de bloques admita la interfaz extendida.

class vfs.AbstractBlockDev

Plantilla de documentación para el protocolo de dispositivo de bloques. MicroPython no expone realmente esta clase — se muestra aquí únicamente para documentar los métodos que debe implementar una clase de dispositivo de bloques definida por el usuario. Los argumentos del constructor dependen por completo de la implementación (normalmente cosas como el bus de la memoria flash, el pin de selección de chip, el tamaño de sector, etc.).

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

Lee bytes del dispositivo en buf. Dos sobrecargas exponen las interfaces simple y extendida.

Forma simple (readblocks(block_num, buf)): lee bloques completos a partir del índice de bloque block_num. len(buf) debe ser un múltiplo del tamaño de bloque, y el número de bloques leídos es len(buf) // block_size.

Forma extendida (readblocks(block_num, buf, offset)): lee len(buf) bytes – no necesariamente un número entero de bloques – a partir del byte offset dentro del bloque block_num. Usa esta forma cuando el sistema de archivos necesite acceso de lectura a nivel de subbloque.

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

Escribe bytes desde buf en el dispositivo.

Forma simple (writeblocks(block_num, buf)): escribe bloques completos a partir del índice de bloque block_num. len(buf) debe ser un múltiplo del tamaño de bloque, y el número de bloques escritos es len(buf) // block_size. La implementación es responsable de borrar primero cada bloque de destino si el hardware subyacente lo requiere.

Forma extendida (writeblocks(block_num, buf, offset)): escribe len(buf) bytes – no necesariamente un número entero de bloques – a partir del byte offset dentro del bloque block_num. Solo pueden cambiar los bytes que se están escribiendo; quien hace la llamada es responsable de garantizar que los bloques afectados se hayan borrado mediante una llamada previa a ioctl(6, block_num). Las implementaciones de esta forma nunca deben borrar implícitamente un bloque, ni siquiera cuando offset es cero.

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

Controla el dispositivo de bloques y consulta sus parámetros. La operación que se va a realizar viene dada por op, que es uno de los siguientes enteros:

  • 1 – inicializa el dispositivo (arg no se utiliza)

  • 2 – apaga el dispositivo (arg no se utiliza)

  • 3 – sincroniza el dispositivo (arg no se utiliza)

  • 4 – obtiene un recuento del número de bloques, debe devolver un entero (arg no se utiliza)

  • 5 – obtiene el número de bytes de un bloque, debe devolver un entero, o None, en cuyo caso se utiliza el valor predeterminado de 512 (arg no se utiliza)

  • 6 – borra un bloque, arg es el número del bloque que se va a borrar

Como mínimo debe interceptarse ioctl(4, ...); los sistemas de archivos que utilizan la interfaz extendida requieren además ioctl(6, ...). La necesidad de las demás operaciones depende del hardware.

Antes de cualquier llamada a writeblocks(block, ...), un sistema de archivos que utiliza la interfaz extendida emite ioctl(6, block) para que el controlador pueda borrar primero el bloque si el hardware lo requiere. Un controlador puede, en su lugar, interceptar ioctl(6, block) y devolver 0 (éxito), asumiendo él mismo la responsabilidad de detectar cuándo es necesario el borrado.

Salvo que se indique lo contrario, ioctl(op, arg) puede devolver None. En consecuencia, una implementación puede ignorar los valores no utilizados de op. Cuando se intercepta op, el valor de retorno para las operaciones 4 y 5 es el detallado anteriormente. Las demás operaciones deben devolver 0 en caso de éxito y un valor distinto de cero en caso de fallo, siendo el valor devuelto un código errno de OSError.