Notas: estructura del formato de archivos TAR

Ayer en Twitch tocó desarrollo de sistemas operativos y empecé a trabajar en la implementación de un driver de sistema de archivos TAR para mi sistema operativo. El objetivo es poder incrustar en la distribución un archivo TAR que contenga un ramdisk y montarlo al arrancar el sistema para poder acceder a más archivos (por ejemplo, recursos gráficos, archivos de texto…)

Este es un sistema parecido al que usan muchos otros sistemas operativos cuando introduces un CD de instalación al encender la máquina. El cargador de arranque del CD carga el ejecutable con el programa principal, pero los recursos, como el entorno LiveCD de Linux, vive en un archivo compacto que se carga en memoria para dar la apariencia de un entorno real.

Elegí el formato TAR porque es un formato muy sencillo de comprender. No aplica compresión, esencialmente cuando creas un archivo TAR estás concatenando el contenido de todos los archivos que quieras incorporar en el archivo. Cada archivo lleva al principio una cabecera que contiene sus metadatos: nombre, tamaño, tipo de archivo, permisos…

Un archivo TAR está dividido en bloques. Un bloque tiene 512 bytes. O sea, los primeros 512 bytes del archivo (bytes 0 a 511) forman el bloque 0. Los siguientes 512 (bytes 512 a 1023) forman el bloque 1. Los siguientes 512 (bloque 1024 a 1535) forman el bloque 2… todos los componentes de un TAR están alineados respecto a un bloque. Por ejemplo, la cabecera de un archivo siempre empieza al principio de un bloque y ocupa todo el bloque. Si sobra sitio después de cada bloque, se rellena con ceros para que la siguiente sección empiece al principio del siguiente bloque.

Entonces, ¿de qué manera está compuesto un archivo TAR? Para cada uno de los archivos que haya dentro, se vuelca un bloque con los metadatos y luego cero, uno o varios bloques con el contenido del archivo. Esto se repite en bucle para cada archivo que haya en el TAR. Un TAR no tiene metadatos generales: haz un hexdump de un TAR (no comprimido) que tengas a mano y verás que empieza directamente con los metadatos del primer archivo. Al final del archivo TAR hay dos bloques en blanco (o sea, 1 KB lleno de ceros).

La estructura de metadatos es binaria y puede ser accedida a través de registros. El manual de usuario de GNU TAR tiene un capítulo dedicado a la especificación del formato también, y ahí se encuentra un ejemplo de cómo sería la estructura de datos para acceder a los metadatos:


struct posix_header
{                              /* byte offset */
  char name[100];               /*   0 */
  char mode[8];                 /* 100 */
  char uid[8];                  /* 108 */
  char gid[8];                  /* 116 */
  char size[12];                /* 124 */
  char mtime[12];               /* 136 */
  char chksum[8];               /* 148 */
  char typeflag;                /* 156 */
  char linkname[100];           /* 157 */
  char magic[6];                /* 257 */
  char version[2];              /* 263 */
  char uname[32];               /* 265 */
  char gname[32];               /* 297 */
  char devmajor[8];             /* 329 */
  char devminor[8];             /* 337 */
  char prefix[155];             /* 345 */
                                /* 500 */
};

Un pequeño detalle es que, para mejorar la compatibilidad con procesadores que sean big endian, se decidió que el formato TAR guardaría los números directamente en ASCII, en vez de codificados como binario. O sea, que el número 1000 no se guarda convertido a binario, porque entonces habría que saber si el sistema es big endian (0x03 0xE8) o little endian (0xE8 0x03). En su lugar, se guarda tal cual en ASCII, codificado como octal («1750», que es 1000 en base 8). Al final de cada cadena de estas, hay un caracter \0 de fin de string. Es posible convertir entre una de estas «cadenas octales» y número int normal.

Después del bloque de metadatos, el siguiente bloque contiene el contenido del archivo. Puede ocupar uno, dos, los bloques que sea. El último bloque del archivo también tiene ceros al final del bloque si sobra espacio, para que el siguiente archivo empiece al principio del siguiente bloque.

El campo typeflag de la estructura de metadatos indica el tipo de archivo: archivo regular, directorio… esto es importante porque en las carpetas se guarda su nombre y sus permisos, pero como son carpetas, el tamaño es 0 y no tiene contenido. Después de un bloque de metadatos de una carpeta, viene otro bloque de metadatos que describe el siguiente archivo que haya en el archivador TAR.

Además de eso, TAR es capaz de representar enlaces simbólicos e incluso archivos de dispositivo, ya que tiene campos para guardar el devmajor y el devminor.