#!/usr/bin/env python import os import empty import tm_ut import base import cmd_ut to_str = base.to_str cmd_call = lambda cmd: cmd_ut.call( cmd, b2s=True ) cmd_lst = lambda cmd: sorted( cmd_call( cmd ).strip().split('\n') ) # fs # #define S_IFMT 0170000 /* type of file */ # #define S_IFIFO 0010000 /* named pipe (fifo) */ # #define S_IFCHR 0020000 /* character special */ # #define S_IFDIR 0040000 /* directory */ # #define S_IFBLK 0060000 /* block special */ # #define S_IFREG 0100000 /* regular */ # #define S_IFLNK 0120000 /* symbolic link */ # #define S_IFSOCK 0140000 /* socket */ # #define S_IFWHT 0160000 /* whiteout */ # #define S_ISUID 0004000 /* set user id on execution */ # #define S_ISGID 0002000 /* set group id on execution */ # #define S_ISVTX 0001000 /* save swapped text even after use */ # #define S_IRUSR 0000400 /* read permission, owner */ # #define S_IWUSR 0000200 /* write permission, owner */ # #define S_IXUSR 0000100 /* execute/search permission, owner */ mode_type_dic = { 'S_IFMT': 0o170000, 'S_IFIFO': 0o010000, 'S_IFCHR': 0o020000, 'S_IFDIR': 0o040000, 'S_IFBLK': 0o060000, 'S_IFREG': 0o100000, 'S_IFLNK': 0o120000, 'S_IFSOCK': 0o140000, 'S_IFWHT': 0o160000, 'S_ISUID': 0o004000, 'S_ISGID': 0o002000, 'S_ISVTX': 0o001000, 'S_IRUSR': 0o000400, 'S_IWUSR': 0o000200, 'S_IXUSR': 0o000100, } def is_mode_type(mode, name): mask = mode_type_dic.get( 'S_IFMT', 0 ) v = mode_type_dic.get( name, 0 ) return mode & mask == v is_mode_dir = lambda mode: is_mode_type( mode, 'S_IFDIR' ) is_mode_slink = lambda mode: is_mode_type( mode, 'S_IFLNK' ) def fs_new(mode, sec, size, path): def to_txt(): lst = ( oct( mode ), tm_ut.sec_to_str( sec, tm_ut.sample ), str( size ), path ) return to_str( lst, delim=' ' ) def eq_mode(o_mode): (a, b) = ( mode, o_mode ) is_allow_grp = ( lambda : ( is_mode_slink( a ) and is_mode_slink( b ) ) or ( is_mode_type( a, 'S_IFREG' ) and is_mode_type( b, 'S_IFREG' ) ) ) if is_allow_grp(): # 0120777 2018-10-13_00.36.06 13 argmnt/ido.sh # 0o120755 2018-10-13_00.36.06 13 argmnt/ido.sh mask_clr = 0o22 a &= ~mask_clr b &= ~mask_clr return a == b eq = lambda o: eq_mode( o.mode ) and o.sec == sec and o.size == size and o.path == path return empty.new( locals() ) def fs_new_path(dir_path, path): st = os.lstat( os.path.join( dir_path, path ) ) return fs_new( st.st_mode, int( st.st_mtime ), st.st_size, path ) def fs_new_str(s): lst = s.split( ' ' ) (mode, sec, size, path) = lst[:3] + [ to_str( lst[3:], delim=' ' ) ] return fs_new( int( mode, 8 ), tm_ut.str_to_sec( sec ), int( size ), path ) # snap def new_fss(fss, sec): get_paths = lambda : list( map( lambda fs: fs.path, fss ) ) get_txt = lambda: to_str( map( lambda fs: fs.to_txt(), fss ), last=True ) def write(fn): s = tm_ut.sec_to_str( sec, tm_ut.sample ) + '\n' + get_txt() with open( fn, 'w' ) as f: f.write( s ) return empty.new( locals() ) def new_dir(dir_path): sec = tm_ut.now_sec() dir_paths = cmd_lst( 'find {} -type f -o -type l'.format( dir_path ) ) # files and symlinks dir_paths = filter( lambda s: s, dir_paths ) paths = list( map( lambda s: os.path.relpath( s, start=dir_path ), dir_paths ) ) fss = list( map( lambda path: fs_new_path( dir_path, path ), paths ) ) return new_fss( fss, sec ) def new_fn(fn): s = '' with open( fn, 'r' ) as f: s = f.read().strip() lst = s.split( '\n' ) (sec, lst) = ( tm_ut.str_to_sec( lst[ 0 ] ), lst[ 1: ] ) fss = list( map( fs_new_str, lst ) ) return new_fss( fss, sec ) def cmp_new(snap_old, snap_new): old = snap_old.get_paths() new = snap_new.get_paths() rm = list( filter( lambda p: p not in new, old ) ) add = list( filter( lambda p: p not in old, new ) ) com = list( filter( lambda p: p in old, new ) ) fss_old = snap_old.fss fss_new = snap_new.fss fss_old_com = list( filter( lambda fs: fs.path in com, fss_old ) ) fss_new_com = list( filter( lambda fs: fs.path in com, fss_new ) ) (same, chg) = ( [], [] ) for (fs_a, fs_b) in zip( fss_old_com, fss_new_com ): if fs_a.eq( fs_b ): same.append( fs_b.path ) else: chg.append( fs_b.path ) is_same = lambda : not ( rm + add + chg ) e = empty.new() get_k_str = lambda k: to_str( getattr( e, k, '' ), pre=k+' ' ) def get_ks_str(ks): ks = filter( lambda k: getattr(e, k), ks ) return to_str( map( get_k_str, ks ) ) rm_add_chg_str = lambda : get_ks_str( ( 'rm', 'add', 'chg' ) ) return empty.to_attr( e, locals() ) # EOF