Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 69 additions & 42 deletions src/libcommonserver/io/iohelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,27 +170,26 @@ bool IoHelper::getNodeId(const SyncPath &path, NodeId &nodeId) noexcept {
LONGLONG fileInfo[(MAX_PATH_LENGTH_WIN_LONG + sizeof(FILE_ID_FULL_DIR_INFORMATION)) / sizeof(LONGLONG)];
PFILE_ID_FULL_DIR_INFORMATION pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION) fileInfo;

PZW_QUERY_DIRECTORY_FILE zwQueryDirectoryFile =
(PZW_QUERY_DIRECTORY_FILE) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwQueryDirectoryFile");

if (zwQueryDirectoryFile == 0) {
LOGW_WARN(logger(), L"Error in GetProcAddress: " << Utility::formatSyncPath(path.parent_path()) << L", "
<< utility_base::getLastErrorMessage());
IoError ioError = IoError::Success;
PZW_QUERY_DIRECTORY_FILE pzwQueryDirectoryFile = pzwQueryDirectoryFileFct(ioError);
if (!pzwQueryDirectoryFile) {
LOGW_WARN(logger(), L"Error in pzwQueryDirectoryFileFct: " << Utility::formatIoError(ioError));
(void) CloseHandle(hParent);
return false;
}

NTSTATUS status = zwQueryDirectoryFile(hParent, NULL, NULL, NULL, &iosb, fileInfo, sizeof(fileInfo),
FileIdFullDirectoryInformation, true, &fn, TRUE);
NTSTATUS status = pzwQueryDirectoryFile(hParent, nullptr, nullptr, nullptr, &iosb, fileInfo, sizeof(fileInfo),
FileIdFullDirectoryInformation, true, &fn, TRUE);

if (!NT_SUCCESS(status)) {
CloseHandle(hParent);
(void) CloseHandle(hParent);
return false;
}

// Get the Windows file id as an inode replacement.
nodeId = std::to_string(computeNodeId(pFileInfo));

CloseHandle(hParent);
(void) CloseHandle(hParent);
return true;
}

Expand All @@ -205,8 +204,8 @@ bool IoHelper::_getFileStatFn(const SyncPath &path, FileStat *filestat, IoError
retry = false;

const DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
hParent = CreateFileW(path.parent_path().wstring().c_str(), FILE_LIST_DIRECTORY, dwShareMode, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
hParent = CreateFileW(path.parent_path().wstring().c_str(), FILE_LIST_DIRECTORY, dwShareMode, nullptr, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (hParent == INVALID_HANDLE_VALUE) {
DWORD dwError = GetLastError();
if (utility_base::isLikeFileNotFoundError(dwError)) {
Expand Down Expand Up @@ -243,23 +242,20 @@ bool IoHelper::_getFileStatFn(const SyncPath &path, FileStat *filestat, IoError
LONGLONG fileInfo[(MAX_PATH_LENGTH_WIN_LONG + sizeof(FILE_ID_FULL_DIR_INFORMATION)) / sizeof(LONGLONG)];
PFILE_ID_FULL_DIR_INFORMATION pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION) fileInfo;

PZW_QUERY_DIRECTORY_FILE zwQueryDirectoryFile =
(PZW_QUERY_DIRECTORY_FILE) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwQueryDirectoryFile");

if (zwQueryDirectoryFile == 0) {
LOG_WARN(logger(), "Error in GetProcAddress");
ioError = dWordError2ioError(GetLastError(), logger());
CloseHandle(hParent);
PZW_QUERY_DIRECTORY_FILE pzwQueryDirectoryFile = pzwQueryDirectoryFileFct(ioError);
if (!pzwQueryDirectoryFile) {
LOGW_WARN(logger(), L"Error in pzwQueryDirectoryFileFct: " << Utility::formatIoError(ioError));
(void) CloseHandle(hParent);
return false;
}

NTSTATUS status = zwQueryDirectoryFile(hParent, NULL, NULL, NULL, &iosb, fileInfo, sizeof(fileInfo),
FileIdFullDirectoryInformation, true, &fn, TRUE);
NTSTATUS status = pzwQueryDirectoryFile(hParent, nullptr, nullptr, nullptr, &iosb, fileInfo, sizeof(fileInfo),
FileIdFullDirectoryInformation, true, &fn, TRUE);

DWORD dwError = GetLastError();
// On FAT32 file system, NT_SUCCESS will return false even if it is a success, therefore we also check GetLastError
if ((CommonUtility::isNTFS(path) && !NT_SUCCESS(status)) || (CommonUtility::isFAT(path) && dwError != 0)) {
CloseHandle(hParent);
(void) CloseHandle(hParent);

if (!NT_SUCCESS(status)) {
ioError = ntStatus2ioError(status);
Expand All @@ -281,15 +277,16 @@ bool IoHelper::_getFileStatFn(const SyncPath &path, FileStat *filestat, IoError

filestat->isHidden = pFileInfo->FileAttributes & FILE_ATTRIBUTE_HIDDEN;
filestat->nodeType = pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? NodeType::Directory : NodeType::File;
CloseHandle(hParent);
(void) CloseHandle(hParent);

return true;
}

bool IoHelper::isFileAccessible(const SyncPath &absolutePath, IoError &ioError) {
ioError = IoError::Success;

HANDLE hFile = CreateFileW(Path2WStr(absolutePath).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
HANDLE hFile =
CreateFileW(Path2WStr(absolutePath).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, NULL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
return false;
Expand Down Expand Up @@ -753,8 +750,8 @@ bool IoHelper::checkIfIsJunction(const SyncPath &path, bool &isJunction, IoError
isJunction = false;
ioError = IoError::Success;

HANDLE hFile = CreateFileW(Path2WStr(path).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
HANDLE hFile = CreateFileW(Path2WStr(path).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
return isExpectedError(ioError);
Expand All @@ -763,8 +760,8 @@ bool IoHelper::checkIfIsJunction(const SyncPath &path, bool &isJunction, IoError
BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER &ReparseBuffer = (REPARSE_DATA_BUFFER &) buf;
DWORD dwRet;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, &ReparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet,
NULL)) {
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, &ReparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet,
nullptr)) {
DWORD dwError = GetLastError();
CloseHandle(hFile);

Expand All @@ -785,22 +782,22 @@ bool IoHelper::createJunction(const std::string &data, const SyncPath &path, IoE
ioError = IoError::Success;

// Create the junction directory
if (!CreateDirectoryW(Path2WStr(path).c_str(), NULL)) {
if (!CreateDirectoryW(Path2WStr(path).c_str(), nullptr)) {
ioError = dWordError2ioError(GetLastError(), logger());
return false;
}

// Set the reparse point
HANDLE hDir;
hDir = CreateFileW(Path2WStr(path).c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
hDir = CreateFileW(Path2WStr(path).c_str(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hDir == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
return false;
}

DWORD dwRet = 0;
if (!DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, (void *) data.data(), (WORD) data.size(), NULL, 0, &dwRet, NULL)) {
if (!DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, (void *) data.data(), (WORD) data.size(), nullptr, 0, &dwRet, nullptr)) {
RemoveDirectoryW(Path2WStr(path).c_str());
CloseHandle(hDir);
ioError = dWordError2ioError(GetLastError(), logger());
Expand All @@ -816,7 +813,7 @@ bool IoHelper::readJunction(const SyncPath &path, std::string &data, SyncPath &t

HANDLE hFile =
CreateFileW(Path2WStr(path).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
return isExpectedError(ioError);
Expand All @@ -825,8 +822,8 @@ bool IoHelper::readJunction(const SyncPath &path, std::string &data, SyncPath &t
BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER &reparseBuffer = (REPARSE_DATA_BUFFER &) buf;
DWORD dwRet;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, &reparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet,
NULL)) {
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, &reparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet,
nullptr)) {
DWORD dwError = GetLastError();
CloseHandle(hFile);

Expand Down Expand Up @@ -854,15 +851,15 @@ bool IoHelper::createJunctionFromPath(const SyncPath &targetPath, const SyncPath
ioError = IoError::Success;

// Create the junction directory
if (!CreateDirectoryW(Path2WStr(path).c_str(), NULL)) {
if (!CreateDirectoryW(Path2WStr(path).c_str(), nullptr)) {
ioError = dWordError2ioError(GetLastError(), logger());
return false;
}

// Set the reparse point
HANDLE hDir;
hDir = CreateFileW(Path2WStr(path).c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
hDir = CreateFileW(Path2WStr(path).c_str(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hDir == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
return false;
Expand Down Expand Up @@ -893,7 +890,7 @@ bool IoHelper::createJunctionFromPath(const SyncPath &targetPath, const SyncPath
DWORD dwError = ERROR_SUCCESS;
const bool success =
DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, reparseDataBuffer,
reparseDataBuffer->ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &dwError, NULL);
reparseDataBuffer->ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE, nullptr, 0, &dwError, nullptr);

ioError = dWordError2ioError(dwError, logger());
free(reparseDataBuffer);
Expand Down Expand Up @@ -935,8 +932,8 @@ IoError IoHelper::setFileDates(const SyncPath &filePath, const SyncTime creation
HANDLE hFile = INVALID_HANDLE_VALUE;
for (bool isDirectory: {false, true}) {
hFile = CreateFileW(filePath.native().c_str(), FILE_WRITE_ATTRIBUTES,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
(isDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0) | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
(isDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0) | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD dwError = GetLastError();
if (dwError == ERROR_ACCESS_DENIED) {
Expand All @@ -960,7 +957,7 @@ IoError IoHelper::setFileDates(const SyncPath &filePath, const SyncTime creation
return IoError::Unknown;
}

if (!SetFileTime(hFile, &creationTime, NULL, &modificationTime)) {
if (!SetFileTime(hFile, &creationTime, nullptr, &modificationTime)) {
auto ioError = IoError::Unknown;
DWORD dwError = GetLastError();
if (utility_base::isLikeFileNotFoundError(dwError)) {
Expand Down Expand Up @@ -1162,4 +1159,34 @@ bool IoHelper::moveItemToTrash(const SyncPath &itemPath) {
return result;
}

PZW_QUERY_DIRECTORY_FILE pzwQueryDirectoryFileFct(IoError &ioError) {
static PZW_QUERY_DIRECTORY_FILE pzwQueryDirectoryFile = nullptr;

ioError = IoError::Success;
if (pzwQueryDirectoryFile) return pzwQueryDirectoryFile;

HMODULE hModule = GetModuleHandle(L"ntdll.dll");
if (hModule == nullptr) {
LOG_WARN(Log::instance()->getLogger(), "Error in GetModuleHandle for ntdll.dll");
ioError = dWordError2ioError(GetLastError(), Log::instance()->getLogger());
return nullptr;
}

try {
pzwQueryDirectoryFile = (PZW_QUERY_DIRECTORY_FILE) GetProcAddress(hModule, "ZwQueryDirectoryFile");
} catch (const std::exception &e) {
LOG_WARN(Log::instance()->getLogger(), "Exception in GetProcAddress: err=" << e.what());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe force the value of ioError to something (ex: Unknown). If I understand the code correctly, ioError is still equal to Success here and the log message on line 176 might be misleading.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done
c71e523

ioError = IoError::Unknown;
return nullptr;
}

if (pzwQueryDirectoryFile == nullptr) {
LOG_WARN(Log::instance()->getLogger(), "Error in GetProcAddress");
ioError = dWordError2ioError(GetLastError(), Log::instance()->getLogger());
return nullptr;
}

return pzwQueryDirectoryFile;
}

} // namespace KDC
4 changes: 4 additions & 0 deletions src/libcommonserver/io/iohelper_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,7 @@ using REPARSE_DATA_BUFFER = struct _REPARSE_DATA_BUFFER {
#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
constexpr auto REPARSE_MOUNTPOINT_HEADER_SIZE = 8;
// Definitions for DeviceIoControl - End

namespace KDC {
PZW_QUERY_DIRECTORY_FILE pzwQueryDirectoryFileFct(IoError &ioError);
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void FolderWatcher_win::watchChanges() {
overlapped.hEvent = _resultEventHandle;

while (!_stop) {
ResetEvent(_resultEventHandle);
(void) ResetEvent(_resultEventHandle);

DWORD dwBytesReturned = 0;
if (!ReadDirectoryChangesW(_directoryHandle, &fileNotifyBuffer, static_cast<DWORD>(NOTIFY_BUFFER_SIZE), true,
Expand Down Expand Up @@ -141,6 +141,11 @@ void FolderWatcher_win::watchChanges() {

const FILE_NOTIFY_INFORMATION *notifInfo = reinterpret_cast<const FILE_NOTIFY_INFORMATION *>(&fileNotifyBuffer);
while (!_stop) {
if (!notifInfo) {
LOG_WARN(KDC::Log::instance()->getLogger(), "Bad notifInfo");
break;
}

std::wstring wPathName(notifInfo->FileName,
notifInfo->FileName + (notifInfo->FileNameLength / sizeof(notifInfo->FileName)));
SyncPath filepath = (_folder / wPathName).lexically_normal();
Expand Down Expand Up @@ -190,8 +195,8 @@ void FolderWatcher_win::watchChanges() {
}
}

CancelIo(_directoryHandle);
closeHandle();
(void) CancelIo(_directoryHandle);
(void) closeHandle();

LOG_DEBUG(_logger, "Watching changes stopped");
}
Expand Down