Utilidad para leer particiones Ext2/3/4

mayo 1, 2010

En los dos últimos posts describí el formato del sistema de archivos Ext2/3/4 y las extensiones más frecuentes. Hoy, puesto que una línea de código vale más que mil palabras, presento una pequeña librería que proporciona acceso a los archivos de uno de estos sistemas (en modo solo lectura, no quiero problemas), y una herramienta sencilla de ejemplo: e2cat. Esta copia un archivo del dispositivo indicado sin necesidad de copiar el volumen.

Descarga el código fuente aquí (licencia zlib/libpng).

Y descarga el binario para MS-Windows aquí.


Pero debes ser consciente de que el principal objetivo de este código es ser didáctico, por lo que no es particularmente completo ni eficiente.

Instrucciones de uso de e2cat

Si ejecutas el programa sin parámetros muestra la ayuda rápida:

$ ./e2cat
Copyright (c) 2010 Rodrigo Rivas Costa. http://rodrigo.dualnot.com
Syntax:
    ./e2cat -d <device> [-f] [-o <output>] [<file> | -i <inode>]*

Donde es el nombre del dispositivo que contiene el sistema de archivos (por ejemplo /dev/sdc4) o el nombre de un archivo imagen. El parámetro opcional indica el nombre de un fichero en el que se guardan, concatenados, todos los ficheros que se listen a continuación. Si no se incluye se copia a la salida estándar. Los son nombres de fichero dentro del sistema de archivos, siemplre con path absoluto. También se puede indicar un número de inodo, en lugar de un nombre de fichero, con la opción -i.
La opción -f hace que se intente leer el sistema incluso ante la presencia de extensiones incompatibles.

Si todavía utilizas MS-Windows los parámetros para seleccionar la partición son ligeramente diferentes. Esto es necesario porque Windows no asigna nombres de dispositivo a los volúmenes que no reconoce.

C:\> e2cat.exe
Copyright (c) 2010 Rodrigo Rivas Costa. http://rodrigo.dualnot.com
Syntax:
    e2cat.exe -d <device> [-p <part-num>] [-f] [-o <output>] [<file> | -i <inode>]*
Or:
    e2cat.exe -p <dev-num>:[<part-num>] [-f] [-o <output>] [<file> | -i <inode>]*

Si el sistema Ext2 está en un disco físico sin particiones puedes usar -d \\.\PhysicalDrive<N> o -p <N>: o -d \\.\D:, siendo <N> el número de disco físico o D: la letra de unidad asignada por Windows.
Pero es más probable que tengas el volumen Ext2 en una partición, en cuyo caso debes escribir -d \\.\PhysicalDrive<N> -p <P> o bien -p <N>:<P>, donde <N> es el número de disco físico y <P> el número de la partición.

(Ejecuta el administrador de discos si no sabes cuál es cuál).

La librería miext2

El código de la librería miext2 es bastante sencillo de entender si has seguido mis dos posts anteriores. Todos los símbolos se declaran en el espacio de nombre ext2. Se incluyen unas cuantas estructuras y las siguientes clases:

  • Volume: Representa el sistema de archivos.
  • Block: Es un bloque de disco (básicamente un array de bytes). Está diseñada para que sea sencillo incluir una caché de bloques, aunque no se incluye. Sí se evita leer el mismo bloque muchas veces consecutivas, en la mayoría de los casos.
  • File: Describe un archivo en el sistema de archivos.
  • Dir: Es una subclase de File con funciones para leer las entradas de directorio.

Como el volumen se accede en modo “solo lectura” no he implementado ninguna de las features compatibles ni ro-compatibles. De las incompatibles he programado filetype, extens y flex_bg, que son suficientes para acceder a todos los volúmenes de mi Linux.
Una ausencia incompatible notable es 64bits, que se utiliza con volúmenes muy grandes; el problema es que no tengo ningún disco lo bastante grande como para probarlo (se aceptan donaciones y/o parches).
Si intentas acceder a un volumen Ext3 o Ext4 montado te fallará diciendo Incompatible features: recover. Puedes intentarlo otra vez con la opción -f y ver qué pasa. También puede ser una buena idea ejecutar el comando sync antes, para que los datos en disco estén actualizados.

Ficheros sparse

Los ficheros sparse (dispersos) son ficheros que no tienen todos sus bloques de datos guardados en disco. Desde una aplicación de usuario los agujeros en los datos se ven como secuencias de ceros. Puedes determinar si un fichero es sparse comparando el tamaño devuelto por ls y por du.
El módulo miext2 detecta correctamente los agujeros en los ficheros sparse y devuelve los ceros que corresponde. Con el método clásico de índices, un agujero en el fichero es un índice de valor 0. Con los extents es simplemente un rango de bloques que no aparece en el árbol.
La clase Volume contiene una variable miembro llamada m_zeroBlock, que representa a todos los bloques que forman parte de un agujero.

Particiones en Windows

MS-Windows no asigna (que yo sepa) nombres de dispositivo ni letras de unidad a particiones que no reconoce, por lo que es necesario acceder a la partición dentro del disco físico de forma manual. Afortunadamente existe un mecanismo por el que el sistema nos informa del contenido de la tabla de particiones. Puedes ver los detalles en la siguiente función:

static off64_t GetOffsetOfPartition(int fd, int part)
{
    HANDLE hDisk = (HANDLE)_get_osfhandle(fd);
    DWORD bytes;
    union
    {
        DRIVE_LAYOUT_INFORMATION_EX hdr;
        char data[sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 7*sizeof(PARTITION_INFORMATION_EX)];
    } layout;
    BOOL res = DeviceIoControl((HANDLE)hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 
                NULL, 0, &layout, sizeof(layout), &bytes, NULL);
    if (!res)
        return 0;
    if (part >=0 && static_cast<unsigned>(part) < layout.hdr.PartitionCount && part < 8)
        return layout.hdr.PartitionEntry[part].StartingOffset.QuadPart;
    else
        return 0;
}

El tamaño de off_t

Un problema al compilar este programa es que es necesario que el tipo off_t, que se utiliza para indicar una posición, en bytes, dentro de un fichero (offset), sea de al menos 64 bits. Pero en Linux tradicional y en Windows este tipo es de 32 bits. La solución más sencilla es utilizar la función lseek64 en lugar de lseek para moverse en el fichero, y off64_t en lugar de off_t.

Artículos relacionados:

  1. Analizando Ext2, Ext3 y Ext4 Resulta paradójico que el sistema de archivos más utilizado de...
  2. Extensiones de Ext2, Ext3 y Ext4 En el post anterior describía con más o menos detalle...
  3. Jugando con device-mapper y loop Hace unos días tuve que mover un archivo grande de...

2 Responses to “Utilidad para leer particiones Ext2/3/4”

  1. Hola Rodrigo, estoy realizando una practica de la universidad: se trata de leer diversos volumenes (fat12,16,32 y ext2) desde C y listar el arbol de archivos y directorios. Tengo todos hechos menos el de ext2. Estoy un poco desesperado y necesitaría alguien que me echara un cable. No puedo pagar mucho, no se si 50€ por implementarme la función que me falta te parece mucho o poco pero te aseguro que es un esfuerzo para mi.
    En cualquier caso, si te interesara enviame un mail a talibanjustice@hotmail.com y te doy los detalles exactos, el codigo que tengo ya hecho y lo hablamos, si te parece.
    Un saludo.

  2. Hola, Estudiante.

    Me temo que no puedo hacer eso :-(
    Pero tienes el código de mi librería ext2/3/4 aquí mismo, además de la explicación del formato en:

    http://rodrigo.dualnot.com/analizando-ext2/
    Y las extensiones, aunque no creo que las necesites:
    http://rodrigo.dualnot.com/extensiones-de-ext2/

    Si te encuentras con dificultades, estaría encantado de ayudarte a resolverlas, pero no puedo hacer la práctica por ti.

    Saludos.
    Rodrigo

Deja un comentario