1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-27 10:18:12 +00:00

support hardlinks via create_helper context manager

also: reduce code duplication
This commit is contained in:
Thomas Waldmann 2017-03-26 13:51:04 +02:00
parent e5d094d0ce
commit 9478e8abd0

View file

@ -834,34 +834,54 @@ def stat_attrs(self, st, path):
attrs.update(self.stat_ext_attrs(st, path)) attrs.update(self.stat_ext_attrs(st, path))
return attrs return attrs
def process_dir(self, path, st): @contextmanager
item = Item(path=make_path_safe(path)) def create_helper(self, path, st, status=None):
item.update(self.stat_attrs(st, path)) safe_path = make_path_safe(path)
item = Item(path=safe_path)
hardlink_master = False
hardlinked = st.st_nlink > 1
if hardlinked:
source = self.hard_links.get((st.st_ino, st.st_dev))
if source is not None:
item.source = source
status = 'h' # hardlink (to already seen inodes)
else:
hardlink_master = True
yield item, status, hardlinked, hardlink_master
# if we get here, "with"-block worked ok without error/exception, the item was processed ok...
self.add_item(item) self.add_item(item)
return 'd' # directory # ... and added to the archive, so we can remember it to refer to it later in the archive:
if hardlink_master:
self.hard_links[(st.st_ino, st.st_dev)] = safe_path
def process_dir(self, path, st):
with self.create_helper(path, st, 'd') as (item, status, hardlinked, hardlink_master): # directory
item.update(self.stat_attrs(st, path))
return status
def process_fifo(self, path, st): def process_fifo(self, path, st):
item = Item(path=make_path_safe(path)) with self.create_helper(path, st, 'f') as (item, status, hardlinked, hardlink_master): # fifo
item.update(self.stat_attrs(st, path)) item.update(self.stat_attrs(st, path))
self.add_item(item) return status
return 'f' # fifo
def process_dev(self, path, st): def process_dev(self, path, st):
item = Item(path=make_path_safe(path), rdev=st.st_rdev) with self.create_helper(path, st, None) as (item, status, hardlinked, hardlink_master): # no status yet
item.rdev = st.st_rdev
item.update(self.stat_attrs(st, path)) item.update(self.stat_attrs(st, path))
self.add_item(item)
if stat.S_ISCHR(st.st_mode): if stat.S_ISCHR(st.st_mode):
return 'c' # char device return 'c' # char device
elif stat.S_ISBLK(st.st_mode): elif stat.S_ISBLK(st.st_mode):
return 'b' # block device return 'b' # block device
def process_symlink(self, path, st): def process_symlink(self, path, st):
with self.create_helper(path, st, 's') as (item, status, hardlinked, hardlink_master): # symlink
with backup_io('readlink'): with backup_io('readlink'):
source = os.readlink(path) source = os.readlink(path)
item = Item(path=make_path_safe(path), source=source) item.source = source # XXX this overwrites hardlink slave's usage of item.source
if hardlinked:
logger.warning('hardlinked symlinks will be extracted as non-hardlinked symlinks!')
item.update(self.stat_attrs(st, path)) item.update(self.stat_attrs(st, path))
self.add_item(item) return status
return 's' # symlink
def write_part_file(self, item, from_chunk, number): def write_part_file(self, item, from_chunk, number):
item = Item(internal_dict=item.as_dict()) item = Item(internal_dict=item.as_dict())
@ -925,18 +945,7 @@ def process_stdin(self, path, cache):
return 'i' # stdin return 'i' # stdin
def process_file(self, path, st, cache, ignore_inode=False): def process_file(self, path, st, cache, ignore_inode=False):
status = None with self.create_helper(path, st, None) as (item, status, hardlinked, hardlink_master): # no status yet
safe_path = make_path_safe(path)
item = Item(path=safe_path)
hardlink_master = False
hardlinked = st.st_nlink > 1
if hardlinked:
source = self.hard_links.get((st.st_ino, st.st_dev))
if source is not None:
item.source = source
status = 'h' # regular file, hardlink (to already seen inodes)
else:
hardlink_master = True
is_special_file = is_special(st.st_mode) is_special_file = is_special(st.st_mode)
if not hardlinked or hardlink_master: if not hardlinked or hardlink_master:
if not is_special_file: if not is_special_file:
@ -983,10 +992,6 @@ def process_file(self, path, st, cache, ignore_inode=False):
# we processed a special file like a regular file. reflect that in mode, # we processed a special file like a regular file. reflect that in mode,
# so it can be extracted / accessed in FUSE mount like a regular file: # so it can be extracted / accessed in FUSE mount like a regular file:
item.mode = stat.S_IFREG | stat.S_IMODE(item.mode) item.mode = stat.S_IFREG | stat.S_IMODE(item.mode)
self.add_item(item)
if hardlink_master:
# Add the hard link reference *after* the file has been added to the archive.
self.hard_links[st.st_ino, st.st_dev] = safe_path
return status return status
@staticmethod @staticmethod