• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • ext2文件系統下恢復誤刪除的文件

    發表于:2007-07-02來源:作者:點擊數: 標簽:
    本系的 BBS 系統真是多災多難 (嗯 .... 其實是因為我的疏忽,才會這么多災多難 ....) ,繼這幾日系統時間不正確,造成許多人的 ID 被誤砍后,又一次因系統設定上的問題,將 BBS 的重要備份檔給殺了。這件事是學弟發現后告訴我的,當我上站來一見到他的 mail,

    本系的 BBS 系統真是多災多難 (嗯 .... 其實是因為我的疏忽,才會這么多災多難 ....) ,繼這幾日系統時間不正確,造成許多人的 ID 被誤砍后,又一次因系統設定上的問題,將 BBS 的重要備份檔給殺了。這件事是學弟發現后告訴我的,當我上站來一見到他的 mail, 當真是欲哭無淚,差點沒去撞墻。

    那時已是周六晚 11:00 左右,我一邊想著要編一套說辭向大家解釋無法替大家恢復舊信件與設定了,一邊還在想是否能夠挽回局面。大家知道, UNIX like 的系統是很難像 M$ 的系統一樣,做到 undelete 的,所有網管前輩都曾再三警告我們,要小心! 小心! 砍檔之前三思而后行,砍了之后再后悔也沒用。雖然我已漸漸做到砍檔三思而后行,但之次誤砍事件是系統在背景中定時執行的,等到我找出原因時已是檔案被砍后一個多小時。

    我憑著一點點的印象,想起在網絡上,有人討論過在 Linux ext2 filesystem中 undelete 的可能性,但我所見到的多半是負面的答案,但好象真的有人做過這件事,于是我第一個所做的,就是馬上將該檔案原來所在的 partition mount成 read-only, 禁止任何的寫入動作,不是怕再有檔案被誤砍 (因為已沒什么可砍的了) ,而是怕有新檔案寫進來,新資料可能會覆蓋到舊資料原本存在的磁區 (block) 。我們現在唯一個指望,就是企圖將檔案原來存在的磁區一個個找回來,并且「希望」這些磁區上的舊資料都還在,然后將這些磁區串成一個檔案。

    終于被我找到了!! 原來這方面的技術文件就存在我自己的系統中 :-))


    /usr/doc/HOWTO/mini/Ext2fs-Undeletion.gz

     

    于是我就按照這份文件的指示一步步來,總算將一個長達 8MB 的壓縮檔救回了 99%, 還有一個長達 1.1 MB 的壓縮檔完整無缺地救了回來。感謝上帝、 Linux 的設計者、寫那篇文件的作者、曾經討論過此技術的人、以及 Linux 如此優秀的 ext2 filesystem, 讓我有機會搶救過去?,F在,我將我的搶救步驟做一個整理讓大家參考,希望有派得上用場的時候 (喔! 不,最好是希望大家永遠不要有機會用到以下的步數 :-)))

    在此嚴正聲明!! 寫這篇文章的目的,是給那些處于萬不得已情況下的人們,有一個挽回的機會,并不意味著從此我們就可以大意,砍檔不需要三思。前面提到,我有一個檔案無法 100% 救回,事實上,長達 8MB 的檔案能救回 99% 已是幸運中的幸運,一般的情況下若能救回 70% - 80% 已經要愉笑了。所以,不要指望 undelete 能救回一切。預防勝于治療! 請大家平時就養成好習慣,砍檔前請三思!!!

    理論分析
    我們能救回的機會有多大? 在 kernel-2.0.X 系列中 (本站所用的 kernel 是 2.0.33) ,取決以下兩點:

    檔案原來所在的磁區是否沒有被覆寫?
    檔案是否完全連續?
    第一點我們可以與時間競賽,就是當一發現檔案誤砍時,要以最快的速度 umount 該 filesystem, 或將該 filesystem remount 成唯讀。就這次的情況而言,檔案誤砍是在事發一個小時后才發現的,但由于該 filesystem 寫入的機會很少 (我幾乎可確定一天才只有一次,做 backup),所以第一點算是過關了。
    第二點真的是要聽天由命了,就本站所使用的 kernel, 必須要在假設「長檔案」所占的 block 完全連續的情況下,才有可能完全救回來! 一個 block 是 1024 bytes,長達 8 MB 的檔案就有超過 8000 個 block。在經常讀寫的 filesystem 中,可以想見長檔案很難完全連續,但在我們的系統中,這一點似乎又多了幾分指望。同時,Linux ext2 如此精良的 filesystem, 能做到前 7950 多個 block 都連續,這一點也功不可沒。

    好了,以下我就講一下我的步驟。

    搶救步驟 I - mount filesystem readonly
    該檔案的位置原來是在 /var/hda/backup/home/bbs 下,我們系統的 filesystem 組態是:


    # df

    Filesystem 1024-blocks Used Available Capacity Mounted on
    /dev/sda1 396500 312769 63250 83% /
    /dev/sda3 777410 537633 199615 73% /home
    /dev/hda1 199047 36927 151840 20% /var/hda
    /dev/hda2 1029023 490998 485710 50% /home/ftp

     

    因此 /var/hda 這個 filesystem 要馬上 mount 成 readonly (以下請用 root 身份):


    mount -o remount,ro /var/hda

     

    當然也可以直接 umount 它,但有時候可能有某些 process 正在此 filesystem下運作,您可能無法直接 umount 它。因此我選擇 mount readonly。但您也可以用:


    fuser -v -m /usr

     

    看一下目前是那些 process 在用這個 filesystem, 然后一一砍掉,再 umount。

    搶救步驟 II
    執行


    echo lsdel | debugfs /dev/hda1 | less

     

    看一下該 filesystem 最近被砍的 inode (檔案) 有那些 (為什么是 /dev/hda1? 請見上頭的 df 列表)? 在這奶F檔案的重要資訊,如大小、時間、屬性等等。就我們的系統而言,其列示如下:


    debugfs: 92 deleted inodes found.
    Inode Owner Mode Size Blocks Time deleted
    ..................................................................................................................................................

    29771 0 100644 1255337 14/14 Sat Jan 30 22:37:10 1999
    29772 0 100644 5161017 14/14 Sat Jan 30 22:37:10 1999
    29773 0 100644 8220922 14/14 Sat Jan 30 22:37:10 1999
    29774 0 100644 5431 6/6 Sat Jan 30 22:37:10 1999

     

    請注意!我們必須要在檔案大小、被砍時間等資訊中判斷出要救回的檔案是那一個。在此,我們要救回 29773 這個 inode。

    搶救步驟 III
    執行


    echo "stat <29773>" | debugfs /dev/hda1

     

    列出該 inode 的所有資訊,如下:


    debugfs: stat <29773>
    Inode: 29773 Type: regular Mode: 0644 Flags: 0x0 Version: 1
    User: 0 Group: 0 Size: 8220922
    File ACL: 0 Directory ACL: 0
    Links: 0 Blockcount: 16124
    Fragment: Address: 0 Number: 0 Size: 0
    ctime: 0x36b31916 -- Sat Jan 30 22:37:10 1999
    atime: 0x36aebee4 -- Wed Jan 27 15:23:16 1999
    mtime: 0x36adec25 -- Wed Jan 27 00:24:05 1999
    dtime: 0x36b31916 -- Sat Jan 30 22:37:10 1999
    BLOCKS:
    123134 123136 123137 123138 123140 131404 131405 131406 131407 131408 131409 131
    410 131411 131668
    TOTAL: 14

     

    現在的重點是,必須將該 inode 所指的檔案,所指的 block 全部找回來。在這它?14 個 block? 不對啊! 應該要有 8000 多個 block 才對啊! 在這卯ilesystem 的「奧密」了。上頭所列的前 12 個 block 是真正指到檔案資料的 block, 稱之為 direct block 。第 13 個稱為第一階 indirect block, 第 14 個稱為第二階 indirect block 。什么意思? 該檔的資料所在的 block 位置如下:

     

    各位明白嗎? 第 13 個 (131411) 與第 14 個 block 其實不是 data, 而是 index,它指出接下來的 block 的位置。由于一個 block 的大小是 1024 bytes, 一個 int 在 32 位系統中是 4 bytes, 故一個 block 可以記錄 256 筆資料。以 131411 block 為例,它所記錄的資料即為 (在檔案未砍前):


    131412 131413 131414 .... 131667 (共 256 筆)

     

    而這 256 個 block 就真正記錄了檔案資料,所以我們稱為第一階。同理,第二階就有兩個層 index, 以 131668 來說,它可能記錄了:


    131669 131926 132182 .... (最多有 256 筆)

     

    而 131669 的 block 記錄為:


    131670 131671 131672 .... 131925 (共 256 筆)

     

    而這 256 個 block 才是真正儲存檔案資料的。而我們要的,就是這些真正儲存檔案資料的 block 。 理論上,我們只要將這些 index block 的內容全部讀出來,然后照這些 index 把所有的 block 全部讀到手,就能 100% 救回檔案 (假設這些 block 全部沒有被新檔案覆寫的話)。工程很大,但是可行。不幸的是,在 kernel-2.0.33, 其設計是,如果該檔案被砍了,則這些 index block 全部會規零,因此我所讀到的是


    0 0 0 0 0 ..... (共 256 筆)

     

    哇! 沒辦法知道這些 data block 真正所在的位置。所以,在此我們做了一個很大的假設: 整個檔案所在的 block 是連續的! 也就是我上頭的例子。這也就是為什么說,只有連續 block (是指后頭的 indirect block) 的檔案才能完整救回,而這一點就要聽天由命了。

    搶救步驟 IV
    好了,現在我們只好假設所有的檔案處于連續的 block 上,現在請用


     

    去找這個工具: 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 并沒有完全連續!!!)


    fsgrab -c 1 -s 123134 /dev/hda1 > recover
    fsgrab -c 3 -s 123136 /dev/hda1 >> recover
    fsgrab -c 1 -s 123140 /dev/hda1 >> recover
    fsgrab -c 7 -s 131404 /dev/hda1 >> recover

     

    這是開頭的 12 個 block, 對于第一階 indirect, 就資料來看好象是連續的 :-))


    fsgrab -c 256 -s 131412 /dev/hda1 >> recover

     

    注意要跳過 131411, 因為它是 index block。對于第二階 indirect, 我們 *假設* 它們都是連續的:


    fsgrab -c 256 -s 131670 /dev/hda1 >> recover
    fsgrab -c 256 -s 131927 /dev/hda1 >> recover
    fsgrab -c 256 -s 132184 /dev/hda1 >> recover
    ............................................

     

    要一直做,直到 recover 的大小超過我們所要救回的檔案大小 (8220922) 為止。要注意在這市 p心地跳過那些 index block (如 131668, 131669, 131926, 132183, ....) 了。

    搶救步驟 V
    最后一步,就是把檔案「剪」出來,并看看我們救回多少了。在這戊]我們重復上述步驟,弄出來的 recover 檔大小為 8294400,而我們要的大小是 8220922, 那就這樣下指令:


    split -b 8220922 recover rec

     

    則會做出兩個檔,一個是 recaa, 大小是 8220922, 另一個是 recab 則是剩下的大小,后者是垃圾,扔了即可?,F在我們可以檢查這個檔案是不是「完整」的那個被誤砍的檔案了。由于我們的那個檔案是 .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 設計者正著手研究,看能否克服這個困難,也就是在檔案砍掉時,不要將 index block 規零。我剛剛試一下 kenrel-2.2.0 的環境,發現已做到了!! 以下是一個已砍的檔案的 inode data (由 debugfs 所讀出):

     

    debugfs: Inode: 36154 Type: regular Mode: 0600 Flags: 0x0 Version: 1
    User: 0 Group: 0 Size: 2165945
    File ACL: 0 Directory ACL: 0
    Links: 0 Blockcount: 4252
    Fragment: Address: 0 Number: 0 Size: 0
    ctime: 0x36b54c3b -- Mon Feb 1 14:39:55 1999
    atime: 0x36b54c30 -- Mon Feb 1 14:39:44 1999
    mtime: 0x36b54c30 -- Mon Feb 1 14:39:44 1999
    dtime: 0x36b54c3b -- Mon Feb 1 14:39:55 1999
    BLOCKS:
    147740 147741 147742 147743 147744 147745 147746 147747 147748 147769 147770 157
    642 157643 157644 157645 157646 157647 157648 157649 157650 157651 157652 157653
    157654 157655 157656 157657 157658 157659 157660 157661 157662 157663 157664 15
    7665 157666 157667 157668 157669 157670 157671 157672 157673 157674 157675 15767
    6 157677 157678 157679 157680 157681 157682 157683 157684 157685 157686 157687 1
    ........................................................................................................................................................
    9745 159746 159747 159748 159749 159750 159751 159752 159753 159754 159755 15975
    6
    TOTAL: 2126

     

    真是太完美了!! 這意味著在 kernel-2.2.X 的環境下,我們不必假設所有的 block 都連續,而且可以百分之百找回所有砍掉的 block! 因此上述的第二個風險就不存在了。

    以上資料,謹供參考

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>