Los archivos tar – Como funcionan y como extraerlos sin tener tar

Los archivos tar se diseñaron para utilizarse en cintas de copias. Básicamente son bloques de 512k uno tras otro siguiendo este patrón:

cabecera archivo1 [512]
– contenido archivo1 [512]
– contenido archivo1 [512]
– contenido archivo1 [512]
cabecera archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
– contenido archivo2 [512]
cabecera archivo3 [512]
– contenido archivo3 [512]
cabecera archivo4 [512]
– contenido archivo4 [512]
– contenido archivo4 [512]
– …

Como puede verse el contenido irá en bloques de 512k tras la cabecera (tambien de 512k) del archivo que se empaqueta. En la cabecera se añade el tamaño del archivo de modo que este puede ocupar más o menos bloques de 512 tras la cabecera. Si el tamaño del archivo es menor de 512k entonces ocupará el contenido solamente 1 bloque, si es más grande pues va ocupando más bloques dejando con valores nulos lo sobrante.

Los archivos tar suelen verse con extensión “tar” y se usa normalmente la herramienta “tar” para empaquetar y desempaquetar.
Se trata de un standard de formato de archivo muy utilizado en el mundo GNU/Linux y lo veremos con extensiones como por ejemplo tar.gz ya que aparte de empaquetarse luego se comprimen en gzip por ejemplo.

Hagamos una prueba
de como empaquetar (sin comprimir) 5 archivos que generamos para la ocasión:

$ mkdir archivostar
$ cd archivostar
$ echo "hola mundo 1" > hola1.txt
$ echo "hola mundo 2" > hola2.txt
$ echo "hola mundo 3" > hola3.txt
$ echo "hola mundo 4" > hola4.txt
$ echo "hola mundo 5" > hola5.txt
$ tar cf hola.tar hola1.txt hola2.txt hola3.txt hola4.txt hola5.txt 

Obtendremos un nuevo archivo llamado hola.tar que es el que contiene el resto de archivos en su interior.

Este script realizado en un par de horas puede servir para conocer cuantos archivos contiene un tar y que nombre tienen.

#!/bin/bash

file=$1
blockhead=512
dblock=1024
position=0

for i in $(seq 1 100);
do
        xxd -s $position -g 1 -l 100 -c 100 $file | rev | cut -d " " -f 1 | rev
        let positionsize=position+124
        sizefile=$(printf "%d" $(dd skip=$positionsize count=12 bs=1 status=none if="$file" | hexdump -e '12/1 "%c"'))

        if [[ $sizefile -lt 512 ]]
        then
                let position=dblock+position
        else
                rbf=$(echo "($sizefile/$blockhead)" | bc)
                resto=$(echo "$sizefile%512" | bc)
                #resto=$((10#$resto))
                if [[ $resto -eq 0 ]]
                then
                        let position=blockhead+position+sizefile
                else
                        ns=$(echo "($rbf*$blockhead)" | bc)
                        let position=blockhead+position+ns+blockhead
                fi
        fi

done

Ese mismo script en bash puede modificarse para extraer los archivos sin mucha dificultad, es decir, podemos utilizarlo si no tenemos tar en algún entorno.

Sigamos viendo como funciona el tema.

Cabecera de un tar:

filename [100]
mode [8]
uid [8]
gid [8]
fileSize [12]
lastModification [12]
checksum [8]
typeFlag [1]
linkedFileName [100]
ustarIndicator [6]
ustarVersion [2]
ownerUserName [32]
ownerGroupName [32]
deviceMajorNumber [8]
deviceMinorNumber [8] 
filenamePrefix [155]
padding [12]

Usando dd podemos extraer los datos de la cabecera de por ejemplo el archivo1:

