diff --git a/dedupestore/archiver.py b/dedupestore/archiver.py index f629803c3..0c0396d66 100644 --- a/dedupestore/archiver.py +++ b/dedupestore/archiver.py @@ -11,7 +11,8 @@ import msgpack from .chunkifier import chunkify from .cache import Cache, NS_ARCHIVES, NS_CHUNKS from .bandstore import BandStore -from .helpers import location_validator, pretty_size, LevelFilter +from .helpers import location_validator, pretty_size, LevelFilter, \ + uid2user, user2uid, gid2group, group2gid CHUNK_SIZE = 55001 @@ -110,6 +111,14 @@ class Archive(object): raise Exception('Invalid chunk checksum') data = zlib.decompress(data) fd.write(data) + os.chmod(path, item['mode']) + uid = user2uid(item['user']) or item['uid'] + gid = group2gid(item['group']) or item['gid'] + try: + os.chown(path, uid, gid) + except OSError: + pass + os.utime(path, (item['ctime'], item['mtime'])) def verify(self): for item in self.items: @@ -189,7 +198,13 @@ class Archive(object): for chunk in chunkify(fd, CHUNK_SIZE, 30): size += len(chunk) chunks.append(self.add_chunk(*self.cache.add_chunk(chunk))) - self.items.append({'type': 'FILE', 'path': path, 'chunks': chunks, 'size': size}) + self.items.append({ + 'type': 'FILE', 'path': path, 'chunks': chunks, 'size': size, + 'mode': st.st_mode, + 'uid': st.st_uid, 'user': uid2user(st.st_uid), + 'gid': st.st_gid, 'group': gid2group(st.st_gid), + 'ctime': st.st_ctime, 'mtime': st.st_mtime, + }) class Archiver(object): diff --git a/dedupestore/helpers.py b/dedupestore/helpers.py index fe4f12271..a639b30fd 100644 --- a/dedupestore/helpers.py +++ b/dedupestore/helpers.py @@ -1,10 +1,51 @@ import logging import argparse import re +import grp +import pwd +def memoize(function): + cache = {} + def decorated_function(*args): + try: + return cache[args] + except KeyError: + val = function(*args) + cache[args] = val + return val + return decorated_function + +@memoize +def uid2user(uid): + try: + return pwd.getpwuid(uid).pw_name + except KeyError: + return None + +@memoize +def user2uid(user): + try: + return pwd.getpwnam(user).pw_uid + except KeyError: + return None + +@memoize +def gid2group(gid): + try: + return grp.getgrgid(gid).gr_name + except KeyError: + return None + +@memoize +def group2gid(group): + try: + return grp.getgrnam(group).gr_gid + except KeyError: + return None class LevelFilter(logging.Filter): - + """Filter that counts record levels + """ def __init__(self, *args, **kwargs): logging.Filter.__init__(self, *args, **kwargs) self.count = {} @@ -15,7 +56,6 @@ class LevelFilter(logging.Filter): return record - class Location(object): loc_re = re.compile(r'^((?:(?P[^@]+)@)?(?P[^:]+):)?'