俺とPhotoRec 〜誤って削除された、4GBを超えるTSファイルを救出する〜
前回のあらすじ
- WMPの操作を誤って、大量のTSファイルを削除してしまった!
- 4GB以下のTSファイルであれば、様々なフリーソフトで救出できた。
- だが、4GBを超えるファイルに対応するソフトがない!
PhotoRecというソフトは4GB超のファイルも救出できるが、
残念ながらTS形式に対応していない!諦めるしかないのか!?
しかし幸いにもPhotoRecはオープンソースであり、
比較的簡単に対応するファイル形式を追加できる仕様であった。
なのでソースコードを修正し、4GBを超えるTSファイルを救出してみた。
作業内容
MPEG2-TS形式について
実際のファイルを確認してみる
バイナリエディタでMPEG2-TS形式のファイル(.ts/.m2ts/.m2t)を調査してみる。
.m2ts/.m2tファイルについては、これらを出力する機器を持っていないので
Web上から各ファイルを*2探してきました
ソースコードからPhotoRec*5の動作を確認
MPEG2-TS形式の救出処理は、file_m2ts.cを参照。
- .m2tsファイル
- ファイル検索処理
0xd7にHDMVが存在すること - ヘッダ判定処理
- 0x04、0xc4(4+192)、0x184(2+4×192)の位置に、sync_byte(0x47)があること
(先頭から3パケット分のsync_byteをチェックしている模様) - かつ、0xd7と0x8eにHDMVが存在すること
- 0x04、0xc4(4+192)、0x184(2+4×192)の位置に、sync_byte(0x47)があること
- ファイル検索処理
- .m2tファイル
- ファイル検索処理
0x18bにTSHVが存在すること - ヘッダ判定処理
- 0x00、0xbc、0x178(2×188)の位置に、sync_byte(0x47)があること
(先頭から3パケット分のsync_byteをチェックしている模様) - かつ、0x18bにTSHVが存在すること
- 0x00、0xbc、0x178(2×188)の位置に、sync_byte(0x47)があること
- ファイル検索処理
上記から分かること
- .tsファイルについては、ファイル先頭のsync_byte(0x47)で引っかけるしかなさそう。
- しかし0x47はパケットの先頭以外(パケット内)にも登場するので、
単純に0x47だけを見るわけにはいかない。
PhotoRec:対応ファイルフォーマットの追加方法
オフィシャルサイトのwikiを参照。
Developers - CGSecurity
- 救出処理を書いたsrc/file_ts.cを新規作成
- src/file_list.cに追記
- src/Makefile.amに追記
上記を踏まえたコード:file_ts.c
- ファイル先頭のsync_byte(0x47)でファイルを検索
- 念の為、先頭5パケット分のsync_byte位置を確認する
- 最小ファイルサイズを4GB(4,294,967,296byte)に設定*6
- 後はfile_m2ts.cの処理を流用
#ifdef HAVE_CONFIG_H #include <config.h> #endif #ifdef HAVE_STRING_H #include <string.h> #endif #include <stdio.h> #include "types.h" #include "filegen.h" static void register_header_check_ts(file_stat_t *file_stat); /* TS */ static int header_check_ts(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new); static int data_check_ts(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); const file_hint_t file_hint_ts= { .extension="ts", .description="MPEG-2 TS(4GB over)", .min_header_distance=0, .max_filesize=PHOTOREC_MAX_FILE_SIZE, .recover=1, .enable_by_default=1, .register_header_check=®ister_header_check_ts }; static const unsigned char ts_header[1]= {0x47}; static void register_header_check_ts(file_stat_t *file_stat) { register_header_check(0, ts_header, sizeof(ts_header), &header_check_ts, file_stat); } static int header_check_ts(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) { if(file_recovery!=NULL && file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_ts && file_recovery->calculated_file_size == file_recovery->file_size) return 0; /* Each frame is 188 byte long and begins by a TS_SYNC_BYTE */ if(buffer[0]==0x47 && buffer[188]==0x47 && buffer[2*188]==0x47 && buffer[3*188]==0x47 && buffer[4*188]==0x47 && buffer[5*188]==0x47) { reset_file_recovery(file_recovery_new); file_recovery_new->extension=file_hint_ts.extension; file_recovery_new->min_filesize=4294967296; file_recovery_new->calculated_file_size=188; file_recovery_new->data_check=&data_check_ts; file_recovery_new->file_check=&file_check_size; return 1; } return 0; } static int data_check_ts(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) { while(file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2) { unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2; if(buffer[i]!=0x47) /* TS_SYNC_BYTE */ return 2; file_recovery->calculated_file_size+=188; } return 1; }
PhotoRec:コンパイル環境の構築とコンパイル
オフィシャルサイトのwikiを見れば、俺でも理解できたので割愛
TestDisk Compilation - CGSecurity
PhotoRecの使い方
こちらが大変詳しいので割愛
「PhotoRec」の使い方 - PCと解
※[File Opt]の設定で、TSにだけチェック(X印)を入れて実行すること。
他の拡張子と一緒に救出しようとすると、上手く行かない可能性があります。
最後に
当方の環境では、5GB〜33GB程度のファイルでも救出できました。
とはいえあまりスマートじゃない方法*7なので、参考程度でお願いします。
より良い判定方法をご存じの方は、是非教えて戴きたく。
あとかなり雑なエントリなので、いずれ全般的に追記修正したいと思います。