diff --git a/backupy/fileman.py b/backupy/fileman.py index 1da9da8..f3413ec 100644 --- a/backupy/fileman.py +++ b/backupy/fileman.py @@ -85,7 +85,10 @@ def _copyFile(self, source_root: str, dest_root: str, source_file: str, dest_fil source = os.path.join(source_root, source_file) dest = os.path.join(dest_root, dest_file) if os.path.isdir(source): - os.makedirs(dest) + if os.path.islink(source): + shutil.copyfile(source, dest, follow_symlinks=False) + else: + os.makedirs(dest) else: if not os.path.isdir(os.path.dirname(dest)): os.makedirs(os.path.dirname(dest)) diff --git a/backupy/filescanner.py b/backupy/filescanner.py index 5acce0f..d3a5f01 100644 --- a/backupy/filescanner.py +++ b/backupy/filescanner.py @@ -57,9 +57,6 @@ def __init__(self, directory_root_path: str, unique_id: str, self.force_posix_path_sep = config.force_posix_path_sep self.write_database_x2 = config.write_database_x2 and not config.scan_only self.follow_symlinks = not config.nofollow - # self.opener = None - # if config.nofollow: - # self.opener = lambda path, flags: os.open(path, flags | os.O_PATH | os.O_NOFOLLOW) # Init other variables self.dir = directory_root_path self.other_dir = other_root_path @@ -158,12 +155,17 @@ def calcCrc(self, file_path: str, prev: int = 0) -> str: prev = zlib.crc32(line, prev) return "%X" % (prev & 0xFFFFFFFF) else: - crc = zlib.crc32(os.readlink(file_path).encode()) - return "%X" % (crc & 0xFFFFFFFF) + return self.symlinkCrc(file_path) except Exception: # file either removed by user, or another program such as antimalware (using realtime monitoring) during scan, or lack permissions raise Exception("Exiting, error trying to read file: " + file_path) + def symlinkCrc(self, file_path: str) -> str: + if os.path.islink(file_path): + crc = zlib.crc32(os.readlink(file_path).encode()) + return "%X" % (crc & 0xFFFFFFFF) + return "0" + def timeMatch(self, t1: float, t2: float, exact_only: bool = False, tz_diffs: list = [3600, 3601, 3602], fs_tol: int = 2) -> bool: if t1 == t2: return True @@ -228,12 +230,12 @@ def scanDir(self, stdout_status_bar: bool) -> None: for subdir in subdir_list: full_path = os.path.join(dir_path, subdir) try: - if len(os.listdir(full_path)) == 0: + if len(os.listdir(full_path)) == 0 or os.path.islink(full_path): # track empty directories with a dummy entry, non-empty directories should not have entries, they are handled automatically by having files inside them relative_path = os.path.relpath(full_path, self.dir) if self.force_posix_path_sep: relative_path = relative_path.replace(os.path.sep, "/") - self.dict_current[relative_path] = {"size": 0, "mtime": 0, "crc": "0", "dir": True} + self.dict_current[relative_path] = {"size": 0, "mtime": 0, "crc": self.symlinkCrc(full_path), "dir": True} self.set_dirs.add(relative_path) except Exception as e: raise Exception("%s %s for directory: %s" % (type(e).__name__, str(e.args), full_path))