1from tarfile import TarFile, \ 2 TarInfo 3import os 4import stat 5from itertools import chain 6from .misc import filehash 7 8 9def normalized_recursive_directory_iterator(path): 10 Q = iter([ path ]) 11 name = next(Q, None) 12 while name: 13 st = os.lstat(name) 14 if stat.S_ISDIR(st.st_mode): 15 L = sorted(os.listdir(name)) 16 def create_map(name, L): 17 return map(lambda x: os.path.join(name, x), L) 18 L = create_map(name, L) 19 yield (os.path.relpath(name, path), name, st.st_mode, st.st_uid, st.st_gid, st.st_size, st.st_mtime) 20 Q = chain(L, Q) 21 else: # file 22 yield (os.path.relpath(name, path), name, st.st_mode, st.st_uid, st.st_gid, st.st_size, st.st_mtime) 23 name = next(Q, None) 24 25 26def _export_diff(mountpoint, origin_mountpoint, output_directory): 27 28 mit = normalized_recursive_directory_iterator(mountpoint) 29 oit = normalized_recursive_directory_iterator(origin_mountpoint) 30 31 def emit_removal(o): 32 print('Removal:', o[0]) 33 34 def emit_creation(m): 35 print('Creation:', m[0]) 36 37 def emit_compare(m, o): 38 if m[2] != o[2] or m[3] != o[3] or m[4] != o[4]: 39 print('Metadata change:', o[0]) 40 elif stat.S_ISREG(m[2]) and m[5] != o[5]: 41 print('Size change:', o[0]) 42 elif stat.S_ISREG(m[2]) and m[6] != o[6] and filehash(m[1]) != filehash(o[1]): 43 print('Content change:', o[0]) 44 else: # no change 45 pass # print('Compare:', m[0]) 46 47 m = next(mit, None) 48 o = next(oit, None) 49 while True: 50 if m is None and o is None: 51 break 52 elif m is None and o is not None: 53 emit_removal(o) 54 elif m is not None and o is None: 55 emit_creation(m) 56 elif m[0] < o[0]: 57 emit_creation(m) 58 m = next(mit, None) 59 elif m[0] > o[0]: 60 emit_removal(o) 61 o = next(oit, None) 62 elif stat.S_ISDIR(m[2]) != stat.S_ISDIR(o[2]): 63 emit_creation(m) 64 m = next(mit, None) 65 o = next(oit, None) 66 else: 67 emit_compare(m, o) 68 m = next(mit, None) 69 o = next(oit, None) 70 71 #for root, dirs, files in os.walk(path): 72 # dirs.sort() 73 # for dirname in dirs: 74 # print(os.path.join(root, dirname)) 75 76 77def command_export(args): 78 name, _ = zfs_find(args.reference, focker_type='image') 79 mountpoint = zfs_mountpoint(name) 80 origin = zfs_parse_output(['zfs', 'get', '-H', 'origin', name]) 81 origin = origin[2].split('@')[0] 82 origin_mountpoint = zfs_mountpoint(origin) 83 Q = [ zfs_mountpoint(name) ] 84 while len(Q) > 0: 85 el = Q.pop() 86