なんかwebに転がっていそうだけど,ちゃんと探さず実装.
python on cygwinで動作確認.
os.statを使っているので,多分シンボリックリンク辿ってしまう.
なんでこんなもんがいるのかっつーと,truecryptのストレージファイルをdropboxで共有していて,うっかりあるPCでマウントしたまま別のPCでもマウントしてしまうと,ストレージファイルのタイムスタンプが両方とも新しくなって競合が起こって,それぞれのPCでマウントしていたストレージファイルが両方残ってしまうから.
すぐその場で気付けばいいんだが,後で増殖しているのに気付いた場合,差分がどこにあるか把握するのが困難なので,全ファイル,全dirを比較して,どのファイル/dirがどう差分あるのか出力する.
linuxは忘れたけど,windowsでフォルダ配下に新規ファイルを作ったりファイルを消したりすると,ディレクトリのタイムスタンプが更新されてしまうので,無駄に差分が出力されるのを防ぐため,ディレクトリの時刻は比較しないことにした.
どうせ,そのディレクトリ配下で何かいじってたら,ファイルの差分として検出できるし.
import os,sys,stat
if len(sys.argv)<3:
sys.stderr.write("""Too few arguments!
Usage:
python diffdrive.py drivepath1 drivepath2
""")
sys.exit()
if not os.path.isdir(sys.argv[1]) or not os.path.isdir(sys.argv[2]):
sys.stderr.write("""input path is not found!
""")
sys.exit()
apath=sys.argv[1]
bpath=sys.argv[2]
def diffdir(apath,bpath,counter):
if counter>10000: return True
try:
alist=os.listdir(apath)
blist=os.listdir(bpath)
except OSError,ex:
if ex.errno == 13:
alist=[]
blist=[]
# permission error
else:
raise ex
tmplist=[]
nextlist=[]
for afile in alist:
# ignore fucking wasted file started by '._' which is created by Mac OS X
if afile[:2] == '._':
continue
if afile not in blist:
sys.stdout.write("< %s/%s\n"%(apath,afile))
counter+=1
else:
tmplist.append(afile)
for bfile in blist:
# ignore fucking wasted file started by '._' which is created by Mac OS X
if bfile[:2] == '._':
continue
if bfile not in alist:
sys.stdout.write("> %s/%s\n"%(bpath,bfile))
counter+=1
for abfile in tmplist:
astat=os.stat(apath+'/'+abfile)
bstat=os.stat(bpath+'/'+abfile)
amode=astat[stat.ST_MODE]
bmode=bstat[stat.ST_MODE]
asize=astat[stat.ST_SIZE]
bsize=bstat[stat.ST_SIZE]
atime=astat[stat.ST_MTIME]
btime=bstat[stat.ST_MTIME]
if stat.S_ISDIR(amode) and stat.S_ISDIR(bmode):
nextlist.append((apath+'/'+abfile,bpath+'/'+abfile))
elif stat.S_ISDIR(amode)==stat.S_ISDIR(bmode):
if asize==bsize and atime==btime: next
elif atime>btime:
sys.stdout.write("< %s/%s is newer\n"%(apath,abfile))
counter+=1
elif atime %s/%s is newer\n"%(bpath,abfile))
counter+=1
elif asize>bsize:
sys.stdout.write("< %s/%s is larger\n"%(apath,abfile))
counter+=1
elif asize %s/%s is larger\n"%(bpath,abfile))
counter+=1
else:
if stat.S_ISDIR(amode):
afiletype='DIR'
bfiletype='FILE'
else:
afiletype='FILE'
bfiletype='DIR'
sys.stdout.write("< %s/%s is %s\n> %s/%s is %s\n"\
%(apath,abfile,afiletype,bpath,abfile,bfiletype))
counter+=1
for nextpair in nextlist:
if diffdir(nextpair[0],nextpair[1],counter): return
return False
diffdir(apath,bpath,0)