viernes, 14 de septiembre de 2007

Recuperando archivos corruptos

Muchas veces tenemos algún archivo en CD o DVD que no podemos copiar a disco porque cierta parte del mismo está corrupta. Tanto desde el escritorio en KDE como utilizando el comand cp en la consola el archivo se copia hasta el bloque en que no se puede leer y el resto se descarta.

No siempre que haya un defecto en el archivo éste queda inusable... en el caso de AVIs, MP3 y seguramente muchos otros el defecto simplemente se verá o se oirá por un instante y la reproducción continuará sin mayores problemas.

En Windows existen varios programas (ninguno libre, que yo sepa) que pueden recuperar estos archivos, obviamente rellenando las zonas que no se puedan leer. Estos procesos son generalmente poco configurables y muchas veces demoran demasiado por lo que uno termina aburriéndose y cancelándolos.

Resulta que googleando un pocó encontré que esto se puede hacer muy fácilmente con la añeja herramienta dd de Linux. Es muy fácil ajustar también el grado de recuperación/velocidad que se quiere usar.

El comando necesario es:

dd bs=2K if=ruta_archivo_entrada of=ruta_archivo_salida conv=noerror,sync



La herramienta dd se utiliza generalmente para hacer copias de dispositivos completos o también secciones importantes de éstos (como el MBR en el disco duro). En este caso vamos a utilizarla para copiar archivos reales de un sistema de archivos a otro. En realidad en Linux no hay diferencia: tanto un dispositivo como un archivo real en disco son en fin archivos en nuestro filesystem.

Este comando va a leer y escribir bloques de 2K = 2048 bytes de datos (si no se especifica bs se utiliza el valor por defecto de 512 bytes) desde el archivo origen (if) hacia el archivo destino (of). Sin opciones adicionales la copia se detiene al encontrar un error de lectura y el archivo queda truncado. Utlizando las opción conv=noerror,sync en la llamada se hace que cuando dd encuentra un error de lectura en un bloque particular el resto del bloque se rellene con carácteres nulos. Utilizando un tamaño de bloque más grande la copia se hace más rápidamente pero cada vez que se encuentra un error en un bloque, el resto del éste es ignorado. Bloques más pequeños minimizan la pérdida de datos, pero hacer la copia con un tamaño de bloque menor consume más tiempo.

Siempre que ocurra un error de lectura se imprime el mensaje de error correspondiente en stderr, junto con el estado actual del proceso. Por ejemplo:

dd: reading `/media/cdrom0/Se7en.1995.DVDRip.XviD-FreeGuy-CD1.avi': Input/output error
358586+704 records in
359290+0 records out
735825920 bytes (736 MB) copied, 532.963 seconds, 1.4 MB/s



El valor para 'records in' es la cantidad de bloques completos leidos con éxito seguida de la cantidad de bloques con error de lectura. El valor para 'records out', como ya suponen, es la cantidad de bloques escritos completos escritos exitosamente seguida de la cantidad de bloques en los que ocurrió un error de escritura. Estas cantidades corresponden con el tamaño de bloque bs especificado en la llamada al comando, como es fácil comprobar con la cantidad de bytes copiados desplegada.

También es posible hacer que dd imprima el estado actual (siempre en la salida estandar de error) en cualquier momento enviándole la señal SIGUSR1, de la siguiente manera:

$ kill -USR1 PID_DEL_PROCESO



Esto es útil para tener una idea sobre el avance de la copia si no han ocurrido errores.

Saludos!

No hay comentarios: