aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/native/windows/file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/native/windows/file.cc')
-rw-r--r--src/main/native/windows/file.cc89
1 files changed, 62 insertions, 27 deletions
diff --git a/src/main/native/windows/file.cc b/src/main/native/windows/file.cc
index c020eebd24..c46744a2c2 100644
--- a/src/main/native/windows/file.cc
+++ b/src/main/native/windows/file.cc
@@ -154,22 +154,25 @@ int CreateJunction(const wstring& junction_name, const wstring& junction_target,
}
AutoHandle handle(CreateFileW(
- name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL));
+ name.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL));
if (!handle.IsValid()) {
DWORD err = GetLastError();
// We can't open the directory for writing: either it disappeared, or turned
// into a file, or another process holds it open without write-sharing.
- // Either way, don't try to create the junction, just try opening it for
- // reading and check its value.
+ // Either way, don't try to create the junction, just try opening it without
+ // any read or write access (we can still read its metadata) and maximum
+ // sharing, and check its target.
create = false;
handle = CreateFileW(
- name.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (!handle.IsValid()) {
- // We can't open the directory even for reading: either it disappeared, or
- // it turned into a file, or another process holds it open without
- // read-sharing. Give up.
+ // We can't open the directory at all: either it disappeared, or it turned
+ // into a file, or another process holds it open without any sharing.
+ // Give up.
DWORD err = GetLastError();
if (err == ERROR_SHARING_VIOLATION) {
// The junction is held open by another process.
@@ -226,7 +229,23 @@ int CreateJunction(const wstring& junction_name, const wstring& junction_target,
create = false;
if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
// The path is no longer a directory, and it's not a junction either.
- return CreateJunctionResult::kAlreadyExistsButNotJunction;
+ // Though this is a case for kAlreadyExistsButNotJunction, let's instead
+ // print the attributes and return kError, to give more information to
+ // the user.
+ if (error) {
+ // Print the attributes as a 32-bit hexadecimal number.
+ WCHAR attr_str[9];
+ DWORD attr_value = info.dwFileAttributes;
+ attr_str[8] = 0;
+ for (int i = 0; i < 8; ++i) {
+ attr_str[7 - i] = L"0123456789abcdef"[attr_value & 0xF];
+ attr_value >>= 4;
+ }
+ *error = MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ L"GetFileInformationByHandle", name,
+ wstring(L"attrs=0x") + attr_str);
+ }
+ return CreateJunctionResult::kError;
}
}
}
@@ -334,18 +353,18 @@ int DeletePath(const wstring& path, wstring* error) {
DWORD err = GetLastError();
if (err == ERROR_SHARING_VIOLATION) {
// The file or directory is in use by some process.
- return DELETE_PATH_ACCESS_DENIED;
+ return DeletePathResult::kAccessDenied;
} else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
// The file or directory does not exist, or a parent directory does not
// exist, or a parent directory is actually a file.
- return DELETE_PATH_DOES_NOT_EXIST;
+ return DeletePathResult::kDoesNotExist;
} else if (err != ERROR_ACCESS_DENIED) {
// Some unknown error occurred.
if (error) {
*error = MakeErrorMessage(WSTR(__FILE__), __LINE__, L"DeleteFileW",
path, err);
}
- return DELETE_PATH_ERROR;
+ return DeletePathResult::kError;
}
// DeleteFileW failed with access denied, because the file is read-only or
@@ -356,15 +375,31 @@ int DeletePath(const wstring& path, wstring* error) {
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
// The file disappeared, or one of its parent directories disappeared,
// or one of its parent directories is no longer a directory.
- return DELETE_PATH_DOES_NOT_EXIST;
+ return DeletePathResult::kDoesNotExist;
+ } else if (err != ERROR_ACCESS_DENIED) {
+ // Some unknown error occurred.
+ if (error) {
+ *error = MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ L"GetFileAttributesW", path, err);
+ }
+ return DeletePathResult::kError;
}
- // Some unknown error occurred.
- if (error) {
- *error = MakeErrorMessage(WSTR(__FILE__), __LINE__,
- L"GetFileAttributesW", path, err);
+ // According to a comment in .NET CoreFX [1] (which is the only relevant
+ // information we found as of 2018-07-13) GetFileAttributesW may fail with
+ // ERROR_ACCESS_DENIED if the file is marked for deletion but not yet
+ // actually deleted, but FindFirstFileW should succeed even then.
+ //
+ // [1]
+ // https://github.com/dotnet/corefx/blob/f25eb288a449010574a6e95fe298f3ad880ada1e/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs#L205-L208
+ WIN32_FIND_DATAW find_data;
+ HANDLE find = FindFirstFileW(wpath, &find_data);
+ if (find == INVALID_HANDLE_VALUE) {
+ // The path is already deleted.
+ return DeletePathResult::kDoesNotExist;
}
- return DELETE_PATH_ERROR;
+ FindClose(find);
+ attr = find_data.dwFileAttributes;
}
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
@@ -374,14 +409,14 @@ int DeletePath(const wstring& path, wstring* error) {
err = GetLastError();
if (err == ERROR_SHARING_VIOLATION) {
// The junction or directory is in use by another process.
- return DELETE_PATH_ACCESS_DENIED;
+ return DeletePathResult::kAccessDenied;
} else if (err == ERROR_DIR_NOT_EMPTY) {
// The directory is not empty.
- return DELETE_PATH_DIRECTORY_NOT_EMPTY;
+ return DeletePathResult::kDirectoryNotEmpty;
} else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
// The directory or one of its directories disappeared or is no longer
// a directory.
- return DELETE_PATH_DOES_NOT_EXIST;
+ return DeletePathResult::kDoesNotExist;
}
// Some unknown error occurred.
@@ -389,7 +424,7 @@ int DeletePath(const wstring& path, wstring* error) {
*error = MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"DeleteDirectoryW", path, err);
}
- return DELETE_PATH_ERROR;
+ return DeletePathResult::kError;
}
} else {
// It's a file and it's probably read-only.
@@ -400,14 +435,14 @@ int DeletePath(const wstring& path, wstring* error) {
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
// The file disappeared, or one of its parent directories disappeared,
// or one of its parent directories is no longer a directory.
- return DELETE_PATH_DOES_NOT_EXIST;
+ return DeletePathResult::kDoesNotExist;
}
// Some unknown error occurred.
if (error) {
*error = MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"SetFileAttributesW", path, err);
}
- return DELETE_PATH_ERROR;
+ return DeletePathResult::kError;
}
if (!DeleteFileW(wpath)) {
@@ -416,7 +451,7 @@ int DeletePath(const wstring& path, wstring* error) {
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
// The file disappeared, or one of its parent directories disappeared,
// or one of its parent directories is no longer a directory.
- return DELETE_PATH_DOES_NOT_EXIST;
+ return DeletePathResult::kDoesNotExist;
}
// Some unknown error occurred.
@@ -424,11 +459,11 @@ int DeletePath(const wstring& path, wstring* error) {
*error = MakeErrorMessage(WSTR(__FILE__), __LINE__, L"DeleteFileW",
path, err);
}
- return DELETE_PATH_ERROR;
+ return DeletePathResult::kError;
}
}
}
- return DELETE_PATH_SUCCESS;
+ return DeletePathResult::kSuccess;
}
} // namespace windows