diff --git a/borg/archive.py b/borg/archive.py index 26ad16455..4d436c860 100644 --- a/borg/archive.py +++ b/borg/archive.py @@ -660,8 +660,6 @@ Number of files: {0.stats.nfiles}'''.format( self.add_item(item) status = 'h' # regular file, hardlink (to already seen inodes) return status - else: - self.hard_links[st.st_ino, st.st_dev] = safe_path is_special_file = is_special(st.st_mode) if not is_special_file: path_hash = self.key.id_hash(os.path.join(self.cwd, path).encode('utf-8', 'surrogateescape')) @@ -709,6 +707,9 @@ Number of files: {0.stats.nfiles}'''.format( item[b'mode'] = stat.S_IFREG | stat.S_IMODE(item[b'mode']) self.stats.nfiles += 1 self.add_item(item) + if st.st_nlink > 1 and source is None: + # 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 @staticmethod diff --git a/borg/fuse.py b/borg/fuse.py index f92f76900..25c935229 100644 --- a/borg/fuse.py +++ b/borg/fuse.py @@ -128,15 +128,21 @@ class FuseOperations(llfuse.Operations): else: self.items[inode] = item continue - segments = prefix + os.fsencode(os.path.normpath(item[b'path'])).split(b'/') - del item[b'path'] + path = item.pop(b'path') + segments = prefix + os.fsencode(os.path.normpath(path)).split(b'/') num_segments = len(segments) parent = 1 for i, segment in enumerate(segments, 1): # Leaf segment? if i == num_segments: if b'source' in item and stat.S_ISREG(item[b'mode']): - inode = self._find_inode(item[b'source'], prefix) + try: + inode = self._find_inode(item[b'source'], prefix) + except KeyError: + file = path.decode(errors='surrogateescape') + source = item[b'source'].decode(errors='surrogateescape') + logger.warning('Skipping broken hard link: %s -> %s', file, source) + continue item = self.cache.get(inode) item[b'nlink'] = item.get(b'nlink', 1) + 1 self.items[inode] = item