Skip to content

Commit

Permalink
add --nofollow flag to copy symbolic links verbatim
Browse files Browse the repository at this point in the history
  • Loading branch information
elesiuta committed Jun 29, 2021
1 parent feac33a commit d41e52e
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 6 deletions.
2 changes: 2 additions & 0 deletions backupy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def main() -> int:
"Disable archiving files before overwriting/deleting to:\n"
" <source|dest>/.backupy/Archives/yymmdd-HHMM/\n"
" <source|dest>/.backupy/Trash/yymmdd-HHMM/"))
group2.add_argument("--nofollow", dest="nofollow", action="store_true",
help=getString("Do not follow symlinks when copying files"))
group2.add_argument("--nomoves", dest="nomoves", action="store_true",
help=getString("Do not detect when files are moved or renamed"))
group3.add_argument("--noprompt", dest="noprompt", action="store_true",
Expand Down
1 change: 1 addition & 0 deletions backupy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self, config: dict):
self.filter_exclude_list = None
self.noarchive = False
self.nocolour = False
self.nofollow = False
self.nolog = False
self.nomoves = False
self.noprompt = False
Expand Down
3 changes: 3 additions & 0 deletions backupy/fileman.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def __init__(self, config: ConfigObject, source: FileScanner, dest: FileScanner,
self.config = config
self.source = source
self.dest = dest
# update file operation functions from config
if self.config.nofollow:
FileManager.copy_function = lambda source, dest: shutil.copy2(source, dest, follow_symlinks=False)
# use other backend
if self.config.use_rsync:
def rsync_proc(source, dest):
Expand Down
21 changes: 15 additions & 6 deletions backupy/filescanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ def __init__(self, directory_root_path: str, unique_id: str,
self.ignored_toplevel_folders = list(set([config.archive_dir, config.log_dir, config.trash_dir, config.config_dir]))
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
Expand Down Expand Up @@ -148,10 +152,14 @@ def getCrc(self, relative_path: str, recalc: bool = False) -> str:

def calcCrc(self, file_path: str, prev: int = 0) -> str:
try:
with open(file_path, "rb") as f:
for line in f:
prev = zlib.crc32(line, prev)
return "%X" % (prev & 0xFFFFFFFF)
if self.follow_symlinks or not os.path.islink(file_path):
with open(file_path, "rb") as f:
for line in f:
prev = zlib.crc32(line, prev)
return "%X" % (prev & 0xFFFFFFFF)
else:
crc = zlib.crc32(os.readlink(file_path).encode())
return "%X" % (crc & 0xFFFFFFFF)
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)
Expand Down Expand Up @@ -246,8 +254,9 @@ def scanDir(self, stdout_status_bar: bool) -> None:

def scanFile(self, full_path: str, relative_path: str) -> None:
# get file attributes and create entry
size = os.path.getsize(full_path)
mtime = os.path.getmtime(full_path)
stat = os.stat(full_path, follow_symlinks=self.follow_symlinks)
size = stat.st_size
mtime = stat.st_mtime
self.dict_current[relative_path] = {"size": size, "mtime": mtime}
if self.compare_mode == "crc":
self.dict_current[relative_path]["crc"] = self.calcCrc(full_path)
Expand Down

0 comments on commit d41e52e

Please sign in to comment.