diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-06-27 14:39:01 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-07-14 14:24:50 -0700 |
| commit | fe67d269a5f0df45d138051a3f105e05490ccf9e (patch) | |
| tree | 8d660397d7e5117cc3e5296f0e9904bd2f3cc18d /src/libstd | |
| parent | 996263a01589c5d2bd2a5ad559abac267296ad71 (diff) | |
| download | rust-fe67d269a5f0df45d138051a3f105e05490ccf9e.tar.gz rust-fe67d269a5f0df45d138051a3f105e05490ccf9e.zip | |
std: Make unlink() more consistent
Currently when a read-only file has unlink() invoked on it on windows, the call will fail. On unix, however, the call will succeed. In order to have a more consistent behavior across platforms, this error is recognized on windows and the file is changed to read-write before removal is attempted.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/fs.rs | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 449ad6fa0da..caff7d5e4c5 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -275,11 +275,41 @@ impl File { /// user lacks permissions to remove the file, or if some other filesystem-level /// error occurs. pub fn unlink(path: &Path) -> IoResult<()> { - let err = LocalIo::maybe_raise(|io| { - io.fs_unlink(&path.to_c_str()) - }).map_err(IoError::from_rtio_error); - err.update_err("couldn't unlink path", - |e| format!("{}; path={}", e, path.display())) + return match do_unlink(path) { + Ok(()) => Ok(()), + Err(e) => { + // On unix, a readonly file can be successfully removed. On windows, + // however, it cannot. To keep the two platforms in line with + // respect to their behavior, catch this case on windows, attempt to + // change it to read-write, and then remove the file. + if cfg!(windows) && e.kind == io::PermissionDenied { + let stat = match stat(path) { + Ok(stat) => stat, + Err(..) => return Err(e), + }; + if stat.perm.intersects(io::UserWrite) { return Err(e) } + + match chmod(path, stat.perm | io::UserWrite) { + Ok(()) => do_unlink(path), + Err(..) => { + // Try to put it back as we found it + let _ = chmod(path, stat.perm); + Err(e) + } + } + } else { + Err(e) + } + } + }; + + fn do_unlink(path: &Path) -> IoResult<()> { + let err = LocalIo::maybe_raise(|io| { + io.fs_unlink(&path.to_c_str()) + }).map_err(IoError::from_rtio_error); + err.update_err("couldn't unlink path", + |e| format!("{}; path={}", e, path.display())) + } } /// Given a path, query the file system to get information about a file, @@ -1591,4 +1621,12 @@ mod test { let actual = check!(File::open(&tmpdir.join("test")).read_to_end()); assert!(actual.as_slice() == bytes); }) + + iotest!(fn unlink_readonly() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(File::create(&path)); + check!(chmod(&path, io::UserRead)); + check!(unlink(&path)); + }) } |
