]> git.lizzy.rs Git - rust.git/commit
Rollup merge of #41026 - CleanCut:rust-40860, r=alexcrichton
authorCorey Farwell <coreyf@rwell.org>
Thu, 6 Apr 2017 03:51:41 +0000 (23:51 -0400)
committerGitHub <noreply@github.com>
Thu, 6 Apr 2017 03:51:41 +0000 (23:51 -0400)
commit1a4aab94c314f7564e825bea7be2032841487c22
tree46eb8e3ce5554f1cbdd4d965cd8011a210f6eab9
parent083c7a93beb2951465732b015afc7deb651a7ce5
parentefd6eab366ad44ac6e9b0b12cd4b9688ab71df6d
Rollup merge of #41026 - CleanCut:rust-40860, r=alexcrichton

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

In response to #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. :-)