From c3f0489235f6d0e9cf9d6c302d7b086b4f9968dc Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 28 Apr 2018 22:25:21 +0300 Subject: Fix try_rmfile() to remove symlinks on Windows --- libbutl/filesystem.cxx | 33 ++++++++++++++++++++++++--------- libbutl/filesystem.mxx | 3 +++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index bff251a..2650c25 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -322,19 +322,34 @@ namespace butl // 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. // + // Yet another reason for the 'permission denied' failure can be a + // directory symlink. + // 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)) + if (a != INVALID_FILE_ATTRIBUTES) { - ur = _unlink (f); + bool readonly ((a & FILE_ATTRIBUTE_READONLY) != 0); - // Restoring the attribute is unlikely to fail as we managed to reset - // it earlier. + // Note that we support only directory symlinks on Windows. // - if (ur != 0) - SetFileAttributes (f, a); + bool symlink ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0 && + (a & FILE_ATTRIBUTE_DIRECTORY) != 0); + + if (readonly || symlink) + { + bool restore (readonly && + SetFileAttributes (f, a & ~FILE_ATTRIBUTE_READONLY)); + + ur = symlink ? _rmdir (f) : _unlink (f); + + // Restoring the attribute is unlikely to fail as we managed to reset + // it earlier. + // + if (ur != 0 && restore) + SetFileAttributes (f, a); + } } } #endif @@ -492,8 +507,8 @@ namespace butl FSCTL_SET_REPARSE_POINT, &rb, sizeof (DWORD) + 2 * sizeof (WORD) + // Size of the header. - rb.reparse_data_length, // Size of mount point reparse. - NULL, // buffer. + rb.reparse_data_length, // Size of the mount point + NULL, // reparse buffer. 0, &r, NULL)) diff --git a/libbutl/filesystem.mxx b/libbutl/filesystem.mxx index fbfc0aa..ff9a4a6 100644 --- a/libbutl/filesystem.mxx +++ b/libbutl/filesystem.mxx @@ -194,6 +194,9 @@ LIBBUTL_MODEXPORT namespace butl // it does not exist. Unless ignore_error is true, all other // errors are reported by throwing std::system_error. // + // Note that if it is known that the path refers to a symlink, then usage of + // try_rmsymlink() function must be preferred, as a more efficient one. + // enum class rmfile_status {success, not_exist}; // Note that on Windows the read-only attribute is reset prior to the file -- cgit v1.1