| Autor: Udo Rader |
| Erstellungsdatum: 2003-08-11 Letzte Änderung: 2005-10-17 |
Der Alptraum jedes Systemadministrators: Man hat ein Backup von wichtigen Dateien erstellt, will
diese später wieder entpacken - aber das tar-Archiv ist aus unerfindlichen Gründen defekt ...
Genau das ist mir einmal (und hoffentlich nie wieder) passiert und ich habe seeeeehr viel
Zeit dafür gebraucht, diese Dateien (oder zumindest einen brauchbaren Teil davon) aus dem
Archiv herauszubekommen.
Bevor wir loslegen, hier noch ein paar notwendige Annahmen, um die Sache klarer zu gestalten:
- tar bedeutet GNU-tar
- das Archiv wurde auch bzip2 komprimiert
(wenn auch der Kompressionstyp im Endeffekt nebensächlich ist)
- das tar-Archiv ist an einem zugänglichen Platz verfügbar
(GNU-)tar hat ja selbst einige Optionen, welche von sich behaupten, bei der Wiederherstellung
von defekten Daten behilflich zu sein (Sie werden meinen Sarkasmus verstehen, wenn Sie weiterlesen ...)
Aber, überprüfen wir zuerst, was das genaue Problem ist:
% tar xjf the_bad_bad_backup.tar.bz2
bzip2: Data integrity error when decompressing.
Input file = (stdin), output file = (stdout)
It is possible that the compressed file(s) have become corrupted.
You can use the -tvv option to test integrity of such files.
You can use the `bzip2recover' program to *attempt* to recover
data from undamaged sections of corrupted files.
tar: 56 garbage bytes ignored at end of archive
tar: Unexpected EOF in archive
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
|
Das zeigt uns also, daß ich bzip2recover "to *attempt* to
recover data from undamaged sections verwenden soll. Klingt also nicht zu schlecht, oder?
Also verwenden wir bzip2recover:
|
% bzip2recover the_bad_bad_backup.tar.bz2
|
So passiert zumindest irgendetwas. Abhängig von der Größe des Archives, erstellt bzip2recover
eine nette Anzahl von kleinen 'rec*' Dateien (typischerweise 900K groß), welche die normale
Blocksatzgröße darstellt, die bzip2 als Standard für Kompression verwendet. "Die nette
Anzahl von kleinen Dateien" kann jedoch leicht die Anwandlung haben, eine "RIESIGE Anzahl von
kleinen Dateien" zu werden, wenn das Archiv groß war - und meines war groß!
Das von mir verwendete Archiv war über 200MB groß, was mehrere hundert(!) dieser "kleinen
Dateien" zur Folge hatte. Naja, so schnell habe ich nicht aufgegeben und trotzdem daran
geglaubt, daß ich die Daten aus den kleinen Dateien herausbekommen könnte, wenn ich die
defekte "kleine Datei" irgendwie herausfinden könnte. So war also mein nächster Schritt,
herauszufinden, welche der kleinen Dateien kaputt waren und welche nicht:
bunzip2 stoppt, wenn die erste (und damit hoffentlich auch die letzte) korrupte Datei
gefunden wird - eigentlich genau das was wir hier brauchen. Da es keine Verwendung für
die schlechten Dateien mehr gibt, habe ich die einfach gelöscht und erneut den obigen
Befehl verwendet, inklusive Löschung aller weiteren korrupten Dateien. Das wirklich
wichtige bei der Aktion ist, sich die Zahl der gelöschten Dateien zu merken
(z.b. 00199, wenn die gelöschte Datei rec00199.bz2 geheißen hat).
Jetzt habe ich mir gedacht, daß es ab da einfach wäre: "Einfach tar auf die dekomprimierten
Dateien anwenden ...", aber ich wurde eines besseren belehrt. Wenn rec00199 die erste
(und letzte) korrupte Datei war, so beginnen wir mit rec00200:
% tar xf rec00200
tar: this doesn't look like a »tar«-archive
tar: jumping to the next header
tar: error upon exit caused by previous errors
|
"Shit." ... Und bei jeder weiteren der >200 verbleibenden Dateien immer dieselbe
Fehlermeldung erhalten. Suchen über google und diverse Postings in verschiedenen Mailinglists
haben mir keine verwertbaren Ergebnisse gebracht.
Tar behaupt von sich, auch korrupte Dateien nach tar-Headern zu scannen, aber dieses
sogenannte Feature hat einen entscheidenden Nachteil: Es funktioniert nur, wenn keines der
Bytes in der Datei verloren und/oder verschoben ist, weil tar beim Scannen nach Fileheadern
die jeweiligen Fileheader exakt 512 Bytes groß erwartet. Wenn auch nur ein einziges Byte
in einem Header (oder einem folgenden Datenblock) verloren ist, ist dieses
"Wiederherstellungs-Feature" eine reine Zeitverschwendung.
Aber das Glück ist einige Wochen später zurückgekehrt: Ich erhielt eine Email von einem
netten Typen, der ein kleines perl-script geschrieben hatte, das eine Datei nach einem
tar-Header Byte für Byte untersucht und sich nicht an die "512 Bytes" Art von tar hält.
Sie können dieses hier downloaden.
Um die Dinge zum Laufen zu bringen, habe ich den zweiten Teil der bunzip'ten
Dateien zu einer einzigen großen Datei kombiniert (die Dateien nach der
schlechten rec00199 Datei):
|
% cat rec00[2-4][0-9][0-9] > good_tail.tar
|
Der obige Befehl kombiniert alle Dateien von rec00200 bis rec00499 in einem
großen good_tail.jar Archiv.
Jetzt mußte ich nur noch das Script starten, um die Position des ersten guten
tar-Headers im good_tail.tar Archiv zu finden:
% perl find_tar_headers.pl good_tail.tar
good_tail.tar:17185:top/secret/warp_reactor.so:157106
good_tail.tar:75041:top/secret/kernel_injectors.so:153125
good_tail.tar:130849:top/secret/dampening_fields.so:145746
good_tail.tar:183585:top/secret/plasma_controls.so:157035
[...]
|
Das einzige was zählt, ist die erste Zeile des Outputs. Es zeigt, dass der erste
gute tar-Header im good_tail.tar Archiv auf der Position 17185 liegt. Was blieb, war
das Entpacken beginnend ab der gefundenen Position:
% tail -c +17185 good_tail.tar > extracted_tail.tar
% tar xf extracted_tail.tar
|
Happy End der Geschichte!
|