Capítulo 4: Estructura de FAT12 y lectura de disco
Nuestro disco ya tiene un sistema de archivos, pero no tiene ningún archivo dentro. Sus primeros 512 bytes contienen información crucial para iniciar FAT12, pero no hemos escrito ningún archivo como tal. La pregunta con la que empezaremos este capítulo es una de mis favoritas: ¿qué ocurre exactamente cuando creamos un archivo en un disco?
Tabla de contenidos
Estructura básica de FAT12
Tras añadir los headers y formatearlo, nuestro disco ha pasado a tener 4 secciones. Este es un mapa de los primeros 24 kilobytes (48 sectores) del disco, en el que se ven las 3 primeras secciones y el inicio de la cuarta:
8 KB | 16 KB | 24 KB | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
Puedes pasar el ratón por encima de la tabla para ver una descripción más detallada de cada elemento.
Si has decidido emular un floppy que no sea de 3 pulgadas y media o has cambiado los headers de alguna forma, es probable que las fronteras entre secciones sean ligeramente distintas, pero las secciones serán las mismas. También es importante aclarar que la sección de datos ocupa todo el resto del disco, no solamente los 7,5 KB que se ven en la tabla.
Si tienes curiosidad por un mapa del disco entero, aquí lo tienes:
360 KB | 720 KB | 1080 KB | 1440 KB | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
|
|
Puedes pasar el ratón por encima de la tabla para ver una descripción más detallada de cada elemento.
Geometría del disco
Dentro de nuestros headers hemos definido muchas variables interesantes. Ahora mismo nos interesan solo algunas, entre las que se incluyen:
- bdb_bytes_per_sector: 512 bytes por cada sector.
- bdb_sectors_per_track: 18 sectores por cilindro (o track).
- bdb_heads: 2 cabezales en el disco.
La definición más importante de estas 3 es la que indica que un sector equivale a 512 bytes. Un sector es una porción de la memoria que funciona como unidad mínima de lectura, y su longitud depende de la geometría del disco.
Cuando leemos datos que están localizados en el disco, lo que hacemos cargarlos en alguna parte de la RAM, sector a sector. Es decir, si queremos leer un archivo que ocupe 1 KB, el proceso a realizar será el siguiente:
- Localizar alguna parte de la RAM que esté libre y tenga espacio para escribir todo el archivo: pongamos que nos quedamos con la dirección 0x50000.
- Leer el primer sector del archivo hacia 0x50000 y apuntar nuestro puntero hacia 0x50200 (512 bytes para delante).
- Leer el segundo sector del archivo hacia 0x50200, y terminar la operación de lectura.
Volveremos a esto cuando tengamos que leer archivos, pero por ahora lo más importante es que entiendas que no se puede leer el disco byte a byte, la unidad mínima de lectura es un sector.
Existen dos formas de definir la dirección de un sector dentro del disco. La más moderna y fácil es el LBA o Logical Block Addressing, y la más antigua (que usaremos únicamente en el modo real del procesador) es el CHS o Cylinder-Head-Sector. El LBA indica el sector en el que se encuentra una parte del disco si empezamos a contar desde cero. El boot sector sería 0, el siguiente 1, 2... y así hasta 2879. Su cálculo es sorprendentemente simple.
Para hablar del direccionamiento CHS hay que tratar primero la arquitectura de un disco duro. El esquema de la izquierda, creado por el usuario de Wikipedia LionKimbro, la ilustra muy bien.
El cabezal es la unidad más grande de las 3. En el caso de nuestro disco (3½" DSHD 1.44 MB) existen únicamente 2 cabezales.
Los cilindros son las secciones concéntricas que incluye un cabezal. En nuestro disco hay un total de 80 cilindros por cabezal.
Los sectores son secciones cónicas que atraviesan todos los cilindros del disco. En nuestro caso, existen 18 sectores por cilindro.
Lo lógico sería que el direccionamiento fuera Cabezal-Cilindro-Sector (o HCS), pero... sencillamente no es así. Así que habrá que acostumbrarse.
Existe una equivalencia clara entre los dos sistemas de direccionamiento. Por ejemplo, el LBA 0 apunta al mismo sector que el CHS 0, 0, 1; el LBA 1 es el CHS 0, 0, 2; el LBA 19 es el CHS 0, 1, 1... y así sucesivamente.
Este sistema está completamente obsoleto hoy en día, pero es necesario conocerlo porque vamos a utilizar la función de la BIOS INT 13/AH=02h para leer sectores del disco, y esta función exige que le proporciones la dirección CHS del disco que quieres leer. Crearemos un "traductor" de LBA a CHS para librarnos de este problema cuanto antes.
Secciones de FAT12: La sección reservada
Los headers que hemos definido y todo el código que escribamos en nuestra stage1 se encuentra en el boot sector, que es el primer sector de la sección reservada. Merece la pena destacar que este sector es lo único que hemos cargado a la RAM hasta ahora. Aquí tienes un mapa de dicho sector:
128 B | 256 B | 384 B | 512 B | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
Puedes pasar el ratón por encima de la tabla para ver una descripción más detallada de cada elemento.
Merece la pena destacar los últimos 2 bytes (en naranja), que contienen la firma necesaria para que la BIOS detecte nuestro dispositivo como iniciable. Es decir, contiene el valor 0x55AA.
Dentro de la sección reservada también puede haber una cantidad arbitraria de sectores reservados para el sistema. Estos sectores serían los siguientes partiendo desde el boot sector, aunque nosotros no hemos reservado ninguno. Esto se puede configurar mediante la variable bdb_reserved_sectors, a la que hemos dado un valor de 1 (para reservar únicamente el boot sector).
Secciones de FAT12: La sección de FAT
La sección de FAT (File Allocation Tables) es un mapa de la sección de datos, que está dividida en clusters. A continuación, explicaremos qué es un cluster, su papel en la sección de datos y cómo esto afecta a la sección de FAT. Se puede calcular su LBA en el disco de la siguiente forma:
/**
* Recuerda:
* bdb_reserved_sectors = Nº de sectores reservados.
*
* Está definido en el header de FAT12.
*/
int fatlba = bdb_reserved_sectors;
Puedes configurar cuántos sectores conforman un cluster usando la variable bdb_sectors_per_cluster, declarada en el header. Nosotros le hemos dado el valor de 1, por lo que un cluster es equivalente a un sector. Igualmente, debemos programar nuestro bootloader teniendo en cuenta que esto podría cambiar cuando nuestro sistema operativo crezca.
La sección de FAT incluye una lista enlazada que nos muestra los clusters que ocupa cada archivo. Una lista enlazada (o linked list) es una secuencia lineal en la que cada valor contiene el siguiente al que hay que apuntar. Aquí tienes una linked list básica:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
1 | 2 | 3 | 7 | 5 | 100 | 4 | 6 |
Para leer la lista en orden, debemos empezar en el índice 0 y dirigirnos al índice que hay guardado ahí, luego al índice guardado en el siguiente valor, y así sucesivamente. Vamos a asumir que el valor 100 marca el fin de la lista. En ese caso, el orden sería el siguiente:
Para entender cómo se traslada todo esto a la data section, vamos a imaginarnos una. Estos son los primeros 16 clusters de una sección de datos hipotética:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 |
---|---|---|---|---|---|---|---|
archivo.txt | carpeta | ||||||
0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
programa.bin | imagen.png |
Aquí tenemos un archivo de texto (archivo.txt) que ocupa 6 clusters, una carpeta que ocupa 2 clusters, un ejecutable de 4 clusters y un archivo de imagen que ocupa otros 4. La sección de FAT resume esta información para que el sistema no tenga que recorrerse la data section entera si quiere buscar un archivo.
Teniendo en cuenta que los finales de archivo se suelen marcar con el número 0xFFF, la sección de FAT sería así:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 |
---|---|---|---|---|---|---|---|
0x001 | 0x002 | 0x003 | 0x004 | 0x005 | 0xFFF | 0x007 | 0xFFF |
0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
0x009 | 0x00A | 0x00B | 0xFFF | 0x00D | 0x00E | 0x00F | 0xFFF |
Si te fijas, cada valor nos indica el siguiente cluster de un archivo, hasta que llegamos al valor 0xFFF, que nos indica el cluster final de un archivo. Si no lo ves claro, compara las dos tablas y verás a lo que me refiero.
A lo mejor te preguntas por qué los números de la tabla tienen 3 cifras. Bueno, te presento una de las particularidades más molestas de FAT12. Los números incluidos en una FAT ocupan 12 bits cada uno. 1,5 bytes. Esto genera un problema de lectura que tendremos que solucionar más tarde. Por ahora solo tienes que tener en cuenta que esa tablita tan clara de arriba, al verla en el disco dividida por bytes, se ve de esta forma:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB |
---|---|---|---|---|---|---|---|---|---|---|---|
0x01 | 0x20 | 0x00 | 0x03 | 0x40 | 0x00 | 0x05 | 0xF0 | 0xFF | 0x07 | 0x80 | 0x00 |
0xC | 0xD | 0xE | 0xF | 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 |
0x09 | 0xA0 | 0x00 | 0x0B | 0xC0 | 0x00 | 0x0D | 0xE0 | 0x00 | 0x0F | 0xF0 | 0xFF |
Explicamos cómo leer tablas como esta más adelante, pero si te puede la curiosidad, aquí te dejo la explicación de este fenómeno incluida en el artículo de Wikipedia del sistema de archivos FAT.
Secciones de FAT12: La carpeta raíz
Esta sección es mucho más simple que las anteriores. Simplemente, muestra la carpeta raíz del sistema de archivos. En Linux, esto serían los contenidos de la carpeta /. El equivalente en Windows es la carpeta C:. Se puede calcular su LBA en el disco de la siguiente forma:
/**
* Recuerda:
* fatlba = Definida en la sección anterior
*
* bdb_sectors_per_fat = Sectores que ocupa cada FAT
* bdb_fat_count = Nº de FATs en el disco
*
* Estas 2 últimas están definidas en el header de FAT12.
*/
int rootlba = fatlba + (bdb_sectors_per_fat * bdb_fat_count);
En este sistema de archivos, una carpeta se representa como una sucesión de entradas de 32 bytes cada una, que definen el nombre de un archivo, sus atributos y la localización de su contenido dentro de la data section. Estos son los contenidos de una entrada, byte por byte:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
nombre
Nombre del archivo (8 bytes, rellenados con espacios)
Ejemplo: FILE . |
extension
Extensión del archivo (3 bytes, rellenados con espacios)
Ejemplo: TXT. |
atr
Atributos: 1 byte en el que cada bit define una propiedad.
Ejemplo: para un archivo de sistema en modo solo lectura, 00000101. |
_res
Byte reservado para el sistema
|
Cms
Milisegundos de la creación del archivo
|
Ctime
Hora, minutos y segundos de la creación del archivo
Ejemplo: 01100 100010 11100. |
||||||||||
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
Cdate
Fecha de creación
Ejemplo: 0000000 0000 00000. |
accessed
Fecha del último acceso, formateada igual que Cdate.
|
Clhigh
Primer cluster del archivo (solo sus primeros 8 bits)
Ejemplo: para el cluster nº 00001111 11110000, este valor sería 00001111. |
Mtime
Hora de modificación, formateada igual que Ctime.
|
Mdate
Fecha de modificación, formateada igual que Cdate.
|
Cllow
Primer cluster del archivo (solo sus últimos 8 bits)
Ejemplo: para el cluster nº 00001111 11110000, este valor sería 11110000. |
size
Tamaño del archivo en bytes
Ejemplo: para un archivo de 15 bytes, este valor sería 00000000 00000000 00000000 00001111. |
Puedes pasar el ratón por encima de la tabla para ver una descripción más detallada de cada elemento.
La carpeta raíz contiene muchas de estas entradas. Para ser exactos, contiene el número de entradas definido en la variable bdb_dir_entries_count, localizada en nuestro header. Si sigues la configuración del capítulo anterior, esta variable tendrá el valor 224, por lo que el directorio raíz ocupará exactamente 7168 bytes (224 * 32).
Secciones de FAT12: La sección de datos
Esta sección contiene el contenido de los archivos del disco, y está dividida en clusters, que son grupos de sectores contiguos. Se puede definir cuántos sectores ocupa cada cluster en la variable bdb_sectors_per_cluster, definida en el header. También podemos calcular el LBA de esta sección de la siguiente forma:
/**
* Recuerda:
* rootlba = Definida en el apartado anterior
*
* bdb_dir_entries_count = Entradas del directorio raíz
* bdb_bytes_per_sector = Bytes por sector
*
* Estás 2 últimas variables están definidas en el header.
*/
/**
* rootsize = Tamaño de la carpeta raíz en bytes
* rootsec = Tamaño de la carpeta raíz en sectores
*/
int rootsize = bdb_dir_entries_count * 32;
int rootsec = (rootsize + bdb_bytes_per_sector - 1) / bdb_bytes_per_sector;
/* datalba = LBA de la sección de datos */
int datalba = rootlba + rootsec;
Vamos a usar esta sección para consultar el contenido de un archivo. Por ejemplo, pongamos que el disco contiene en su raíz un archivo llamado ejemplo.txt y su contenido ocupa 1.500 bytes. En algún punto de la carpeta raíz encontraremos la siguiente entrada:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
'E' | 'J' | 'E' | 'M' | 'P' | 'L' | 'O' | ' ' | 'T' | 'X' | 'T' | 0x20 | 0x18 | -- | -- | |
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF |
-- | -- | 0x0000 | -- | -- | 0x001C | 0x000005DC |
Podemos ver que Clhigh tiene el valor 0x0000 y Cllow tiene el valor 0x001C. Si juntamos el número de 32 bits completo, nos da el siguiente valor:
Hexadecimal | Decimal |
---|---|
0x0000001C | 28 |
Este valor nos indica el cluster en el que se encuentra el archivo. Los clusters se pueden traducir directamente a LBA de forma muy sencilla:
int LBA = lba_de_la_data_section + ((cluster * sectores_por_cluster) - 2);
- Los sectores que ocupa cada cluster los tenemos en la variable bdb_sectors_per_cluster de nuestro header, que en nuestra configuración de disco es igual a 1.
- El cluster que queremos buscar es el 28 (0x1C).
- El LBA de la sección de datos lo hemos calculado al principio del apartado. Si has seguido la misma configuración de disco que el manual, será igual a 33.
Si hacemos la cuenta (33 + (28 * 1) = 61) sabremos que el primer sector del archivo está escrito en el sector nº 61 del disco. Pero en nuestro caso un sector son solo 512 bytes... ¿qué pasa con los archivos que pesan más de un sector? Pues, en ese caso, habría que consultar la FAT para saber dónde está el siguiente cluster del archivo.
Pongamos que la FAT de nuestro disco contiene las siguientes entradas:
0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B |
---|---|---|---|---|---|---|---|---|---|---|---|
0xFF0 | 0xFFF | 0x003 | 0x004 | 0x005 | 0xFFF | 0x007 | 0x008 | 0x009 | 0x00A | 0x00B | 0x00C |
0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 |
0x00D | 0xFFF | 0x00F | 0x016 | 0x011 | 0x012 | 0x013 | 0x014 | 0x015 | 0xFFF | 0x017 | 0xFFF |
0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23 |
0x019 | 0x01A | 0x01B | 0xFFF | 0x022 | 0x01E | 0x01F | 0x020 | 0x021 | 0xFFF | 0x023 | 0xFFF |
Las 2 primeras entradas están en verde porque son entradas reservadas. No indican el contenido de ningún cluster de la sección de datos, solamente varían en función de si el disco está particionado o no. Después, las entradas indican el contenido de un archivo de 4 clusters y otro de 8. Tras estos, podemos ver que el archivo que comienza en el cluster 0x0E, marcado en azul oscuro, está fragmentado.
Si seguimos su cadena de clusters, obtendremos la siguiente lista: 0xE, 0xF, 0x16, 0x17. El archivo ocupa 4 clusters que no son contiguos en la memoria, por eso decimos que está fragmentado. En los clusters que se encuentran en medio, encontramos los datos de otro archivo. Si seguimos, tras otro archivo que ocupa 4 clusters, llegamos al índice que buscábamos: el 0x1C.
El archivo que buscamos está marcado en azul claro y también está fragmentado. Si queremos leer su contenido tendremos que leer, en orden, los clusters 0x1C, 0x22 y 0x23. Lo que en nuestro disco equivale a leer los sectores 61, 67 y 68.
Estos 3 clusters suman en nuestro disco 1.536 bytes, pero nuestro archivo ocupa 1.500 bytes. Por eso, los últimos 36 bytes del cluster 0x23 tendrán el valor 0. Al leerlo, conviene consultar el tamaño del archivo en su entrada para asegurarnos de que leemos el número de bytes correcto.
Resumen
Hemos visto en qué consisten las secciones reservada, de FAT, de directorio raíz y de datos de FAT12. También hemos aprendido cómo calcular su posición en el disco y cómo usarlas para leer el contenido de un archivo. En el proceso, hemos aprendido sobre la fragmentación de disco y los sistemas de direccionamiento LBA y CHS.
En el siguiente capítulo aprenderemos cómo leer parámetros del disco y cómo leer sus sectores hacia la memoria. Para ello, necesitarás tener conocimientos mínimos de assembly (como los explicados en el capítulo 1) y del sistema de archivos FAT12 (como los tratados en este capítulo).