oopsの日記: NTFSの件その4
NTFSの圧縮によりファイルが壊れる件の続き。
チェックスクリプトを更新してみた。
ファイルが壊れるのは最後の部分のみが多いみたいで、前のスクリプトでは検出できない。1メガバイト以上のでかいファイルは壊れにくいけど(壊れた場合を見たことない)、数十キロバイト程度だと壊れる可能性がかなり高い。
出力は、
Broken?:4011:2:DF: t:/foo/bar.jpg
とか出るけど、Broken? は壊れたかもしれないというメッセージ、4011はファイルサイズ、2は可能性レベルで1より2の方が壊れてる可能性高い、DFは壊れたときに埋め込まれるコードでDFの場合はほぼ壊れたとみていい、それ以外の場合は壊れてない可能性が高い。ファイル末尾に00が並ぶ正常なファイルが多数あるので検出しないようにしてる。
検出性を優先しているので壊れてないファイルも出力される。ただ、壊れたファイルをすべて検出してくれるわけでもない。出力されたファイルはバイナリエディタで自分なりに検証することが必要。
今回も Ruby スクリプトだけど、C だと Find.find 相当のことやるとソースがかなりでかくなるし。
Microsoft からバグフィクスとともに壊れたファイルを検出してくれるツールも出してくれるのを期待。これはそれまでのつなぎと言うことで。
#!/usr/local/bin/ruby
require 'find'
def scan_broken(path,tail)
bsize = 1024
c0 = nil
begin
File.open(path,'rb') do |f|
f.seek(-tail,IO::SEEK_END) if tail != nil
c0 = f.getc
while buf = f.read(bsize)
buf.each_byte do |c|
return :ok if c != c0
end
end
end
rescue
return :err
end
return c0
end
def check_broken(path,size,aus=4096,min_tail=3000)
level = nil
tail = size % aus
tail = aus if tail == 0
if tail < min_tail
tail = min_tail
level = 1
else
level = 2
end
result = scan_broken(path,tail)
if result != :ok && result != :err && result != 0
return [level,result]
else
return [0,0]
end
end
def printm(buf,ios,is_flush=true)
ios.each do |io|
if io != nil
io.print(buf)
io.flush if is_flush
end
end
end
logfile = File.open("00check.log",'w')
aus = 4096
min_tail = 3000
$*.each do |root|
Find.find(root) do |path|
next if !test(?f,path)
st = File.stat(path)
next if st == nil || st.size < min_tail
level, code = check_broken(path,st.size,aus,min_tail)
if level > 0
printm("Broken?:#{st.size}:#{level}:#{format('%X',code)}: #{path}\n",[logfile,STDOUT])
end
end
end
logfile.close
NTFSの件その4 More ログイン