| Index: runtime/bin/directory_win.cc
|
| diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
|
| index d4b0aafa6d2bebed3e53f598f40afcc0f6eac44b..7ee9b593cd22a2fadd8af116b85a769821503a0c 100644
|
| --- a/runtime/bin/directory_win.cc
|
| +++ b/runtime/bin/directory_win.cc
|
| @@ -6,6 +6,7 @@
|
| #if defined(TARGET_OS_WINDOWS)
|
|
|
| #include "bin/directory.h"
|
| +#include "bin/file.h"
|
|
|
| #include <errno.h> // NOLINT
|
| #include <sys/stat.h> // NOLINT
|
| @@ -48,6 +49,25 @@ class PathBuffer {
|
| }
|
| };
|
|
|
| +// If link_name points to a link, IsBrokenLink will return true if link_name
|
| +// points to an invalid target.
|
| +static bool IsBrokenLink(const wchar_t* link_name) {
|
| + HANDLE handle = CreateFileW(
|
| + link_name,
|
| + 0,
|
| + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
| + NULL,
|
| + OPEN_EXISTING,
|
| + FILE_FLAG_BACKUP_SEMANTICS,
|
| + NULL);
|
| + if (handle == INVALID_HANDLE_VALUE) {
|
| + return true;
|
| + } else {
|
| + CloseHandle(handle);
|
| + return false;
|
| + }
|
| +}
|
| +
|
|
|
| // Forward declarations.
|
| static bool ListRecursively(PathBuffer* path,
|
| @@ -122,18 +142,13 @@ static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
|
| if (!follow_links) {
|
| return HandleLink(find_file_data->cFileName, path, listing);
|
| }
|
| - // Attempt to list the directory, to see if it's a valid link or not.
|
| int path_length = path->length;
|
| if (!path->Add(find_file_data->cFileName)) return false;
|
| - if (!path->Add(L"\\*")) return false;
|
| - WIN32_FIND_DATAW tmp_file_data;
|
| - HANDLE find_handle = FindFirstFileW(path->data, &tmp_file_data);
|
| + bool broken = IsBrokenLink(path->data);
|
| path->Reset(path_length);
|
| - if (find_handle == INVALID_HANDLE_VALUE) {
|
| - // Invalid handle, report as (broken) link.
|
| + if (broken) {
|
| + // Report as (broken) link.
|
| return HandleLink(find_file_data->cFileName, path, listing);
|
| - } else {
|
| - FindClose(find_handle);
|
| }
|
| }
|
| if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
| @@ -253,8 +268,12 @@ static bool DeleteRecursively(PathBuffer* path) {
|
| DWORD attributes = GetFileAttributesW(path->data);
|
| if ((attributes != INVALID_FILE_ATTRIBUTES) &&
|
| (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
|
| - // Just delete the junction itself.
|
| - return RemoveDirectoryW(path->data) != 0;
|
| + if (IsBrokenLink(path->data)) {
|
| + return false;
|
| + } else {
|
| + // Just delete the junction itself.
|
| + return RemoveDirectoryW(path->data) != 0;
|
| + }
|
| }
|
|
|
| if (!path->Add(L"\\*")) return false;
|
| @@ -318,6 +337,7 @@ static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) {
|
| }
|
| }
|
| bool exists = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
| + exists = exists && !IsBrokenLink(dir_name);
|
| return exists ? Directory::EXISTS : Directory::DOES_NOT_EXIST;
|
| }
|
|
|
| @@ -407,13 +427,16 @@ bool Directory::Delete(const char* dir_name, bool recursive) {
|
| bool result = false;
|
| const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name);
|
| if (!recursive) {
|
| - result = (RemoveDirectoryW(system_dir_name) != 0);
|
| + if (File::GetType(dir_name, true) == File::kIsDirectory) {
|
| + result = (RemoveDirectoryW(system_dir_name) != 0);
|
| + } else {
|
| + SetLastError(ERROR_DIRECTORY);
|
| + }
|
| } else {
|
| PathBuffer path;
|
| - if (!path.Add(system_dir_name)) {
|
| - return false;
|
| + if (path.Add(system_dir_name)) {
|
| + result = DeleteRecursively(&path);
|
| }
|
| - result = DeleteRecursively(&path);
|
| }
|
| free(const_cast<wchar_t*>(system_dir_name));
|
| return result;
|
|
|