Skip to content

Commit

Permalink
Merge branch 'mr/adjust_wsl_link_handling' into 'master'
Browse files Browse the repository at this point in the history
Don't normalize the path returned by wsl_reparse_link_target

See merge request it/e3-core!90
  • Loading branch information
Nikokrock committed Jan 9, 2025
2 parents 66bba9c + 8a7832e commit 55a4007
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 8 deletions.
44 changes: 39 additions & 5 deletions src/e3/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ def copystat(src: FileInfo, dst: FileInfo) -> None:

logger.debug("chflags: operation not supported [EOPNOTSUPP]")

def safe_copy(src: FileInfo, dst: FileInfo, is_directory: bool = False) -> None:
def safe_copy(src: FileInfo, dst: FileInfo) -> None:
"""Copy src file into dst preserving all attributes.
:param src: the source FileInfo object
Expand All @@ -842,7 +842,43 @@ def safe_copy(src: FileInfo, dst: FileInfo, is_directory: bool = False) -> None:
# to transform Cygwin links into Win32 symlinks
if dst.stat is not None:
rm(dst.path, recursive=True, glob=False)
os.symlink(linkto, dst.path, target_is_directory=is_directory)

target_is_directory = False
if sys.platform == "win32":
# This is important to try guessing the right nature of the link
# (i.e whether it points to a directory or a file). Indeed on
# Windows system symbolic links to directory and files are distinct.
# During a call to sync_tree we are not sure in advance what will
# be created first: the link or the target of the link. Thus Python
# cannot always guess the right nature of the link (in that case
# Python defaults to a link to a file).
# In addition this function support WSL links that may be created
# by Cygwin when the nature of the target is not known. Python
# cannot read those links so in that case doing
# os.path.isdir(src.path) will always return False. That's why we
# do the check directly on the target path.
# limit recursion to 32 in order not to crash on link loops
src_linkto_path = os.path.join(os.path.dirname(src.path), linkto)
for _ in range(32):
if not os.path.exists(src_linkto_path):
break

src_linkto = FileInfo(
src_linkto_path,
os.lstat(src_linkto_path),
os.path.basename(src_linkto_path),
)

if not islink(src_linkto):
break

src_linkto_path = os.path.join(
os.path.dirname(src_linkto.path),
e3.os.fs.readlink(src_linkto.path),
)
target_is_directory = os.path.isdir(src_linkto_path)

os.symlink(linkto, dst.path, target_is_directory=target_is_directory)
copystat(src, dst)
else:
if isdir(dst):
Expand Down Expand Up @@ -1034,9 +1070,7 @@ def walk(
# the source tree.
if need_update(wf.source, wf.target):
if isfile(wf.source) or islink(wf.source):
safe_copy(
wf.source, wf.target, is_directory=os.path.isdir(wf.source.path)
)
safe_copy(wf.source, wf.target)
updated_list.append(wf.target.path)
elif isdir(wf.source):
safe_mkdir(wf.source, wf.target)
Expand Down
6 changes: 3 additions & 3 deletions src/e3/os/windows/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@ def wsl_reparse_link_target(self) -> str | None:
message=f"cannot find target of WSL link for {self.path}",
origin="NTFile.wsl_reparse_link_target",
)
return os.path.join(
os.path.dirname(self.path), result.data[: result.length - 4].decode("utf-8")
)
# Don't return here an absolute path as usually the user needs to know if the
# link is relative or not.
return result.data[: result.length - 4].decode("utf-8")

def read_attributes_internal(self) -> None:
"""Retrieve file basic attributes (internal function).
Expand Down

0 comments on commit 55a4007

Please sign in to comment.