ドライブ間/ディレクトリ間のdiff

[`evernote` not found]
Bookmark this on Hatena Bookmark
Share on Facebook
LINEで送る

なんか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)