- 2025/08/15 Fri
-
I/O device error を吐いてコピーが中断されるファイルのサルベージ作業。
今回もこちらにお世話になる。強制ファイルコピープログラム:fcopy.exe
http://hyperstoneapple3.mydns.jp/fcopy/fcopy.htm
実行してみたところ、どうも途中から挙動がおかしい。
ソースを読んでみると、2GB までしか対応してない感じ。ファイルがでかすぎるせいか。
対応しよう。
とりあえず mingw-w64 の gcc でコンパイル。Releases · niXman/mingw-builds-binaries
https://github.com/niXman/mingw-builds-binaries/releases
win32 が4種類あるけど、i686 は 32bit用、msvcrt は Windows10 より前のものってことなので、x86_64-15.2.0-release-win32-seh-ucrt-rt_v13-rev0.7z をダウンロード。
解凍して bin にパスを通すだけ。
64bit でコンパイルされてるよねと long のサイズを確認したところ、4byte。あれ。【開発環境ほか 1-9】C/C++言語で、64bit環境上で動作するプログラムを作る際の技術的な注意点はありますか? | 図研エルミック
https://www.elwsc.co.jp/knowledge/6494/LLP64 :ポインタのみ64bit (Windows環境)
LP64 :long変数/ポインタが64bit (Linux等UNIX系環境)
Linux だと 64bit になるけど、Windows だと 32bit のままなんだっけ。
__int64 に置き換え。
次にアドレスを printf している個所を8桁から16桁に拡張したけど、8桁しか表示されず。[MSVC 2005] printf系で64Bit型整数に気をつけよう #VisualStudio - Qiita
https://qiita.com/chromabox/items/13f85e51afa9a875042cgccでは上位32Bitが切られて表示されます。書式文字列に%xを指定するのではなくて%llxとするとちゃんと表示できます。
%lx を %llx にする必要があると。
あとは、ファイル操作系の関数を 64bit 対応のものに置き換え。--- fcopy.c Sat Jun 06 15:30:02 2009 +++ fcopy64.c Fri Aug 15 10:51:02 2025 @@ -89 +89 @@ - long pos = 0; + __int64 pos = 0; @@ -179 +179 @@ - printf( "Read error at %08lX pos = %08lX\n", ftell( fi ), pos ); + printf( "Read error at %016llX pos = %016llX\n", _ftelli64( fi ), pos ); @@ -181 +181 @@ - fseek( fi, pos + buff_size, SEEK_SET ); + _fseeki64( fi, pos + buff_size, SEEK_SET );
こんな感じで。
修正版を実行。fcopy64 e:\foo.vhdx d:\foo.vhdx Read error at 00000000067A8000 pos = 00000000067A8000 Read error at 00000000067C8000 pos = 00000000067C8000 Read error at 00000000068F8000 pos = 00000000068F8000 Read error at 000000015EA58000 pos = 000000015EA58000 Total error count = 4 block(s) fcopy64 e:\bar.vhdx d:\bar.vhdx Read error at 0000000077600000 pos = 0000000077600000 Read error at 0000000077608000 pos = 0000000077608000 Read error at 0000000077610000 pos = 0000000077610000 Read error at 0000000077618000 pos = 0000000077618000 Read error at 0000000077620000 pos = 0000000077620000
(中略)Read error at 0000000077738000 pos = 0000000077738000 Read error at 0000000077740000 pos = 0000000077740000 Read error at 0000000077748000 pos = 0000000077748000 Read error at 0000000077750000 pos = 0000000077750000 Read error at 0000000077758000 pos = 0000000077758000 Total error count = 44 block(s)
32bit 超の領域もちゃんと処理されてますね。
にしても、エラー吐いてんなぁ!
1ブロック 32KB なので 1MB 程度ではあるものの、これはあくまで読み出せなかった領域。
他が破損してないというわけではないので、微妙なところ。
恐る恐る仮想マシンを起動してみたところ、両方起動。
イェーイ!
ただ起動はしたものの、chkdsk でめちゃくちゃエラー検出されてからの起動。
ネットワークドライブに繋がらなかったりと挙動も怪しいので再構築はしよう。
とりあえずデータを吸い出せる状態までは持っていけてよかった。