aboutsummaryrefslogtreecommitdiff
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
parentb6ebda4aad5b007d5cd6942e6c5a2795a881020c (diff)
Make try_rmfile() to delete read-only files on Windows
-rw-r--r--libbutl/filesystem.cxx28
-rw-r--r--libbutl/filesystem.mxx4
-rw-r--r--libbutl/url.txx3
3 files changed, 33 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.
diff --git a/libbutl/filesystem.mxx b/libbutl/filesystem.mxx
index 8ffbce9..a87e57b 100644
--- a/libbutl/filesystem.mxx
+++ b/libbutl/filesystem.mxx
@@ -196,6 +196,10 @@ LIBBUTL_MODEXPORT namespace butl
//
enum class rmfile_status {success, not_exist};
+ // Note that on Windows the read-only attribute is reset prior to the file
+ // removal (as it can't otherwise be deleted). In such a case the operation
+ // is not atomic.
+ //
LIBBUTL_SYMEXPORT rmfile_status
try_rmfile (const path&, bool ignore_error = false);
diff --git a/libbutl/url.txx b/libbutl/url.txx
index addfe88..e511bed 100644
--- a/libbutl/url.txx
+++ b/libbutl/url.txx
@@ -413,8 +413,11 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (authority)
{
+ // We can't append '//' string literal, so appending characters.
+ //
r += '/';
r += '/';
+
r += authority->string ();
}