-
Notifications
You must be signed in to change notification settings - Fork 189
Fix Windows symlink handling in FileManager APIs #858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -817,7 +817,16 @@ enum _FileOperations { | |
guard delegate.shouldPerformOnItemAtPath(src, to: dst) else { return } | ||
|
||
try dst.withNTPathRepresentation { pwszDestination in | ||
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY { | ||
// Check for reparse points first because symlinks to directories are reported as both reparse points and directories, and we should copy the symlink not the contents of the linked directory | ||
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT { | ||
do { | ||
let linkDest = try fileManager.destinationOfSymbolicLink(atPath: src) | ||
try fileManager.createSymbolicLink(atPath: dst, withDestinationPath: linkDest) | ||
} catch { | ||
try delegate.throwIfNecessary(error, src, dst) | ||
return | ||
} | ||
} else if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY { | ||
do { | ||
try fileManager.createDirectory(atPath: dst, withIntermediateDirectories: true) | ||
} catch { | ||
|
@@ -826,10 +835,10 @@ enum _FileOperations { | |
for item in _Win32DirectoryContentsSequence(path: src, appendSlashForDirectory: true) { | ||
try linkOrCopyFile(src.appendingPathComponent(item.fileName), dst: dst.appendingPathComponent(item.fileName), with: fileManager, delegate: delegate) | ||
} | ||
} else if bCopyFile || faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT { | ||
} else if bCopyFile { | ||
var ExtendedParameters: COPYFILE2_EXTENDED_PARAMETERS = .init() | ||
ExtendedParameters.dwSize = DWORD(MemoryLayout<COPYFILE2_EXTENDED_PARAMETERS>.size) | ||
ExtendedParameters.dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS | COPY_FILE_COPY_SYMLINK | COPY_FILE_NO_BUFFERING | COPY_FILE_OPEN_AND_COPY_REPARSE_POINT | ||
ExtendedParameters.dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS | COPY_FILE_NO_BUFFERING | ||
|
||
if FAILED(CopyFile2(pwszSource, pwszDestination, &ExtendedParameters)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @jakepetroules mentioned in the GitHub issue - it seems there may be an issue with |
||
try delegate.throwIfNecessary(GetLastError(), src, dst) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would a non-symlinked directory happen to satisfy this constraint as well, and is that the desired behavior? By reading at this code, I'm not sure if
fileManager.createSymbolicLink
would succeed since it's not a symlink. And if it fails, we'dthrow
instead of proceeding to copy the content of the directory. Is that ok?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah plain directories won't have this flag set, but other types of reparse points that aren't supported by
destinationOfSymbolicLink
would likely fail here - I think we can address that later since most of theFileManager
code in general likely doesn't do well with other types of reparse points