Skip to content
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

Windows, build-runfiles: Implement SymlinkResolver #6014

Closed
wants to merge 3 commits into from

Conversation

meteorcloudy
Copy link
Member

Provide a ReadSymlinkW function for resolving symlink on Windows.
Also made IsDirectoryW available.

@laszlocsomor
Copy link
Contributor

What's the motivation for this PR?

@meteorcloudy
Copy link
Member Author

This is for implementing build-runfiles on Windows. It's used to check if a link already points to the correct target. If so, we don't need to recreate the symlink, because creating symlink is slow on Windows.

I tested GetFinalPathNameByHandleW API, it works when you pass the correct parameters, but the performance is much slower than reading the reparse point directly.

Just filed #6019 to track the progress.

Copy link
Contributor

@laszlocsomor laszlocsomor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, thanks for having measured the performance of GetFinalPathNameByHandleW!

FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FILE_FLAG_BACKUP_SEMANTICS is required when and only when opening a directory or junction. When opening a file symlink, you must not use FILE_FLAG_BACKUP_SEMANTICS. I suggest trying to open it with FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT in case this CreateFileW call fails.

Furthermore, in order to minimize risk of filesystem races I suggest attempting to open the file without trying to call GetFileAttributesW. The benefit: if the path does not exist, CreateFileW fails and GetLastError() will return a corresponding error code, but if the path does exist, we have an open handle to it and no other process can delete or modify the file until we release this handle. (The OS will delay actual deletion until all handles are closed.)

And in case you do need the attributes after opening the file, you can use GetFileInformationByHandle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestions! Thanks!

Provide a ReadSymlinkW function for resolving symlink on Windows.
Also made IsDirectoryW available.

Change-Id: I5588c06ee768de12b949f2aa19e3acb84282bb4d
Change-Id: Ic9e71c79ef1c761f94f046cdbf7c61b75cddd746
@meteorcloudy
Copy link
Member Author

Addressed the comment, please take a look again~

OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
NULL));
if (!handle.IsValid()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, CreateFileW(..., FILE_ATTRIBUTE_NORMAL | ...) fails for directories (and junctions, which are also directories), therefore this failure may just mean that "path" refers to a directory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think we can call GetFileAttributesW first to check if the path refers to a reparse point or not. If it does, we can just use FILE_FLAG_OPEN_REPARSE_POINT, otherwise, we skip and return the original path. WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we can tell from the attribute if the path is a directory or not, if it is, we set FILE_FLAG_BACKUP_SEMANTICS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think calling GetFileAttributeW then CreateFileW (with FILE_ATTRIBUTE_NORMAL or FILE_FLAG_BACKUP_SEMANTICS, depending on the attributes) is as good as calling CreateFileW first with FILE_FLAG_BACKUP_SEMANTICS then with FILE_ATTRIBUTE_NORMAL -- both approaches achieve the same goal and both are susceptible to file system races (i.e. when the file is modified between the two function calls).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it's done. But I think we don't need FILE_ATTRIBUTE_NORMAL for file symlink because in the document it says This attribute is valid only if used alone.
https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea

Change-Id: I2b289c9b9701b28421afe4f81e858d678918c16b
@bazel-io bazel-io closed this in d84a976 Aug 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants