aboutsummaryrefslogtreecommitdiff
path: root/libbutl/filesystem.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-01-24 18:32:05 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-02-08 20:49:08 +0300
commit62adfcd24d2b5b92fdb6627a7b5b0471b300f923 (patch)
treef390c1c218fd822e501a4e91b956e9e2d2289e3c /libbutl/filesystem.cxx
parentb6ebda4aad5b007d5cd6942e6c5a2795a881020c (diff)
Make try_rmfile() to delete read-only files on Windows
Diffstat (limited to 'libbutl/filesystem.cxx')
-rw-r--r--libbutl/filesystem.cxx28
1 files changed, 26 insertions, 2 deletions
diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx
index fd9ba75..bd91c07 100644
--- a/libbutl/filesystem.cxx
+++ b/libbutl/filesystem.cxx
@@ -299,12 +299,36 @@ namespace butl
try_rmfile (const path& p, bool ignore_error)
{
rmfile_status r (rmfile_status::success);
+ const char* f (p.string ().c_str ());
#ifndef _WIN32
- if (unlink (p.string ().c_str ()) != 0)
+ int ur (unlink (f));
#else
- if (_unlink (p.string ().c_str ()) != 0)
+ int ur (_unlink (f));
+
+ // On Windows a file with the read-only attribute can not be deleted. This
+ // can be the reason if the deletion fails with the 'permission denied'
+ // error code. In such a case we just reset the attribute and repeat the
+ // attempt. If the attempt fails, then we try to restore the attribute.
+ //
+ if (ur != 0 && errno == EACCES)
+ {
+ DWORD a (GetFileAttributes (f));
+ if (a != INVALID_FILE_ATTRIBUTES && (a & FILE_ATTRIBUTE_READONLY) != 0 &&
+ SetFileAttributes (f, a & ~FILE_ATTRIBUTE_READONLY))
+ {
+ ur = _unlink (f);
+
+ // Restoring the attribute is unlikely to fail as we managed to reset
+ // it earlier.
+ //
+ if (ur != 0)
+ SetFileAttributes (f, a);
+ }
+ }
#endif
+
+ if (ur != 0)
{
// Strangely on Linux unlink() removes a dangling symlink but returns
// ENOENT.