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

Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves #40860. #41026

Merged
merged 1 commit into from
Apr 6, 2017
Merged

Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves #40860. #41026

merged 1 commit into from
Apr 6, 2017

Conversation

CleanCut
Copy link
Contributor

@CleanCut CleanCut commented Apr 2, 2017

In response to #40860

The broken condition can be replicated with:

export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir &&
touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file
build/$MYARCH/subdir/symlink

src/bootstrap/clean.rs has a custom implementation of removing a tree
fn rm_rf that used std::path::Path::{is_file, is_dir, exists} while
recursively deleting directories and files. Unfortunately, Path's
implementation of is_file() and is_dir() and exists() always
unconditionally follow symlinks, which is the exact opposite of standard
implementations of deleting file trees.

It appears that this custom implementation is being used to workaround a
behavior in Windows where the files often get marked as read-only, which
prevents us from simply using something nice and simple like
std::fs::remove_dir_all, which properly deletes links instead of
following them.

So it looks like the fix is to use .symlink_metadata() to figure out
whether tree items are files/symlinks/directories. The one corner case
this won't cover is if there is a broken symlink in the "root"
build/$MYARCH directory, because those initial entries are run through
Path::canonicalize(), which panics with broken symlinks. So lets just
never use symlinks in that one directory. :-)

The broken condition can be replicated with:

``shell
export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir &&
touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file
build/$MYARCH/subdir/symlink
``

`src/bootstrap/clean.rs` has a custom implementation of removing a tree
`fn rm_rf` that used `std::path::Path::{is_file, is_dir, exists}` while
recursively deleting directories and files.  Unfortunately, `Path`'s
implementation of `is_file()` and `is_dir()` and `exists()` always
unconditionally follow symlinks, which is the exact opposite of standard
implementations of deleting file trees.

It appears that this custom implementation is being used to workaround a
behavior in Windows where the files often get marked as read-only, which
prevents us from simply using something nice and simple like
`std::fs::remove_dir_all`, which properly deletes links instead of
following them.

So it looks like the fix is to use `.symlink_metadata()` to figure out
whether tree items are files/symlinks/directories.  The one corner case
this won't cover is if there is a broken symlink in the "root"
`build/$MYARCH` directory, because those initial entries are run through
`Path::canonicalize()`, which panics with broken symlinks.  So lets just
never use symlinks in that one directory. :-)
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @aturon (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@alexcrichton
Copy link
Member

@bors: r+

Thanks!

@bors
Copy link
Contributor

bors commented Apr 3, 2017

📌 Commit efd6eab has been approved by alexcrichton

@CleanCut
Copy link
Contributor Author

CleanCut commented Apr 3, 2017

You're welcome. :-)

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 6, 2017
Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves rust-lang#40860.

In response to rust-lang#40860

The broken condition can be replicated with:

```shell
export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir &&
touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file
build/$MYARCH/subdir/symlink
```

`src/bootstrap/clean.rs` has a custom implementation of removing a tree
`fn rm_rf` that used `std::path::Path::{is_file, is_dir, exists}` while
recursively deleting directories and files.  Unfortunately, `Path`'s
implementation of `is_file()` and `is_dir()` and `exists()` always
unconditionally follow symlinks, which is the exact opposite of standard
implementations of deleting file trees.

It appears that this custom implementation is being used to workaround a
behavior in Windows where the files often get marked as read-only, which
prevents us from simply using something nice and simple like
`std::fs::remove_dir_all`, which properly deletes links instead of
following them.

So it looks like the fix is to use `.symlink_metadata()` to figure out
whether tree items are files/symlinks/directories.  The one corner case
this won't cover is if there is a broken symlink in the "root"
`build/$MYARCH` directory, because those initial entries are run through
`Path::canonicalize()`, which panics with broken symlinks.  So lets just
never use symlinks in that one directory. :-)
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 6, 2017
Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves rust-lang#40860.

In response to rust-lang#40860

The broken condition can be replicated with:

```shell
export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir &&
touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file
build/$MYARCH/subdir/symlink
```

`src/bootstrap/clean.rs` has a custom implementation of removing a tree
`fn rm_rf` that used `std::path::Path::{is_file, is_dir, exists}` while
recursively deleting directories and files.  Unfortunately, `Path`'s
implementation of `is_file()` and `is_dir()` and `exists()` always
unconditionally follow symlinks, which is the exact opposite of standard
implementations of deleting file trees.

It appears that this custom implementation is being used to workaround a
behavior in Windows where the files often get marked as read-only, which
prevents us from simply using something nice and simple like
`std::fs::remove_dir_all`, which properly deletes links instead of
following them.

So it looks like the fix is to use `.symlink_metadata()` to figure out
whether tree items are files/symlinks/directories.  The one corner case
this won't cover is if there is a broken symlink in the "root"
`build/$MYARCH` directory, because those initial entries are run through
`Path::canonicalize()`, which panics with broken symlinks.  So lets just
never use symlinks in that one directory. :-)
bors added a commit that referenced this pull request Apr 6, 2017
Rollup of 5 pull requests

- Successful merges: #40908, #41011, #41026, #41037, #41050
- Failed merges:
@bors bors merged commit efd6eab into rust-lang:master Apr 6, 2017
@CleanCut CleanCut deleted the rust-40860 branch April 7, 2017 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants