據(jù)恢復(fù)實(shí)戰(zhàn)指南:從ddrescue鏡像到文件找回的完整流程)
簡介開源數(shù)據(jù)恢復(fù)軟件資源包面向因誤刪、格式化、分區(qū)損壞或硬盤故障而丟失數(shù)據(jù)的用戶與開發(fā)者提供一套可自行編譯、修改的恢復(fù)工具源碼。該包共516個文件以364個C源文件、145個頭文件為主輔以少量CPP、RC資源配置及Makefile工程文件壓縮后約4.42MB適合有一定C語言基礎(chǔ)的人員學(xué)習(xí)底層磁盤掃描、文件系統(tǒng)解析FAT/NTFS與恢復(fù)流程。資源涵蓋文件誤刪找回、分區(qū)表修復(fù)、壞道讀取、系統(tǒng)崩潰后數(shù)據(jù)搶救等典型場景源碼按功能模塊劃分便于按需裁剪或擴(kuò)展文件類型支持。已有1524人學(xué)習(xí)下載。通過閱讀源碼可掌握數(shù)據(jù)恢復(fù)軟件從掃描、分析、預(yù)覽到恢復(fù)的完整實(shí)現(xiàn)思路理解FAT與NTFS簇鏈等底層機(jī)制并能夠針對特定存儲介質(zhì)優(yōu)化算法、增加自定義恢復(fù)規(guī)則是一份兼顧理論與實(shí)踐的開源學(xué)習(xí)材料。1. 數(shù)據(jù)恢復(fù)這行當(dāng)先明白它是門底層手藝不是碰運(yùn)氣很多人在存儲設(shè)備出問題后的第一個動作是找個“搶眼”的收費(fèi)軟件掃一遍然后盯著進(jìn)度條祈禱。我做了多年的數(shù)據(jù)和存儲運(yùn)維第一次用開源工具完整救回一塊被誤格式化的盤時才意識到一個反直覺的事實(shí)——數(shù)據(jù)恢復(fù)本質(zhì)上是一場底層的逆向定位文件沒被真正抹掉只是系統(tǒng)把索引標(biāo)記成了“可覆蓋”恢復(fù)工具是在文件系統(tǒng)層和塊層之間把那些還沒被新數(shù)據(jù)占用的殘留結(jié)構(gòu)找出來。開源方案的恢復(fù)能力并不比商業(yè)軟件弱區(qū)別在于它要你自己讀文檔、理解參數(shù)、承擔(dān)操作風(fēng)險。這篇筆記適合運(yùn)維、開發(fā)者和被誤刪文件困擾的個人用戶幫你看清開源數(shù)據(jù)恢復(fù)的邊界并把它用出穩(wěn)定的成功率。2. 開源恢復(fù)工具選型先分清場景再決定用哪把刀數(shù)據(jù)恢復(fù)失敗案例里絕大多數(shù)不是因?yàn)楣ぞ卟恍卸怯缅e了場景。一個在 Windows 下誤刪了 NTFS 分區(qū)的文件拿 extundelete 去掃當(dāng)然什么都掃不出來一塊已經(jīng)出現(xiàn)物理壞道的硬盤直接跑深度掃描結(jié)果往往是掃描卡死盤面損傷進(jìn)一步擴(kuò)大。開源生態(tài)里的恢復(fù)工具各有各的“主場”選型這一步走對后續(xù)基本就是按流程執(zhí)行。2.1 三層恢復(fù)模型文件系統(tǒng)層、簽名層和塊層我把數(shù)據(jù)恢復(fù)分為三個層級選工具前先要判斷數(shù)據(jù)問題發(fā)生在哪一層。文件系統(tǒng)層恢復(fù)依賴文件系統(tǒng)自己的元數(shù)據(jù)。像 ext3/ext4 刪除文件時只清掉了目錄項(xiàng)和 inode 的鏈接計數(shù)數(shù)據(jù)塊本身還在。只要 inode 沒被復(fù)用extundelete 就能把這些文件“撿回來”。這一層恢復(fù)速度最快幾 GB 的分區(qū)往往幾分鐘就掃完但前提是文件系統(tǒng)結(jié)構(gòu)本身沒有被破壞。簽名層恢復(fù)不依賴文件系統(tǒng)而是直接在未分配空間里按文件頭特征去找數(shù)據(jù)。photorec 就干這個它內(nèi)置了兩三百種常見文件的魔數(shù)簽名比如 JPEG 的FF D8 FF、PDF 的%PDF掃到簽名就按預(yù)設(shè)的尾部規(guī)則切出文件。這一層能處理格式化、分區(qū)重建、甚至文件系統(tǒng)完全損毀的情況但恢復(fù)出來的文件名會變成f1234567.jpg這種編號目錄結(jié)構(gòu)也沒了。塊層指 ddrescue 這類工具做的整盤鏡像。它不關(guān)心文件系統(tǒng)只做扇區(qū)級復(fù)制專門對付壞道和物理損傷介質(zhì)。這三層不是互斥的通常塊層鏡像是第一步鏡像做完之后再到鏡像文件上做文件系統(tǒng)層或簽名層恢復(fù)。2.2 工具選型對照表不同故障對應(yīng)不同方案下面這張表是我處理過的典型場景和對應(yīng)的工具組合可以作為選型時的參考。注意同一款工具在不同場景下的效果差異很大不要指望一個工具通吃。故障現(xiàn)象底層原因首選工具備選或補(bǔ)充單個文件誤刪分區(qū)仍在目錄項(xiàng)和 inode 鏈接被清除extundeleteext 系列 / testdisk 的 undeleteFAT/NTFSphotorec 按簽名撈格式化后想找回文件新文件系統(tǒng)覆蓋了舊元數(shù)據(jù)數(shù)據(jù)塊可能還在photorec 深度掃描testdisk 嘗試找回原分區(qū)表分區(qū)丟失、分區(qū)表損壞MBR/GPT 結(jié)構(gòu)損壞分區(qū)起始位置丟失testdisk 的 analyze 和 rebuild先 ddrescue 鏡像再分析壞道、異響、S.M.A.R.T 異常介質(zhì)物理損傷反復(fù)讀寫會擴(kuò)大損傷ddrescue 鏡像再做后續(xù)恢復(fù)強(qiáng)烈不建議直接掃原盤整盤被重新分區(qū)并寫入了部分?jǐn)?shù)據(jù)分區(qū)表和部分?jǐn)?shù)據(jù)被覆蓋testdisk 找回原分區(qū)布局 photorec 兜底取決于覆蓋了多少新數(shù)據(jù)2.3 參數(shù)差異為什么同一套命令在不同工具里結(jié)果不同很多新手在 extundelete 里看到一個--restore-all就以為能通吃結(jié)果在 NTFS 分區(qū)上執(zhí)行直接報錯。原因是 extundelete 只認(rèn)識 ext3/ext4 的 inode 結(jié)構(gòu)。它沒有數(shù)據(jù)簽名概念所有恢復(fù)都靠 inode 里的指針去找數(shù)據(jù)塊位置。一旦格式化把 inode 表清零extundelete 就會告訴你“no deleted inodes found”這時候它不是壞了而是它的設(shè)計根本不處理這種情況。photorec 則完全反過來它從頭到尾不讀 inode只按扇區(qū)掃描簽名。好處是兼容上百種文件系統(tǒng)壞處是恢復(fù)出的文件沒名字、沒路徑、碎片文件會丟失。它的wholespace選項(xiàng)可以控制是否掃描整個磁盤的未使用空間選whole會更慢但要全得多選free只掃空閑空間速度快但有可能漏掉已經(jīng)帶病解析的分區(qū)里的文件。ddrescue 的參數(shù)就更微妙了它的執(zhí)行次數(shù)、日志文件、反向填充模式都會影響最終鏡像的質(zhì)量。后面實(shí)戰(zhàn)部分我會細(xì)講這里先記住一句話鏡像階段寧可慢不要急壞道盤的所有操作都必須以最小化磁頭回退為原則。3. 實(shí)戰(zhàn)流程從 ddrescue 鏡像到 photorec 與 testdisk 的完整操作這一章是整套流程的核心。數(shù)據(jù)恢復(fù)界有個不成文的規(guī)矩在源盤上做一切操作都是在增加風(fēng)險。正確姿勢是先用 ddrescue 把整盤做成鏡像之后所有恢復(fù)動作都在鏡像文件上進(jìn)行。這樣即使恢復(fù)過程出現(xiàn)誤操作源盤仍然保持原樣永遠(yuǎn)有后悔藥可吃。3.1 第一步用 ddrescue 做塊級鏡像假設(shè)系統(tǒng)里現(xiàn)在有兩塊盤/dev/sdb是待恢復(fù)的問題盤/dev/sdc是一塊空盤。先把 sdc 分區(qū)并格式化然后掛載到/mnt/recovery。# 查看當(dāng)前磁盤狀態(tài)確認(rèn)盤符映射 lsblk -o NAME,SIZE,MODEL,SERIAL # 創(chuàng)建鏡像文件注意不要放在源盤上 mkdir -p /mnt/recovery # 執(zhí)行塊級鏡像生成鏡像文件和日志文件 ddrescue -d -r 3 /dev/sdb /mnt/recovery/disk.img /mnt/recovery/disk.log第一條lsblk是操作前必做的確認(rèn)動作防止把好盤當(dāng)成問題盤來鏡像。第二條ddrescue的參數(shù)含義我需要解釋一下。-d表示直接讀取設(shè)備跳過系統(tǒng)緩存這樣能拿到更真實(shí)的物理狀態(tài)-r 3表示每個壞塊區(qū)域最多重試 3 次避免在壞死區(qū)域上無限等待/mnt/recovery/disk.img是鏡像輸出文件/mnt/recovery/disk.log是斷點(diǎn)日志這個日志文件必須保留如果鏡像中途中斷再次執(zhí)行同一條命令時會自動跳過已完成的部分繼續(xù)跑。鏡像完成后檢查日志的末尾統(tǒng)計重點(diǎn)關(guān)注rescued和non-tried兩個數(shù)值。rescued是成功讀出的數(shù)據(jù)量non-tried應(yīng)該為 0如果還有大量non-tried說明鏡像沒有跑完需要再次執(zhí)行同一條命令。這一步很多人會忽略以為 ddrescue 執(zhí)行完就是完整鏡像實(shí)際上對于壞道盤第一次掃描會漏掉許多區(qū)域必須重復(fù)執(zhí)行直到non-tried歸零。3.2 第二步在鏡像上跑 extundelete 恢復(fù)誤刪文件鏡像做完之后如果問題盤是 ext4 文件系統(tǒng)且只是誤刪文件可以直接在鏡像上嘗試 extundelete。注意 extundelete 需要識別鏡像里的文件系統(tǒng)直接把鏡像文件當(dāng)塊設(shè)備用即可。# 先用 losetup 把鏡像掛為 loop 設(shè)備 losetup /dev/loop0 /mnt/recovery/disk.img # 查看文件系統(tǒng)狀態(tài)確認(rèn)分區(qū)偏移 fdisk -l /dev/loop0 # 如果鏡像里有分區(qū)表需要按偏移掛載 loop 設(shè)備 losetup -o $((512*2048)) /dev/loop1 /mnt/recovery/disk.img # 執(zhí)行恢復(fù)全部刪除文件恢復(fù)到指定目錄 extundelete /dev/loop1 --restore-all --output-dir /mnt/recovery/restored這里有三個關(guān)鍵點(diǎn)。第一losetup的-o參數(shù)指定分區(qū)偏移2048 扇區(qū)通常對應(yīng) 1MiB 對齊的 ext4 分區(qū)起點(diǎn)但如果原來的分區(qū)布局不同這個值要根據(jù)fdisk -l的實(shí)際輸出來改不能照抄。第二--restore-all恢復(fù)所有被刪除的 inode如果你只想恢復(fù)某一個文件用--restore-file 路徑名會更精準(zhǔn)也更快。第三--output-dir指定輸出目錄這個目錄必須和鏡像不在同一塊物理盤上否則恢復(fù)出的新文件可能覆蓋掉還沒恢復(fù)的舊數(shù)據(jù)。extundelete 的速度非??煲?yàn)樗前?inode 定位數(shù)據(jù)塊的不需要全盤掃描。如果執(zhí)行后提示沒有找到已刪除的 inode說明格式化過程中已經(jīng)清掉了 inode 表這就得換 photorec 上簽名掃描了。3.3 第三步用 photorec 做簽名級深度恢復(fù)photorec 是 testdisk 工具包里的姊妹程序它的交互界面是字符菜單模式。直接在鏡像文件上運(yùn)行是最安全的做法。# 運(yùn)行 photorec指定操作鏡像文件而非物理盤 photorec /mnt/recovery/disk.img # 交互操作序列 # 1. 選擇要分析的介質(zhì)選中鏡像文件 # 2. 選擇分區(qū)類型通常選 IntelMBR或 EFI GPT # 3. 選擇文件系統(tǒng)類型如果識別不準(zhǔn)確就選 Other # 4. 選擇掃描范圍Whole整個鏡像或 Free僅空閑空間 # 5. 選擇恢復(fù)文件輸出目錄 # 6. 確認(rèn)后開始掃描等待完成photorec 的掃描時間受鏡像大小和文件數(shù)量影響幾十 GB 的盤掃幾個小時是常態(tài)。掃描過程中不要中斷因?yàn)榛謴?fù)進(jìn)度不會保存中斷就得重新來。輸出目錄的選擇同樣遵循獨(dú)立物理盤原則?;謴?fù)完成后輸出目錄里會是一堆f1234567.jpg樣式的文件按擴(kuò)展名分類放在子目錄里。這一步的驗(yàn)證很重要用file命令抽查幾個文件確認(rèn)頭部簽名和擴(kuò)展名一致。# 抽查恢復(fù)文件的真實(shí)性 file /mnt/recovery/restored/*.jpg | head -20 # 統(tǒng)計各類文件的恢復(fù)數(shù)量 find /mnt/recovery/restored -type f | sed s/.*\.// | sort | uniq -c | sort -rnfile命令讀取文件頭部特征如果它輸出JPEG image data而擴(kuò)展名是.jpg基本可以確認(rèn)文件完整。如果輸出data說明這個文件只是掃到半個簽名或者尾部被截斷屬于不完整恢復(fù)可以優(yōu)先排查這一類。統(tǒng)計擴(kuò)展名數(shù)量這一步能幫你快速判斷恢復(fù)結(jié)果覆蓋了哪些類型決定下一步是先修復(fù)還是先篩選。3.4 第四步用 testdisk 找回丟失分區(qū)如果問題不是刪文件而是整個分區(qū)消失、系統(tǒng)提示未格式化這時候 testdisk 是首選。它通過掃描分區(qū)表附近的引導(dǎo)扇區(qū)和文件系統(tǒng)備份來找回原始分區(qū)布局。# 直接對鏡像文件運(yùn)行 testdisk testdisk /mnt/recovery/disk.img # 交互操作序列 # 1. 選擇 Create 創(chuàng)建新日志文件 # 2. 選擇介質(zhì)類型鏡像文件會自動識別 # 3. 選擇分區(qū)表類型Intel / EFI GPT / 其他 # 4. 選擇 Analyse 分析當(dāng)前分區(qū)結(jié)構(gòu) # 5. 用 Quick Search 快速掃描找到疑似分區(qū)后按 P 預(yù)覽 # 6. 預(yù)覽確認(rèn)文件列表正確后選擇 Write 寫回分區(qū)表這里有個容易翻車的點(diǎn)testdisk 的 Write 操作會把分區(qū)表寫回鏡像里。如果鏡像文件本身是你后續(xù)恢復(fù)工作的基礎(chǔ)寫回沒有問題但如果將來還要對這個鏡像做其他法證分析建議先復(fù)制一份鏡像再寫。預(yù)覽步驟里的P鍵可以瀏覽分區(qū)內(nèi)文件這一步一定要做因?yàn)樗?yàn)證的是分區(qū)位置是否正確而不是靠猜。如果 Quick Search 沒找到可以用 Deeper Search 做全盤掃描它會遍歷每個扇區(qū)找引導(dǎo)扇區(qū)標(biāo)志耗時更長但成功率更高。找到的分區(qū)可能不止一個testdisk 會列出所有候選你需要根據(jù)文件列表內(nèi)容判斷哪一個是正確分區(qū)——識別原則是文件列表里能看到你熟悉的目錄結(jié)構(gòu)。4. 避坑要點(diǎn)五條血淚排查記錄覆蓋誤操作與邊界情況開源數(shù)據(jù)恢復(fù)里真正讓數(shù)據(jù)徹底丟失的往往不是故障本身而是恢復(fù)過程中的錯誤操作。下面這幾條是我這些年反復(fù)遇到的踩坑記錄每條都按現(xiàn)象、原因、解決的順序拆開方便你對照排查。4.1 恢復(fù)目標(biāo)盤和源盤是同一塊物理盤現(xiàn)象photorec 掃描時恢復(fù)出的文件不斷報錯打不開掃描速度越來越慢最后連源盤的原始數(shù)據(jù)也被破壞。原因輸出目錄設(shè)在源盤的另一分區(qū)上photorec 一邊從源分區(qū)讀數(shù)據(jù)一邊往同一塊盤的其他分區(qū)寫文件磁頭來回尋道不僅拖慢速度新寫入的數(shù)據(jù)還可能和待恢復(fù)的數(shù)據(jù)塊產(chǎn)生物理干擾。解決恢復(fù)操作前先確認(rèn)輸出目錄不在源盤上。用df查看輸出目錄的掛載設(shè)備與源盤設(shè)備號比對不一致才算安全。我常用的檢查指令是# 確認(rèn)源盤和輸出目錄不在同一設(shè)備上 lsblk /dev/sdb df -h /mnt/recovery這兩條命令的輸出對比一目了然/dev/sdb是源盤/mnt/recovery掛載在/dev/sdc上物理隔離確認(rèn)后才繼續(xù)。4.2 壞道盤直接跑 photorec 導(dǎo)致卡死和二次損傷現(xiàn)象硬盤有壞道直接跑 photorec 掃描進(jìn)度條卡在某個百分比不動硬盤發(fā)出規(guī)律的“咔噠”聲之后整個盤陷入更深的不穩(wěn)定狀態(tài)。原因photorec 是逐扇區(qū)讀取的遇到壞道時硬盤控制器反復(fù)重試每次重試都讓磁頭在壞道附近反復(fù)定位不僅導(dǎo)致進(jìn)度停滯還可能讓相鄰的磁道也受損。解決先 ddrescue 鏡像再在鏡像上跑 photorec。ddrescue 遇到讀錯誤會快速跳過并記錄日志不會卡死。如果情況緊急可以用ddrescue -R反向掃描模式從磁盤尾部開始向頭部掃這樣磁頭移動路徑更平滑。4.3 extundelete 掃不出任何刪除文件現(xiàn)象ext4 分區(qū)誤刪文件后extundelete 提示No deleted inodes found一個文件都恢復(fù)不出來。原因文件刪除后系統(tǒng)可能立即觸發(fā)了 journal 日志清理或后臺的fstrim操作。如果分區(qū)啟用了 discard 掛載選項(xiàng)刪除操作會直接通知 SSD 擦除數(shù)據(jù)塊inode 和數(shù)據(jù)塊內(nèi)容都被物理清空任何恢復(fù)工具都無能為力。另一種可能是 inode 被新文件復(fù)用文件數(shù)據(jù)已經(jīng)被覆蓋。解決開機(jī)第一件事就是用只讀方式掛載分區(qū)或直接拔盤做鏡像任何自動掛載都可能觸發(fā)日志寫入?;謴?fù)前用mount -o ro確認(rèn)掛載狀態(tài)并在鏡像上操作不給系統(tǒng)寫數(shù)據(jù)的機(jī)會。如果確認(rèn)是 trim 導(dǎo)致的這文件基本沒救了換 photorec 也只能碰運(yùn)氣。4.4 testdisk 寫回分區(qū)表后分區(qū)里的文件反而全沒了現(xiàn)象testdisk 找到原分區(qū)Write 寫回后重啟系統(tǒng)分區(qū)存在了但里面文件列表是空的或者文件系統(tǒng)報錯。原因可能是找錯了分區(qū)另一個同樣大小、同樣類型的舊分區(qū)被誤寫入了。也可能是寫回的分區(qū)表里的起始扇區(qū)與實(shí)際數(shù)據(jù)位置偏移了幾個扇區(qū)。原分區(qū)起始位置在備份引導(dǎo)扇區(qū)里記錄了精確值但testdisk 的搜索結(jié)果是基于特征匹配的候選不一定對應(yīng)當(dāng)前數(shù)據(jù)布局。解決Write 之前一定要按P預(yù)覽文件列表確認(rèn)看到的是正確的目錄結(jié)構(gòu)再寫入。如果已經(jīng)寫錯不要急著格式化重新進(jìn)入 testdisk同樣搜索分區(qū)這次預(yù)覽時多注意目錄里文件的修改時間與故障發(fā)生前的情況做比對。4.5 恢復(fù)工具安裝在待恢復(fù)的盤上現(xiàn)象在系統(tǒng)里裝 testdisk 工具包時安裝過程提示分區(qū)只讀或空間不足隨后發(fā)現(xiàn)原盤系統(tǒng)崩潰恢復(fù)無從談起。原因安裝軟件會向系統(tǒng)分區(qū)寫庫文件和程序文件如果這個系統(tǒng)分區(qū)正是待恢復(fù)的分區(qū)寫入動作可能覆蓋了待恢復(fù)的數(shù)據(jù)區(qū)域。解決恢復(fù)工作必須在獨(dú)立環(huán)境里進(jìn)行。我一般用一個帶 Live 系統(tǒng)的 U 盤啟動進(jìn)入系統(tǒng)后直接操作工具全部從 U 盤加載目標(biāo)分區(qū)只做只讀訪問。如果手頭沒有 Live 介質(zhì)也可以用另一臺機(jī)器把問題盤掛成從盤但掛載時務(wù)必注意不要讓它被自動掛載。5. 進(jìn)階用法用文件簽名定制與恢復(fù)日志擺脫黑匣子很多人用 photorec 時把它當(dāng)黑匣子掃到什么全憑運(yùn)氣。其實(shí) signature 文件本身就是可以定制的日志文件也能指導(dǎo)你驗(yàn)證和補(bǔ)掃。掌握這兩項(xiàng)恢復(fù)工作就從“碰運(yùn)氣”變成了“確定性操作”。photorec 的簽名定義文件位于/usr/share/photorec/file_sig.c里面每一條記錄包含文件類型、擴(kuò)展名、頭部簽名、尾部簽名和偏移量。比如 JPEG 的定義是頭部FF D8 FF E0偏移量為 0。你可以在文件末尾追加自定義的類型記錄格式為#define FILE_CUSTOM 999 { FILE_CUSTOM, custom, 0, CUSTOM-HEADER-, 0, NULL, 0, NULL, 0 },這條定義告訴 photorec 掃描時尋找以CUSTOM-HEADER-字符串開頭的扇區(qū)并把后續(xù)連續(xù)數(shù)據(jù)恢復(fù)為.custom文件偏移量為 0尾部由解析長度決定。追加完成后需要重新編譯 photorec。這在處理某個特定軟件生成的私有格式文件時很有用——當(dāng)內(nèi)置簽名列表里沒有它默認(rèn)掃描只能把這些數(shù)據(jù)當(dāng)作未知類型丟棄而定制簽名能做到定向撈取?;謴?fù)日志的問題也常被忽略。photorec 在掃描結(jié)束時會生成一個隱藏的photorec.ses會話文件。如果掃描中斷下次運(yùn)行選擇Resume可以從中斷點(diǎn)繼續(xù)而不是從頭開始。這算是一個后悔藥機(jī)制RT 場景下能讓幾小時的掃描不白跑。給恢復(fù)工作做驗(yàn)證時我會強(qiáng)制走一遍完整閉環(huán)先file抽查每個類型的代表文件再打開幾個關(guān)鍵文檔確認(rèn)內(nèi)容可讀最后用journalctl清掉系統(tǒng)里與該盤相關(guān)的掛載記錄防止下次開機(jī)自動掛載造成二次污染。這套動作堅持下來后我的恢復(fù)成功率從“看運(yùn)氣”變成了“大概率可預(yù)期”。說到底開源恢復(fù)工具給的是地基能否蓋起樓來取決于你有沒有在動手前三分鐘確認(rèn)過選型、鏡像和輸出目錄。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取