dd skip=0 count=100 bs=1 status=none if=hola.tar | hexdump -e '100/1 "%c" "\n"'
dd skip=100 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=108 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=116 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=124 count=12 bs=1 status=none if=hola.tar | hexdump -e '12/1 "%c" "\n"'
dd skip=136 count=12 bs=1 status=none if=hola.tar | hexdump -e '12/1 "%c" "\n"'
dd skip=148 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=156 count=1 bs=1 status=none if=hola.tar | hexdump -e '1/1 "%c" "\n"'
dd skip=157 count=100 bs=1 status=none if=hola.tar | hexdump -e '100/1 "%c" "\n"'
dd skip=257 count=6 bs=1 status=none if=hola.tar | hexdump -e '6/1 "%c" "\n"'
dd skip=263 count=2 bs=1 status=none if=hola.tar | hexdump -e '2/1 "%c" "\n"'
dd skip=265 count=32 bs=1 status=none if=hola.tar | hexdump -e '32/1 "%c" "\n"'
dd skip=297 count=32 bs=1 status=none if=hola.tar | hexdump -e '32/1 "%c" "\n"'
dd skip=329 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=337 count=8 bs=1 status=none if=hola.tar | hexdump -e '8/1 "%c" "\n"'
dd skip=345 count=155 bs=1 status=none if=hola.tar | hexdump -e '155/1 "%c" "\n"'
dd skip=500 count=12 bs=1 status=none if=hola.tar | hexdump -e '12/1 "%c" "\n"'

La mayoría de datos estarán en octal y tendremos que convertirlos si queremos entenderlos.

Explicación de que contenidos extraemos:

filename
dd skip=0 count=100 bs=1 status=none if=hola.tar | hexdump -e ‘100/1 “%c” “\n”‘

mode (644 por ejemplo. en octal. stat hola.tar para verlo y ver tambien el uid y gid)
dd skip=100 count=8 bs=1 status=none if=hola.tar | hexdump -e ‘8/1 “%c” “\n”‘

uid (El valor en octal. 1750 por ejemplo son 1000 en decimal. “id -u user” para ver el uid del usuario.
dd skip=108 count=8 bs=1 status=none if=hola.tar | hexdump -e ‘8/1 “%c” “\n”‘

gid (El valor en octal. 1750 por ejemplo son 100 en decimal. “id -g user” para ver el gid del usuario.
dd skip=116 count=8 bs=1 status=none if=hola.tar | hexdump -e ‘8/1 “%c” “\n”‘

filesize (El valor en octal. 14 = 13 bytes. du -b hola1.txt para ver su tamaño por ejemplo)
dd skip=124 count=12 bs=1 status=none if=hola.tar | hexdump -e ’12/1 “%c” “\n”‘

lastModification (EL valor en octal se pasa a decimal y se obtiene el tiempo Epoch – tiempo unix. Podemos convertirlo: echo “13231210625” | date)
dd skip=136 count=12 bs=1 status=none if=hola.tar | hexdump -e ’12/1 “%c” “\n”‘

checksum (este tiene miga y paso de comentarlo.)
dd skip=148 count=8 bs=1 status=none if=hola.tar | hexdump -e ‘8/1 “%c” “\n”‘

typeFlag (1 byte. Mirar typeFlag lista de valores posibles)
dd skip=156 count=1 bs=1 status=none if=hola.tar | hexdump -e ‘1/1 “%c” “\n”‘

Y así con todos veremos que obtenemos el valor en octal. Sobre typeFlag aquí una chuleta de los valores posibles que tendriamos que obtener (en octal y luego lo pasamos a decimal):

typeFlag

'0' or (ASCII NUL) 	Normal file
'1' 	Hard link
'2' 	Symbolic link
'3' 	Character special
'4' 	Block special
'5' 	Directory
'6' 	FIFO
'7' 	Contiguous file
'g' 	global extended header with meta data (POSIX.1-2001)
'x' 	extended header with meta data for the next file in the archive (POSIX.1-2001)
'A'–'Z' 	Vendor specific extensions (POSIX.1-1988)
All other values 	reserved for future standardization

Links de interés por si andas deseando crear un programa que empaquete y desempaquete archivos tar:

Nota: Si la cinta de backup se paraba o terminaba no perdías todo ya que como vemos esto se almacena linealmente. Siempre puedes recuperar los últimos x archivos que se han grabado ya que van en bloques de 512k.

Deja un comentario