diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-07-31 23:33:21 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-07-31 23:41:28 +0300 |
commit | f3da1e8b8d13a3a52b3eab6f28ed798fa83b4215 (patch) | |
tree | 902d639adef758a6cff55283174f0e7754a75a9c | |
parent | e1e639fc5c85ba4df83040ddb4ac8dc620ae208b (diff) | |
download | ydb-f3da1e8b8d13a3a52b3eab6f28ed798fa83b4215.tar.gz |
Intermediate changes
-rw-r--r-- | library/python/fs/__init__.py | 67 |
1 files changed, 37 insertions, 30 deletions
diff --git a/library/python/fs/__init__.py b/library/python/fs/__init__.py index 6b6a011e7f..0beaf6665a 100644 --- a/library/python/fs/__init__.py +++ b/library/python/fs/__init__.py @@ -196,32 +196,6 @@ def hardlink(src, lnk): os.link(src, lnk) -@errorfix_win -def hardlink_or_copy(src, lnk): - def should_fallback_to_copy(exc): - if WindowsError is not None and isinstance(exc, WindowsError) and exc.winerror == 1142: # too many hardlinks - return True - # cross-device hardlink or too many hardlinks, or some known WSL error - if isinstance(exc, OSError) and exc.errno in ( - errno.EXDEV, - errno.EMLINK, - errno.EINVAL, - errno.EACCES, - errno.EPERM, - ): - return True - return False - - try: - hardlink(src, lnk) - except Exception as e: - logger.debug('Failed to hardlink %s to %s with error %s, will copy it', src, lnk, repr(e)) - if should_fallback_to_copy(e): - copy2(src, lnk, follow_symlinks=False) - else: - raise - - # Atomic file/directory symlink (Unix only) # Dst must not exist # Throws OSError @@ -247,24 +221,57 @@ def copy2(src, lnk, follow_symlinks=True): symlink(os.readlink(src), lnk) +def copy2_safe(src, lnk, follow_symlinks=True): + try: + copy2(src, lnk, follow_symlinks) + except shutil.SameFileError: + pass + + +@errorfix_win +def hardlink_or_copy(src, lnk, copy_function=copy2): + def should_fallback_to_copy(exc): + if WindowsError is not None and isinstance(exc, WindowsError) and exc.winerror == 1142: # too many hardlinks + return True + # cross-device hardlink or too many hardlinks, or some known WSL error + if isinstance(exc, OSError) and exc.errno in ( + errno.EXDEV, + errno.EMLINK, + errno.EINVAL, + errno.EACCES, + errno.EPERM, + ): + return True + return False + + try: + hardlink(src, lnk) + except Exception as e: + logger.debug('Failed to hardlink %s to %s with error %s, will copy it', src, lnk, repr(e)) + if should_fallback_to_copy(e): + copy_function(src, lnk, follow_symlinks=False) + else: + raise + + # Recursively hardlink directory # Uses plain hardlink for files # Dst must not exist # Non-atomic # Throws OSError @errorfix_win -def hardlink_tree(src, dst): +def hardlink_tree(src, dst, hardlink_function=hardlink, mkdir_function=os.mkdir): if not os.path.exists(src): raise CustomFsError(errno.ENOENT, filename=src) if os.path.isfile(src): - hardlink(src, dst) + hardlink_function(src, dst) return for dirpath, _, filenames in walk_relative(src): src_dirpath = os.path.join(src, dirpath) if dirpath != '.' else src dst_dirpath = os.path.join(dst, dirpath) if dirpath != '.' else dst - os.mkdir(dst_dirpath) + mkdir_function(dst_dirpath) for filename in filenames: - hardlink(os.path.join(src_dirpath, filename), os.path.join(dst_dirpath, filename)) + hardlink_function(os.path.join(src_dirpath, filename), os.path.join(dst_dirpath, filename)) # File copy |