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 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'libbutl/filesystem.cxx') 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)) -- cgit v1.1