Documentos de Académico
Documentos de Profesional
Documentos de Cultura
FAT AL
DESNUDO
FAT12
FAT16
FAT32
INDICE:
> Introduccin
> Sector de arranque (Boot Sector) y BIOS Parameter Block (BPB)
> Estructura del sector de arranque (Boot Sector) y BPB
> Campos especficos de FAT12/FAT16
> Campos especficos de FAT32
> Notas sobre los campos de la FAT
> Estructura de datos de la FAT
> Determinacin del tipo de FAT
> Clculos con clusters
...
> Estructura de directorios en la FAT
> Formatos de fecha y hora
> Nombres largos de archivos
Apndices:
> Anlisis de una tarjeta Flash de 1Gb con FAT32 (WinXP)
> Glosario
> Introduccin:
Este documento se basa en el documento titulado FAT: General Overview of On-Disk
Format, un withe paper de la empresa Microsoft. El autor del presente documento no
garantiza la fidelidad de lo expuesto aqu, aunque se ha tratado de ser lo mas riguroso
posible.
byte[3]
3 3 2 2 2 2 2 2
1 0 9 8 7 6 5 4
byte[2]
2 2 2 2 1 1 1 1
3 2 1 0 9 8 7 6
byte[1]
1 1 1 1 1 1 0 0
5 4 3 2 1 0 9 8
byte[0]
0 0 0 0 0 0 0 0
7 6 5 4 3 2 1 0
Zona
Zona
Zona
Zona
[Volver al NDICE]
Utilizaremos esta imagen como ejemplo, y la analizaremos bit a bit a medida que
vayamos conociendo de que se trata cada uno de ellos.
Campo: BS_jmpBoot
Offset (Byte): 0
Tamao (Bytes): 3
Descripcin: Instruccin de salto al cdigo de arranque. Este campo tiene una de las
siguientes formas:
jmpBoot[0] = 0xEB, jmpBoot[1] = 0x??, jmpBoot[2] = 0x90
o
jmpBoot[0] = 0xE9, jmpBoot[1] = 0x??, jmpBoot[2] = 0x??
0x?? significa que esta permitido cualquier valor de 8 bits. Estos tres bytes componen
una instruccin de salto incondicional Intel x86 (jump) que apunta al inicio del cdigo
de arranque del sistema operativo. Generalmente, este cdigo ocupa el resto del
espacio siguiente al BPB en el sector de arranque, posiblemente otros sectores.
Cualquiera de las dos formas son aceptadas, pero JmpBoot[0] = 0xEB es el formato
mas frecuentemente utilizado.
En nuestro ejemplo, encontramos los bytes EB 3C 90 , lo que significa que se trata
de la primera de las alternativas.
Campo: BS_OEMName
Offset (Byte): 3
Tamao (Bytes): 8
Campo: BPB_BytsPerSec
Offset (Byte): 11
Tamao (Bytes): 2
Descripcin: Nmero de bytes por sector. Puede tomar alguno de los valores
siguientes: 512, 1024, 2048 o 4096. Si buscamos el mximo de compatibilidad con
sistemas antiguos, debemos utilizar el valor 512. Existen muchos equipos viejos que
manejan FAT de 512 bytes por sector por hard (hard wired) y no chequean este
campo para determinar el nmero correcto de bytes de cada sector. Todos los
sistemas operativos de Microsoft aceptan 1024, 2048, y 4096.
Siguiendo con el anlisis del diskette, nos encontramos con los bytes 00 02. Como
mencionamos antes, al estar en formato little endian, el byte mas significativo es el
ultimo, por lo que debemos interpretarlo como 02 00 (hexadecimal), que
corresponde al binario 0000 0010 0000 0000 o al decimal 512. Nuestro diskette
contiene 512 bytes por sector.
Campo: BPB_SecPerClus
Offset (Byte): 13
Tamao (Bytes) : 1
Descripcin: Nmero de sectores por cluster. Este valor debe ser una potencia de 2
mayor a 0. Los valores permitidos son 1, 2, 4, 8, 16, 32, 64, y 128. Hay que destacar
que nunca se debe utilizar un valor que multiplicado por BPB_BytsPerSec de un
resultado mayor a 32K (BPB_BytsPerSec * BPB_SecPerClus 32 * 1024).
Es un error pensar que valores mayores son correctos. Si se eligen valores cuyo
resultado sea superior a 32K muchos sistemas no funcionaran de forma correcta.
Algunos sistemas permiten valores de 64K por cluster, pero no funcionan
adecuadamente como volmenes FAT.
En el ejemplo anterior, este byte es 01, por lo que nuestro diskette contiene 1 sector
por cluster.
BPB_BytsPerSec * BPB_SecPerClus 32 * 1024 nos da un valor de 2 * 1 * 1024 = 2048,
que es valido, por ser menor que 32K (32768).
Tamao (Bytes) : 2
Campo: BPB_NumFATs
Offset (Byte): 16
Tamao (Bytes) : 1
Tamao (Bytes) : 2
Campo: BPB_TotSec16
Offset (Byte): 19
Tamao (Bytes) : 2
Descripcin: Este campo contiene en 16 bits la cuenta total de sectores del volumen
(FAT12 o FAT16). Estn incluidas en la cuenta la totalidad de sectores de todas las
zonas. Este campo puede ser 0, en cuyo caso BPB_TotSec32 (ver mas adelante) no
debe ser 0.
En el diskette que estamos analizando vemos los bytes 40 0B, que debemos
interpretar como "0B 40" que en binario es 0000 1011 0100 0000 o 2880 en decimal.
2880 * 512 = 1474560 es el tamao total del diskette.
Campo: BPB_Media
Offset (Byte): 21
Tamao (Bytes) : 1
Descripcin: Especifica el tipo de medio. "F8" es el valor que identifica a los medios
no removibles. Los medios removibles en general se especifican como "F0". Una
cuestin importante es que este valor debe tambin ser colocado en byte bajo de la
entrada FAT [0] . La lista de valores posibles es la siguiente:
Nuestro diskette tiene el valor "F0" en este byte, que es el valor genrico para un
medio removible.
Campo: BPB_FATz16
Offset (Byte): 22
Tamao (Bytes) : 2
Campo: BPB_SecPerTrk
Offset (Byte): 24
Tamao (Bytes) : 2
Descripcin: En aquellos soportes que tienen una "geometra" compuesta por pistas,
cabezas y cilindros, tales como los discos duros, este valor especifica el numero de
sectores por pista. Es utilizado por ejemplo por la int13 de MS-DOS.
Nuestro diskette tiene los bytes 12 00, que debemos interpretar como "00 12" y que
en binario es 0000 0000 0001 0020 o 18 en decimal. Este diskette tiene 18 sectores
de 512 bytes por pista.
Si multiplicamos 18 * 512 * 80 (pistas) * 2 (cabezas), volvemos al tamao total de
bytes del disco, 1474560.
Campo: BPB_NumHeads
Offset (Byte): 26
Tamao (Bytes) : 2
Campo: BPB_HiddSec
Offset (Byte): 28
Tamao (Bytes) : 4
Campo: BPB_TotSec32
Offset (Byte): 32
Tamao (Bytes) : 4
Descripcin: Este campo contiene en 32 bits la cuenta total de sectores del volumen
(FAT32). Estn incluidas en la cuenta la totalidad de sectores de todas las zonas. Este
campo puede ser 0, en cuyo caso BPB_TotSec16 (ver mas arriba) no debe ser 0. En
volmenes FAT32 no debe ser 0. En volmenes FAT12/FAT16 este campo contiene el
numero de sectores solamente cuando BPB_TotSec16 es 0 y el numero de sectores
es mayor a 65535.
En este diskette tenemos 00 00 00 00, debido a que es un volumen con
FAT12/FAT16 con menos de 65536 sectores.
Todos los campos vistos hasta aqu son comunes a las implementaciones de
FAT12/FAT16/FAT32. Los que vienen a continuacin son propios de los sistemas
FAT12/FAT16 o de los FAT32.
[Volver al NDICE] [Saltar a Campos especficos de FAT32]
Offset (Byte): 36
Tamao (Bytes) : 1
Descripcin: Numero de drive para la interrupcin 13. Este campo le indica a MS-DOS
si se trata de un diskette ("00") o de un disco duro ("80").
En nuestro ejemplo, al tratarse de un diskette tenemos 00.
Campo: BS_Reserved1
Offset (Byte): 37
Tamao (Bytes) : 1
Campo: BS_BootSig
Offset (Byte): 38
Tamao (Bytes) : 1
Campo: BS_VolID
Offset (Byte): 39
Tamao (Bytes) : 4
Descripcin: Estos cuatro bytes conforman el numero de serie del soporte. Junto con
BS_VolLab sirven para identificar un soporte en particular. Se obtiene a partir de la
fecha y la hora en que se realizo el formato del disco. (Ms adelante intentar publicar
aqu el algoritmo utilizado).
Campo: BS_VolLab
Offset (Byte): 43
Tamao (Bytes) : 11
Descripcin: Etiqueta electronica del volumen. Es el nombre que uno puede ver
cuando accede al volumen desde Windows, por ejemplo. En aquellos soportes que no
se ha escrito o cambiado el nombre, deberan figurar los bytes "4E 4F 20 4E 41 4D
45 20 20 20 20" ("NO NAME ") .
El diskette que estamos estudiando tiene la cadena "NO NAME "
Campo: BS_FilSysType
Offset (Byte): 54
Tamao (Bytes) : 8
Descripcin: Una cadena de texto, con 8 caracteres de longitud. Debe ser "FAT12 ",
"FAT16 " o "FAT
". Muchos programadores suponen que esta etiqueta sirve para
identificar el tipo de volumen, pero sin embargo no es as, ya que este campo no es
parte del BPB.
En este diskette tenemos la cadena "FAT12 "
Aqu terminan los campos especficos para los volmenes con FAT12/FAT16.
[Volver al NDICE]
Offset (Byte): 36
Tamao (Bytes) : 4
Campo: BPB_ExtFlags
Offset (Byte): 40
Tamao (Bytes) : 2
Campo: BPB_FSVer
Offset (Byte): 42
Tamao (Bytes) : 2
Campo: BPB_RootClus
Offset (Byte): 44
Tamao (Bytes) : 4
Descripcin: Este es el numero de cluster del primer cluster del directorio raz.
Normalmente (pero no necesariamente) es 2.
Campo: BPB_FSInfo
Offset (Byte): 48
Tamao (Bytes) : 2
Campo: BPB_BkBootSec
Offset (Byte): 50
Tamao (Bytes) : 2
Campo: BPB_Reserved
Offset (Byte): 52
Tamao (Bytes) : 12
Descripcin: Reservados para futuras expansiones. Estos bytes deberan ser dejados
en 0.
Campo: BS_DrvNum
Offset (Byte): 64
Tamao (Bytes) : 1
Descripcin: Numero de drive para la interrupcin 13. Este campo le indica a MS-DOS
si se trata de un diskette ("00") o de un disco duro ("80").
Campo: BS_Reserved1
Offset (Byte): 65
Tamao (Bytes) : 1
Campo: BS_BootSig
Offset (Byte): 66
Tamao (Bytes) : 1
Campo: BS_VolID
Offset (Byte): 67
Tamao (Bytes) : 4
Descripcin: Estos cuatro bytes conforman el numero de serie del soporte. Junto con
BS_VolLab sirven para identificar un soporte en particular. Se obtiene a partir de la
fecha y la hora en que se realizo el formato del disco. (Ms adelante intentar publicar
aqu el algoritmo utilizado).
Campo: BS_VolLab
Offset (Byte): 71
Tamao (Bytes) : 11
Descripcin: Etiqueta electrnica del volumen. Es el nombre que uno puede ver
cuando accede al volumen desde Windows, por ejemplo. En aquellos soportes que no
se ha escrito o cambiado el nombre, deberan figurar los bytes "4E 4F 20 4E 41 4D
45 20 20 20 20" ("NO NAME ") .
Campo: BS_FilSysType
Offset (Byte): 82
Tamao (Bytes) : 8
Descripcin: Una cadena de texto, con 8 caracteres de longitud. Debe ser "FAT32
Esta etiqueta no sirve para identificar el tipo de volumen, ya que este campo no es
parte del BPB.
".
El resultado debe ser redondeado hacia arriba. Volviendo a la estructura del diskette
bajo anlisis, tenemos que BPB_RootEntCnt = 224 y BPB_BytsPerSec = 512, por
lo que
Es decir, en nuestro diskette el directorio raz utiliza 15 sectores de 512 bytes cada
uno, o sea, 7680 bytes. En los volmenes con FAT32, BPB_RootEntCnt siempre es 0,
por lo tanto RootDirSectors tambin es 0.
El comienzo de la regin de datos, es decir, el primer sector del segundo cluster, se
calcula de la siguiente manera si se trata de un volumen FAT12/FAT16:
FirstDataSector = 1 + ( 2 * 9 ) + 15
FirstDataSector = 1 + 18 + 15
FirstDataSector = 34
calculo del tipo de FAT. Mantener el numero de clusters a una "distancia" mayor a 16
unidades de los limites (4.085 o 65.525) es una buena idea para que nuestro volumen
sea reconocido correctamente en la mayor cantidad de sistemas.
Si al numero CountOfClusters le sumamos 1, obtenemos el numero de clusters
mximo que es valido. Si le sumamos 2, obtenemos el numero de total de clusters,
incluidos los dos reservados.
Otro dato que podemos necesitar conocer es la posicin de un cluster N dentro de la
FAT. Esto es bastante simple de realizar en FAT16 y FAT32, y algo mas complejo en
FAT12. Veamos:
FAT16:
ThisFATSecNum = BPB_ResvdSecCnt + ( ( N * 2 ) / BPB_BytsPerSec )
ThisFATEntOffset = RESTO ( ( N * 2 ) / BPBBytsPerSec )
FAT12:
Este calculo, como dijimos, es mas complicado debido a que los 12 bits de la direccin
son un byte y medio, lo que dificulta las cuentas.
FATOffset = N + (N/2)
Campo: DIR_Name
Offset (Bytes): 0
Tamao (Bytes): 11
Nombre corto del directorio. Se divide en dos partes, una de 8 caracteres para el
nombre, y otra de 3 para la extensin. Ambas deben rellenarse con espacios al final.
DIR_Name[0] no pueden ser un espacio ("20" o 32 en decimal). El "." entre el
nombre y la extensin es implcito, y no esta almacenado en la estructura. No se
permiten caracteres en minsculas en DIR_Name debido a que pueden ser especficos
de algn idioma.
Si DIR_Name[0] = "E5", esta entrada esta libre, es decir, no hay archivo o
directorio.
Si DIR_Name[0] = "00", esta entrada esta libre (igual que si fuera "E5") y no hay
entradas despus de esta. Por lo tanto, si estamos recorriendo la estructura del
directorio y encontramos esta entrada, no tiene sentido seguir despus de este punto.
Si DIR_Name[0] = "05", el nombre de este archivo es "E5". Esto es as por que "E5"
es un carcter valido en nombres de archivos escritos con caracteres KANJI, y de esta
manera se evita que sistemas basados en ese juego de caracteres interpreten la
entrada del directorio como vaca.
Campo: DIR_Attr
Offset (Bytes): 11
Tamao (Bytes): 1
Atributos especficos del archivo. Los dos bites altos de este byte se deben dejar en 0 y
nunca modificarse.
ATTR_READ_ONLY ("01"): Significa que el archivo es de solo lectura.
ATTR_HIDDEN ("02"): No debe mostrarse este archivo en un listado normal del
contenido de ese directorio.
ATTR_SYSTEM ("04"): Se trata de un archivo perteneciente al sistema operativo.
ATTR_VOLUME_ID ("08"): Debera haber solo un archivo en el volumen con este
atributo en 1, y es el directorio raz. DIR_FstClusHI y DIR_FstClusLO (ver mas
abajo) deben ser cero para la etiqueta del volumen.
ATTR_DIRECTORY ("10"): Indica que se trata de un directorio y no de un archivo.
ATTR_ARCHIVE ("20"): Atributo pensado para las copias de seguridad. Debe ponerse
a 1 cuando el software manejador de la FAT crea, renombra o escribe en un archivo.
Las utilidades de backup pueden basarse en este bit para realizar sus tareas de
respaldo, y ponerlo en 0 para indicar que ya fueron resguardados.
ATTR_LONG_NAME: ATTR_READ_ONLY , ATTR_HIDDEN , ATTR_SYSTEM y
ATTR_VOLUME_ID en 1. Esta combinacin de bits indican que el "archivo" es en
realidad parte del nombre largo de otro archivo. Volveremos sobre este tema mas
adelante.
Campo: DIR_NTRes
Offset (Bytes): 12
Tamao (Bytes): 1
Campo:
DIR_CrtTimeTenth
Offset (Bytes): 13
Tamao (Bytes): 1
Milisegundos de la hora en que se creo el archivo. Este campo en realidad contiene las
dcimas de segundos. La granularidad de los segundos almacenados en
DIR_CrtTime2 es de dos segundos, por lo que este campo puede contener valores
entre 0-199 .
Campo: DIR_CrtTime
Offset (Bytes): 14
Tamao (Bytes): 2
Campo: DIR_CrtDate
Offset (Bytes): 16
Tamao (Bytes): 2
Tamao (Bytes): 2
Fecha en la que se accedi por ultima vez el archivo, ya sea para escribir en el o para
leerlo. En el caso de una escritura, este valor debe ser el mismo que el almacenado en
DIR_WrtDate. No se guarda la hora del ultimo acceso.
Campo: DIR_FstClusHI
Offset (Bytes): 20
Tamao (Bytes): 2
Parte alta de la palabra de 32 bits que contiene el primer cluster del archivo. Siempre
es cero en las FAT12 o FAT16.
Campo: DIR_WrtTime
Offset (Bytes): 22
Tamao (Bytes): 2
Campo: DIR_WrtDate
Offset (Bytes): 24
Tamao (Bytes): 2
Campo: DIR_FstClusLO
Offset (Bytes): 26
Tamao (Bytes): 2
Parte baja de la palabra de 32 bits que contiene el primer cluster del archivo.
Campo: DIR_FileSize
Offset (Bytes): 28
Tamao (Bytes): 4
Cuando se crea un directorio (un archivo con ATTR_DIRECTORY en 1), se debe poner
DIR_FileSize en cero. El tamao de los directorios se calcula siguiendo su cadena de
clusters hasta la marca EOC. Un cluster es asignado al directorio (a menos que se
trate de una FAT12 o FAT16), y se deben apuntar DIR_FstClusLO y DIR_FstClusHI
al numero del cluster, y poner EOC en la entrada correspondiente de la FAT. A
continuacin, se ponen todos los bytes de ese cluster en cero. Si se trata del directorio
raz, no se crean las entradas "." y "..".
En caso de no ser el directorio raz hay que crear dos entradas especiales en las
primeras dos entradas de 32 bits del directorio, con DIR_Name = ".
"y
DIR_Name = "..
". DIR_FileSize es cero en ambas entradas. Los campos de
fecha y hora son iguales a los del directorio que acabamos de crear.
Para terminar, debemos poner en la entrada "." el campo DIR_FstClusLO y
DIR_FstClusHI valores iguales a los del directorio que acabamos de crear. Y en ".."
ponemos en los campos DIR_FstClusLO y DIR_FstClusHI el valor del directorio
"padre". Si se trata del directorio raz, ponemos cero.
Resumiendo: La entrada "." es un directorio que se apunta a si misma, y la entrada ".."
es un directorio que apunta al directorio padre (cero si su "padre" es el directorio raz)
")
"
Ahora, veamos los datos que se pueden calcular con esta informacin:
RootDirSectors: Es el numero de sectores ocupados por el directorio raz: siempre
es 0 para FAT32.
FirstDataSector = BPB_ResvdSecCnt + ( BPB_NumFATs * BPB_FATs32 ) = 38 + ( 2 *
1961 ) = 3960
DataSec = BPB_TotSec32 - (BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz32) ) =
2011917 - ( 38 + ( 2 * 1961 = 2.007.957
CountOfClusters = DataSec / BPB_SecPerClus = 2007957 / 8 = 250994. Si
CountOfClusters > 65524, el volumen es FAT32, lo cual es correcto.