- #前提
朋友的移動硬碟,插入電腦識别很慢很慢,求救與我,讓我幫忙恢複其中的照片。
硬碟資訊為:
# sudo fdisk -l /dev/sdb
Disk /dev/sdb: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x24711ea6
Device Boot Start End Sectors Size Id Type
/dev/sdb1 63 1953520064 1953520002 931.5G 7 HPFS/NTFS/exFAT
硬碟為1TiB的機械硬碟,西部資料,2013年購買的,使用很多年了。
- #首次嘗試
windows下檢測與恢複壞道,使用工具:Diskgenius ,winhex ,hddtune pro ,以及winPE 工具箱(大白菜,老毛桃,微PE,PE工具箱) ,還有一個修複壞道的古老神器 硬碟再生器 hdd regeneration 。
發現windows反應很慢,說明windows在加載硬碟資訊,但是讀取很慢,還把windows給卡住了(說明,某些IO操作沒有進行異步處理,導緻UI界面假死)。
檢測很慢,進度未知,軟體卡死,于是不操作,等待UI 界面恢複。檢測壞道不是很多,就是讀取很慢。
有時候 使用windows自帶的 chkdsk 很管用,是以 使用 chkdsk /f /x /r I: 來修複,大約等待2-4個小時候(電腦重新開機,在開機界面進行移動硬碟分區的錯誤檢查 chkdsk),chkdsk程式異常終止退出,無法完全修複,但是也修複了一部分。
進入到windows以後,等待一段時間(大概十幾分鐘),盤符顯示容量了,檔案清單也可以檢視了,直接開始複制資料。
大約有 600GB資料 / 931GB總資料 ,根目錄就三個目錄,于是進入三級目錄,開始複制到本地硬碟,嘗試用了fastcopy,但是硬碟會斷線重連,就是與電腦斷開連接配接,等過段時間又恢複連接配接,結果這種 裝置IO錯誤,導緻這些軟體大量報錯,無法恢複進度。
于是,我幹脆使用windows explorer 自帶的複制功能,當出現錯誤,會彈出報錯,等待一段時間後,點選重試,可以繼續複制。
但是檔案數量很多,發生這種裝置斷線重連的情況也比較多,我必須一直在電腦面前看着,不能夠自動化,但就這樣,恢複了幾天,大概恢複了接近100GB 的資料,然後就恢複不動了,錯誤更頻繁,沒辦法自動化。
- #嘗試使用linux下的工具,dd 指令進行恢複
安裝了一個ubuntu,開始嘗試dd指令
發現 linux 真是好,裝置IO是異步,你不會感覺很卡。
首先用dd指令來複制到檔案中,指令大緻為:
sudo dd if=/dev/sdb1 of=seagate_disk2.img iflag=skip_bytes oflag=seek_bytes skip=187097939968 seek=187097939968
其中skip和seek 為失敗或取消後,要繼續恢複的進度,這裡是連續恢複的,不能斷。大小根據 ls *.img檔案來擷取的。
linux也有裝置斷線重連的情況,并且有時候 裝置名稱還發生了變化,變成 /dev/sdd1 sde1,是以寫腳本,優化輸入裝置為:
devAbs=/dev/disk/by-uuid/4458199458198638
devAbs=/dev/disk/by-path/pci-0000:00:1d.0-usb-0:1.1:1.0-scsi-0:0:0:0-part1
devAbs=/dev/disk/by-id/usb-ATA_WDC_WD10JPVT-00A_0123456789AE036-0:0-part1
發現,還是 by-id 好,裝置連接配接和裝置基礎資訊不會變,由于要自己控制 skip 和seek 也就是進度情況,恢複了幾天,腳本不斷優化,恢複了200多GB的資料了。
後來突然發現腳本有bug,斷線後判斷檔案大小錯了,進度中有空白了,哎,麻煩,準備換工具。
花了幾天,已經恢複的200多GB的檔案,使用 dd 來寫入到準備好的 2TiB移動硬碟的第四個分區 ,專門準備了硬碟,騰出1TiB空間,來寫入
dd if=/dev/disk/by-id/usb-ATA_WDC_WD10JPVT-00A_0123456789AE036-0:0-part1 of=/dev/sdc4 status=progress
開始使用其他方法,來簡化,來提高可靠性和效率。
- #嘗試不用dd,使用 ddrescue
看到網上說linux 硬碟恢複工具,有個ddrescue 可以有很好的進度控制,與我的想法不謀而合,于是切換到 ddrescue。
大緻指令是:
dev="/dev/disk/by-id/usb-ATA_WDC_WD10JPVT-00A_0123456789AE036-0:0-part1"
dev="/dev/disk/by-id/ata-WDC_WD10JPVT-00A1YT0_WD-WX51AA2L2462-part1"
backupdev="/dev/disk/by-id/usb-WD_Elements_1048_575831314532334459363036-0:0-part4"
mapFile=test.map
while true;do
echo "-----------start--------"
# maxsize --size=1000204886016
# -R 反序,從後向前
# -P3 預覽16*3位元組資料,1-32 範圍限制; -P domainFile 是對比的意思
# -d 直接io -D equal output-direct-io
sudo ddrescue --cpass=1,5 -v -v -P4 -v -i 200GiB --size 931GiB --log-events=test.event.log --log-rates=test.rate.log --log-reads=test.read.log --force $dev $backupdev $mapFile
ret=$?;echo result=$ret;
if test $ret -eq 0;then exit 0;fi;
sleep 6;
done
加三個-v可以檢視更詳細的顯示資訊,-P4可以預覽資料,太棒了。
ddrescue的一個最大的好處是 mapFile 他可以記錄進度,即使中斷,下次在執行這個指令,他會檢測已恢複的進度,并繼續恢複。
但是這個硬碟是在是太慢了,ddrescue 顯示的進度如下(這個僅供參考):
GNU ddrescue 1.25
About to copy 1991 MBytes from '/dev/sdb1' [UNKNOWN] (1_000_202_241_024) to 'mft.img' (501_887_852_544)
Starting positions: infile = 0 B, outfile = 0 B
Copy block size: 128 sectors Initial skip size: 19584 sectors
Sector size: 512 Bytes
Direct in: no Direct out: no Sparse: no Truncate: no
Trim: no Scrape: no Max retry passes: 0
Reverse mode
Press Ctrl-C to interrupt
Initial status (read from mapfile)
current position: 500183 MB, current sector: 976920960
last block size: 498314 MB
(sizes limited to domain from 0 B to 501_887_852_544 B of 1_000_202_241_024 B)
rescued: 336711 kB, tried: 655360 B, bad-sector: 0 B, bad areas: 0
Current status
Data preview:
74A8580000 46 49 4C 45 2A 00 03 00 00 00 00 00 00 00 00 00 FILE*...........
74A8580010 01 00 00 00 30 00 00 00 28 01 00 00 00 04 00 00 ....0...(.......
74A8580020 00 00 00 00 00 00 00 00 06 00 04 00 00 00 00 00 ................
74A8580030 10 00 00 00 60 00 00 00 00 00 00 00 00 00 00 00 ....`...........
ipos: 501040 MB, non-trimmed: 1015 kB, current rate: 16384 B/s
opos: 501040 MB, non-scraped: 0 B, average rate: 41707 B/s
non-tried: 995950 kB, bad-sector: 0 B, error rate: 0 B/s
rescued: 994070 kB, bad areas: 0, run time: 4h 22m 41s
pct rescued: 49.92%, read errors: 6, remaining time: 9h 56m
time since last successful read: 0s
Copying non-tried blocks... Pass 1 (backwards)
速度到了一百多Kb甚至更低,有時候快,有時候慢,感覺要恢複2年的時間。
由于這個ddrescue是全盤克隆,一些不是用的空間也會克隆,極大的浪費了時間。
分區克隆,全盤克隆也有一些其他的軟體,比如ghost,diskgenius等,但是他們光是打開就卡住了,不像linux的ddrescue等軟體,完全不卡,是以沒辦法用ghost等工具。
- #新想法,這個是NTFS檔案系統,我想按照檔案來恢複,而不是全盤恢複。
之前通過apt安裝了 ntfs相關的軟體,以及檔案恢複相關的軟體,有下面的這些指令
anmingwei@ubuntu-wubi1:~$ ntfs
ntfs-3g ntfscmp ntfsinfo ntfsresize ntfswipe
ntfs-3g.probe ntfscp ntfslabel ntfssecaudit
ntfscat ntfsdecrypt ntfsls ntfstruncate
ntfsclone ntfsfallocate ntfsmove ntfsundelete
ntfscluster ntfsfix ntfsrecover ntfsusermap
anmingwei@ubuntu-wubi1:~$ ddr
ddrescue ddrescueview ddru_findbad ddru_ntfsfindbad
ddrescuelog ddru_diskutility ddru_ntfsbitmap ddrutility
我想研究下NTFS結構,把$MFT裡面記錄的檔案所占用的磁盤扇區給列印出來,然後按照扇區恢複檔案,這樣豈不是很好。
通過 ntfsls ntfscat ntfsclone 指令,我發現可以,隻是ntfs-3g 無法儲存進度,一旦裝置斷線重連,一切就白費了。我想是不是可以研究下源碼,改造下。
于是下載下傳了ntfs-3g的源碼,編譯很簡單,标準的linux configure makefile 方式。
開始分析源碼,從ntfsclone ntfscat 開始分析,發現有點困難,源碼缺少注釋,我缺少ntfs專業知識,隻知道大概,改了一下,但是裝置斷線重連依舊繼續報錯,無法繼續導出資料。
想要導出$MFT 但是一定會遇到裝置自動斷線重連,windows NTFS檔案系統加載慢就是因為這些重要檔案有壞道,我現在的目标就是$MFT。
之前恢複的200+資料,在windows用winhex檢視,發現不完整,說明MFT所在扇區并沒有克隆出來。
今天突然發現 ddru_ntfsbitmap 這個指令,檢視了 sf.net 上 ddrutility的文檔,發現這個工具就是我想要的。
通過ddru_ntfsbitmap 可以擷取 ddrescue的 domain mapfile ,我一直琢磨這個 domain mapfile 根mapfile的差別呢?
這才發現: domain mapfile 中的rescue的資料,可以作為清單來讓ddrescue使用,ddrescue隻恢複清單指定的資料
比如:生成sdb1 NTFS檔案系統的 $MFT 和 $bitmap 的 domain mapfile 就是下面的指令了
sudo ddru_ntfsbitmap -D -V -m ___mft.log /dev/sdb1 ddru_ntfsbitmap.log
ddru_ntfsbitmap 1.5 20150111
Reading boot sector...
command = ddrescue -i0 -o0 -s512 /dev/sdb1 '__bootsec' '__bootsec.log'
GNU ddrescue 1.25
Press Ctrl-C to interrupt
Initial status (read from mapfile)
(sizes limited to domain from 0 B to 512 B of 1_000_202_241_024 B)
rescued: 512 B, tried: 0 B, bad-sector: 0 B, bad areas: 0
Current status
ipos: 0 B, non-trimmed: 0 B, current rate: 0 B/s
opos: 0 B, non-scraped: 0 B, average rate: 0 B/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 512 B, bad areas: 0, run time: 0s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
Reading bitmap inode from mft...
command = ddrescue -i3221225472 -o0 -s16384 /dev/sdb1 '__mftshort' '__mftshort.log'
GNU ddrescue 1.25
Press Ctrl-C to interrupt
Initial status (read from mapfile)
(sizes limited to domain from 3_221_225_472 B to 3_221_241_856 B of 1_000_202_241_024 B)
rescued: 16384 B, tried: 0 B, bad-sector: 0 B, bad areas: 0
Current status
ipos: 0 B, non-trimmed: 0 B, current rate: 0 B/s
opos: -3221 MB, non-scraped: 0 B, average rate: 0 B/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 16384 B, bad areas: 0, run time: 0s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
Creating MFT domain logfile...
total mft fragments = 2
mft part 0 offset=0xC0000000 size=0xE000000
mft part 1 offset=0x74722C2000 size=0x68ACC000
............Reading part 0 of $Bitmap...........
command = ddrescue -i500101173248 -o0 -s30527488 /dev/sdb1 '__bitmapfile' '_part0__bitmapfile.log'
GNU ddrescue 1.25
Press Ctrl-C to interrupt
Initial status (read from mapfile)
(sizes limited to domain from 500_101_173_248 B to 500_131_700_736 B of 1_000_202_241_024 B)
rescued: 30527 kB, tried: 0 B, bad-sector: 0 B, bad areas: 0
Current status
ipos: 0 B, non-trimmed: 0 B, current rate: 0 B/s
opos: -500101 MB, non-scraped: 0 B, average rate: 0 B/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 30527 kB, bad areas: 0, run time: 0s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
............ Done reading part 0 of $Bitmap...........
Creating ddrescue domain logfile...
end = 1000202305536
total_size = 1000202241024
Finished creating logfile
total= 1000202305536 bytes
used= 687635582976 (68.75%)
free= 312566722560 (31.25%)
ddru_ntfsbitmap took 3.713145 seconds to complete
View Code
ddru_ntfsbitmap 這個程式好,調用了 ddrescue 以及 ntfs-3g 來分析ntfs資訊,并儲存了 domain mapfile,那麼接下來就可以用 domain mapfile來恢複NTFS最重要的資料了
我先用我的 2TiB移動硬碟的第四個分區 (也就是作之前鏡像的載體,目前還不完整)作實驗
sudo ddrescue -m ___mft.log /dev/sdc4 mft_2.img mft_2.map.log -v -v -v -P4
GNU ddrescue 1.25
About to copy 1991 MBytes from '/dev/sdc4' [UNKNOWN] (1_036_170_297_344) to 'mft_2.img' (0)
Starting positions: infile = 0 B, outfile = 0 B
Copy block size: 128 sectors Initial skip size: 20352 sectors
Sector size: 512 Bytes
Direct in: no Direct out: no Sparse: no Truncate: no
Trim: yes Scrape: yes Max retry passes: 0
Press Ctrl-C to interrupt
Data preview:
74DAD80000 42 61 64 53 65 63 74 6F 52 00 3F 3F 3F 3F 3F 3F BadSectoR.??????
74DAD80010 3F 3F 3F 3F 3F 3F 3E 3F 3F 3F 3F 3F 3F 3F 3F 3F ??????>?????????
74DAD80020 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F ????????????????
74DAD80030 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F ????????????????
ipos: 501887 MB, non-trimmed: 0 B, current rate: 29548 kB/s
opos: 501887 MB, non-scraped: 0 B, average rate: 26905 kB/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 1991 MB, bad areas: 0, run time: 1m 13s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
可以看到 1991MB 就是$MFT 的大小,花了1分鐘13妙。由于這個分區MFT是不完整的,是以隻是測試而以。可以看到資料預覽有點 BadSectoR 字樣(但并不是壞道,不知道是什麼時候克隆MFT失敗,被克隆程式寫入的資訊吧)
按照這個套路,我就把壞道硬碟的NTFS檔案系統的MFT先恢複處理,處理以下,隻保留想要的檔案,然後再導出 ntfsbitmap domain mapfile ,隻恢複bitmap 使用到的資料。
但是現在這個壞道硬碟用ddrescue導出這個1991MB的時間就要十幾個小時:
$ sudo ddrescue -P4 -v -v -v -d -r2 -m ___mft.log /dev/sdb1 mft.img mft.map.log
GNU ddrescue 1.25
About to copy 1991 MBytes from '/dev/sdb1' [UNKNOWN] (1_000_202_241_024) to 'mft.img' (501_887_852_544)
Starting positions: infile = 0 B, outfile = 0 B
Copy block size: 128 sectors Initial skip size: 19584 sectors
Sector size: 512 Bytes
Direct in: no Direct out: no Sparse: no Truncate: no
Trim: no Scrape: no Max retry passes: 0
Reverse mode
Press Ctrl-C to interrupt
Initial status (read from mapfile)
current position: 500183 MB, current sector: 976920960
last block size: 498314 MB
(sizes limited to domain from 0 B to 501_887_852_544 B of 1_000_202_241_024 B)
rescued: 336711 kB, tried: 655360 B, bad-sector: 0 B, bad areas: 0
Current status
Data preview:
74A48F0000 46 49 4C 45 2A 00 03 00 00 00 00 00 00 00 00 00 FILE*...........
74A48F0010 01 00 00 00 30 00 00 00 28 01 00 00 00 04 00 00 ....0...(.......
74A48F0020 00 00 00 00 00 00 00 00 06 00 04 00 00 00 00 00 ................
74A48F0030 10 00 00 00 60 00 00 00 00 00 00 00 00 00 00 00 ....`...........
ipos: 500976 MB, non-trimmed: 1015 kB, current rate: 32768 B/s
opos: 500976 MB, non-scraped: 0 B, average rate: 40664 B/s
non-tried: 932446 kB, bad-sector: 0 B, error rate: 0 B/s
rescued: 1057 MB, bad areas: 0, run time: 4h 55m 27s
pct rescued: 53.11%, read errors: 6, remaining time: 11h 23m
time since last successful read: 0s
Copying non-tried blocks... Pass 1 (backwards)
還有1015MB 的資料沒有嘗試恢複,等在過一天,恢複了大部分,我再嘗試恢複這小部分資料。
----append
經過一夜和一上午的恢複,已經恢複了99.99% 的MFT資料了,剩下4KB無論如何也恢複不了了 (期間要用 while true; do $CMD; done 的方式重複運作這個指令)。
$ sudo ddrescue -P4 -v -v -v -d -r2 -m ___mft.log /dev/sdb1 mft.img mft.map.log;
GNU ddrescue 1.25
About to copy 1991 MBytes from '/dev/sdb1' [UNKNOWN] (1_000_202_241_024) to 'mft.img' (501_887_852_544)
Starting positions: infile = 0 B, outfile = 0 B
Copy block size: 128 sectors Initial skip size: 19584 sectors
Sector size: 512 Bytes
Direct in: yes Direct out: no Sparse: no Truncate: no
Trim: yes Scrape: yes Max retry passes: 2
Press Ctrl-C to interrupt
Initial status (read from mapfile)
current position: 500213 MB, current sector: 976978626
last block size: 498314 MB
(sizes limited to domain from 0 B to 501_887_852_544 B of 1_000_202_241_024 B)
rescued: 1991 MB, tried: 4096 B, bad-sector: 4096 B, bad areas: 4
Current status
Data preview:
No data available
ipos: 500213 MB, non-trimmed: 0 B, current rate: 0 B/s
opos: 500213 MB, non-scraped: 0 B, average rate: 0 B/s
non-tried: 0 B, bad-sector: 4096 B, error rate: 128 B/s
rescued: 1991 MB, bad areas: 4, run time: 1m 7s
pct rescued: 99.99%, read errors: 16, remaining time: n/a
time since last successful read: n/a
Retrying bad sectors... Retry 1 (forwards)
Retrying bad sectors... Retry 2 (backwards)
Finished
###恢複到 我的2TiB硬碟的第四個分區
$ sudo ddrescue -m ___mft.log -v -v -v -P4 --force mft.img /dev/sdc4
GNU ddrescue 1.25
About to copy 1991 MBytes from 'mft.img' (501_887_852_544) to '/dev/sdc4' [UNKNOWN] (1_036_170_297_344)
Starting positions: infile = 0 B, outfile = 0 B
Copy block size: 128 sectors Initial skip size: 9856 sectors
Sector size: 512 Bytes
Direct in: no Direct out: no Sparse: no Truncate: no
Trim: yes Scrape: yes Max retry passes: 0
Press Ctrl-C to interrupt
Data preview:
74DAD80000 46 49 4C 45 30 00 03 00 87 60 3A 36 00 00 00 00 FILE0....`:6....
74DAD80010 01 00 02 00 38 00 01 00 00 02 00 00 00 04 00 00 ....8...........
74DAD80020 00 00 00 00 00 00 00 00 09 00 00 00 F8 AA 1D 00 ................
74DAD80030 56 01 47 11 00 00 00 00 10 00 00 00 60 00 00 00 V.G.........`...
ipos: 501887 MB, non-trimmed: 0 B, current rate: 19849 kB/s
opos: 501887 MB, non-scraped: 0 B, average rate: 37566 kB/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 1991 MB, bad areas: 0, run time: 52s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
這個就快了,後續修改了硬碟的MFT 後不滿意,還可以恢複,這個 mft.img 鏡像檔案一定要保留着。
- #補充 和 mapfile 相關的指令
可以通過這個指令來檢視 mapfile 的概況 (指令行)
$ ddrescuelog -t ddru_ntfsbitmap.log
current pos: 0 B, current status: finished
mapfile extent: 1000 GB, in 39077 area(s)
non-tried: 312566 MB, in 19538 area(s) ( 31.25%)
rescued: 687635 MB, in 19539 area(s) ( 68.74%)
non-trimmed: 0 B, in 0 area(s) ( 0%)
non-scraped: 0 B, in 0 area(s) ( 0%)
bad-sector: 0 B, in 0 area(s) ( 0%)
上面作為domain mapfile 的話,隻會恢複 rescued: 687635 MB 這麼多的資料。但還是太多,是以我要先恢複MFT 想辦法删除一些檔案,再生成新的ntfsbitmap 的mapfile。
也可以通過 ddrescueview 來通過GUI 的方式來檢視 mapfile (内心淚流滿面)
下面 就是我恢複了這麼久的map圖(我嫌順序恢複慢,嘗試跳着恢複的,還是慢,今天合并了mapfile,就是下圖的進度了)
合并多個mapfile的方式為:
for d in `find . -maxdepth 1 -type d `;do ddrescue -v -v -v --force --same-file -s 1TiB -m $d/test.map /dev/zero /dev/zero mergedall.map ;done
通過 dev/zero 假設性的恢複别的mapfile(當作 domain mapfile) 指定恢複到一個 mergeall.map 中,就可以實作 合并mapfile 了。之前還想寫個程式呢,這樣就不用了,一行指令搞定。
----append
發現 ddrescuelog 程式也可以作這個事情:
$ ddrescuelog -h
...
Usage: ddrescuelog [options] mapfile
Options:
...
-A, --annotate-mapfile add comments with human-readable pos/sizes
-x, --xor-mapfile=<file> XOR the finished blocks in file with mapfile
-y, --and-mapfile=<file> AND the finished blocks in file with mapfile
-z, --or-mapfile=<file> OR the finished blocks in file with mapfile
其中 -A 選項可以對mapfile 增加注釋,關于起始位置可讀性的,比如
$ ddrescuelog -v -v -v -A ddru_ntfsbitmap.log
...
0xE86429C000 0x000CA000 + # 998112 MB 827392
0xE864366000 0x0002E000 ? # 998113 MB 188416
0xE864394000 0x7C79A000 + # 998113 MB 2088 MB
0xE8E0B2E000 0x00002000 ? # 1000 GB 8192
0xE8E0B30000 0x00010000 + # 1000 GB 65536
轉載請注明出處:http://www.cnblogs.com/ayanmw 多謝
------------------------------------------------------------------------------------------------
一定要專業!本部落格定位于 ,C語言,C++語言,Java語言,Android開發和少量的Web開發,之前是做Web開發的,其實就是ASP維護,發現EasyASP這個好架構,對前端後端資料庫 都很感覺親切啊。.
linux,總之背景開發多一點。以後也願意學習 cocos2d-x 遊戲用戶端的開發。