本系 BBS 系统真是多灾多难 (嗯....其实是我疏忽才会这么多灾多难 ....)继这几日系统时间不正确造成许多人ID误砍后又次因系统设定上问题将BBS重要备份档给杀了这件事是学弟发现后告诉我当我上站来见到他 mail, 当真是欲哭无泪差点没去撞墙
那时已是周 6晚11:00左右我边想着要编套说辞向大家解释无法替大家恢复旧信件和设定了边还在想是否能够挽回局面大家知道UNIXlike系统是很难像 M$ 系统样做到 undelete 所有网管前辈都曾再 3警告我们要小心! 小心!砍档的前 3思而后行砍了的后再后悔也没用虽然我已渐渐做到砍档 3思而后行但的次误砍事件是系统在背景中定时执行等到我找出原因时已是档案被砍后个多小时
我凭着点点印象想起在网络上有人讨论过在 Linux ext2 filesystem中 undelete可能性但我所见到多半是负面答案但好象真有人做过这件事于是我第个所做就是马上将该档案原来所在 partition mount成 read-only, 禁止任何写入动作不是怕再有档案被误砍(已没什么可砍了)而是怕有新档案写进来新资料可能会覆盖到旧资料原本存在磁区(block)我们现在唯个指望就是企图将档案原来存在磁区个个找回来并且「希望」这些磁区上旧资料都还在然后将这些磁区串成个档案终于被我找到了!!原来这方面技术文件就存在我自己系统中 :-)) /usr/doc/HOWTO/mini/Ext2fs-ndeletion.gz
于是我就按照这份文件指示步步来总算将个长达 8MB 压缩档救回了 99%, 还有个长达 1.1 MB 压缩档完整无缺地救了回来感谢上帝、 Linux 设计者、写那篇文件作者、曾经讨论过此技术人、以及 Linux 如此优秀 ext2filesystem,让我有机会抢救过去现在我将我抢救步骤做个整理让大家参考希望有派得上用场时候 (喔! 不最好是希望大家永远不要有机会用到以下步数 :-))) 在此严正声明!! 写这篇文章目是给那些处于万不得已情况下人们有个挽回机会并不意味着从此我们就可以大意砍档不需要 3思前面提到我有个档案无法100%救回事实上长达 8MB 档案能救回 99% 已是幸运中幸运般情况下若能救回 70% - 80% 已经要愉笑了所以不要指望 undelete 能救回切预防胜于治疗! 请大家平时就养成好习惯砍档前请 3思!!!
理论分析
我们能救回机会有多大? 在 kernel-2.0.X 系列中 (本站所用 kernel 是 2.0.33) 取决以下两点:
档案原来所在磁区是否没有被覆写?
档案是否完全连续?
第点我们可以和时间竞赛就是当发现档案误砍时要以最快速度 umount 该filesystem,或将该filesystemremount成唯读就这次情况而言档案误砍是在事发个小时后才发现但由于该filesystem写入机会很少(我几乎可确定天才只有次做 backup)所以第点算是过关了
第 2点真是要听天由命了就本站所使用kernel,必须要在假设「长档案」所占 block 完全连续情况下才有可能完全救回来! 个 block 是 1024 s,长达 8 MB档案就有超过 8000 个 block在经常读写 filesystem 中可以想见长档案很难完全连续但在我们系统中这点似乎又多了几分指望同时Linuxext2如此精良filesystem,能做到前7950多个block都连续这点也功不可没
好了以下我就讲下我步骤
抢救步骤 I - mount filesystem readonly
该档案位置原来是在 /var/hda/backup/home/bbs 下我们系统filesystem 组态是:
请注意!我们必须要在档案大小、被砍时间等资讯中判断出要救回档案是那个在此我们要救回 29773 这个 inode
抢救步骤 III
执行 echo "stat <29773>" | debugfs /dev/hda1
列出该 inode 所有资讯如下:
现在重点是必须将该inode所指档案所指block全部找回来在这它?14
个block?不对啊!应该要有8000多个block才对啊!在这Filesystem奥妙了上头所列前 12 个 block 是真正指到档案资料 block, 称的为 direct block 第 13个称为第阶 indirect block, 第 14 个称为第 2阶 indirect block 什么意思? 该档案资料所在 block 位置如下:
各位明白吗? 第 13 个 (131411) 和第 14 个 block 其实不是 data, 而是 index,它指出接下来 block 位置由于个 block 大小是 1024 s, 个 在 32 位系统中是 4 s, 故个 block 可以记录 256 笔资料以 131411 block 为例它所记录资料即为 (在档案未砍前): 131412 131413 131414 .... 131667 (共 256 笔)
而这256个block就真正记录了档案资料所以我们称为第阶同理第 2阶就有
两个层 index, 以 131668 来说它可能记录了: 131669 131926 132182 .... (最多有 256 笔)
而 131669 block 记录为: 131670 131671 131672 .... 131925 (共 256笔)而这256个block才是真正储存档案资料而我们要就是这些真正储存档案资料block理论上我们只要将这些indexblock内容全部读出来然后照这些 index把所有block全部读到手就能100%救回档案(假设这些block全部没有被新档案覆写话)工程很大但是可行不幸是在 kernel-2.0.33, 其设计是如果该档案被砍了则这些 index block 全部会规零因此我所读到是 0 0 0 0 0 ..... (共 256 笔)
哇!没办法知道这些datablock真正所在位置所以在此我们做了个很大假
设:整个档案所在block是连续!也就是我上头例子这也就是为什么说只有连续block(是指后头indirectblock)档案才能完整救回而这点就要听天由命了
抢救步骤 IV
好了现在我们只好假设所有档案处于连续block上现在请用http://archie.ncu.edu.tw去找这个工具:fsgrab-1.2.tar.gz,并将它安装起来步骤很简单故在此我就不多谈我们要用它将所需 block 全部抓出来它使用方法如下: fsgrab -c count -s skip device
其中 count 是只要 (连续) 读几个 skip是指要从第几个开始读例如我要从 131670 开始连续读 256 个就这样下指令: fsgrab -c 256 -s 131670 /dev/hda1 > recover
现在我们就开始救档案吧! 以上头资料我们必须用以下指令来救: (注意到头开 12 个 block 并没有完全连续!!!)
这是开头 12 个 block, 对于第阶 indirect, 就资料来看好象是连续 :-)) fsgrab -c 256 -s 131412 /dev/hda1 >> recover
注意要跳过 131411, 它是 index block对于第 2阶 indirect, 我们 *假设* 它们都是连续:
要直做直到 recover 大小超过我们所要救回档案大小(8220922)为止要跳过那些 index block (如 131668, 131669, 131926, 132183, ....) 了
抢救步骤 V
最后步就是把档案「剪」出来并看看我们救回多少了我们重复上述步骤弄出来 recover 档大小为8294400而我们要大小是8220922,那就这样下指令:
split -b 8220922recover rec
则会做出两个档个是recaa,大小是8220922,另个是recab则是剩下大小后者是垃圾扔了即可现在我们可以检查这个档案是不是「完整」那个被误砍档案了由于我们那个档案是 .tar.gz 格式于是我们这个思路方法来检查:
mv recaa recaa.tar.gz
zcat recaa.tar.gz > recaa.tar
如果没有讯息那表示成功了!完全救回来了但不幸是我们没有成功将弄出 recaa.tar 改名再 gzip 的后和原来 recaa.tar.gz 比下大小发现少了 1%, 表示说该档原来所在 block 中最后有 1% 是不连续 (或者被新写入档案覆写了)但这已是不幸中大幸了
后记
对于在 undelete时假设所有 block 连续问题那份 HOWTO 文件说Linus和其它kernel设计者正着手研究看能否克服这个困难也就是在档案砍掉时不要将indexblock规零我刚刚试下kenrel-2.2.0环境发现已做到了!! 以下是个已砍档案 inode data (由 debugfs 所读出):
真是太完美了!! 这意味着在 kernel-2.2.X 环境下我们不必假设所有 block 都连续而且可以百分的百找回所有砍掉 block! 因此上述第 2个风险就不存在了
以上资料谨供参考
参考文件: Ext2fs-Undeletion Mini HOWTO
最新评论