mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-26 15:06:08 +03:00
Win: Use full Windows paths in file watcher and improve logging
This commit is contained in:
parent
7fa7bc54c4
commit
2887a93c40
4 changed files with 39 additions and 26 deletions
|
@ -141,7 +141,7 @@ bool FileSystem::rename(const QString &originFileName,
|
|||
(wchar_t *)dest.utf16(),
|
||||
MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH);
|
||||
if (!success) {
|
||||
error = Utility::formatWinError();
|
||||
error = Utility::formatLastWinError();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
|
|
@ -249,7 +249,10 @@ namespace Utility {
|
|||
OCSYNC_EXPORT void FiletimeToLargeIntegerFiletime(FILETIME *filetime, LARGE_INTEGER *hundredNSecs);
|
||||
OCSYNC_EXPORT void UnixTimeToLargeIntegerFiletime(time_t t, LARGE_INTEGER *hundredNSecs);
|
||||
|
||||
OCSYNC_EXPORT QString formatWinError(long error = GetLastError());
|
||||
OCSYNC_EXPORT QString formatWinError(long error);
|
||||
inline QString formatLastWinError() {
|
||||
return formatWinError(GetLastError());
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <QThread>
|
||||
#include <QDir>
|
||||
|
||||
#include "common/asserts.h"
|
||||
#include "common/utility.h"
|
||||
#include "filesystem.h"
|
||||
#include "folderwatcher.h"
|
||||
#include "folderwatcher_win.h"
|
||||
|
@ -31,10 +33,10 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
bool *increaseBufferSize)
|
||||
{
|
||||
*increaseBufferSize = false;
|
||||
QString longPath = FileSystem::longWinPath(_path);
|
||||
const QString longPath = FileSystem::longWinPath(_path);
|
||||
|
||||
_directory = CreateFileW(
|
||||
(wchar_t *)longPath.utf16(),
|
||||
longPath.toStdWString().data(),
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
|
@ -43,8 +45,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
nullptr);
|
||||
|
||||
if (_directory == INVALID_HANDLE_VALUE) {
|
||||
DWORD errorCode = GetLastError();
|
||||
qCWarning(lcFolderWatcher) << "Failed to create handle for" << _path << ", error:" << errorCode;
|
||||
qCWarning(lcFolderWatcher) << "Failed to create handle for" << _path << ", error:" << Utility::formatLastWinError();
|
||||
_directory = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
|
||||
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
||||
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
||||
fileNotifyBuffer.resize(OCC::Utility::convertSizeToInt(fileNotifyBufferSize));
|
||||
fileNotifyBuffer.resize(static_cast<int>(fileNotifyBufferSize));
|
||||
|
||||
const size_t fileNameBufferSize = 4096;
|
||||
TCHAR fileNameBuffer[fileNameBufferSize];
|
||||
|
@ -64,11 +65,10 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
ResetEvent(_resultEvent);
|
||||
|
||||
FILE_NOTIFY_INFORMATION *pFileNotifyBuffer =
|
||||
(FILE_NOTIFY_INFORMATION *)fileNotifyBuffer.data();
|
||||
reinterpret_cast<FILE_NOTIFY_INFORMATION *>(fileNotifyBuffer.data());
|
||||
DWORD dwBytesReturned = 0;
|
||||
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
||||
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
||||
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
|
||||
if (!ReadDirectoryChangesW(_directory, pFileNotifyBuffer,
|
||||
static_cast<DWORD>(fileNotifyBufferSize), true,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME
|
||||
| FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
| FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
|
@ -76,13 +76,13 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
&dwBytesReturned,
|
||||
&overlapped,
|
||||
nullptr)) {
|
||||
DWORD errorCode = GetLastError();
|
||||
const DWORD errorCode = GetLastError();
|
||||
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
|
||||
qCDebug(lcFolderWatcher) << "The buffer for changes overflowed! Triggering a generic change and resizing";
|
||||
emit changed(_path);
|
||||
*increaseBufferSize = true;
|
||||
} else {
|
||||
qCWarning(lcFolderWatcher) << "ReadDirectoryChangesW error" << errorCode;
|
||||
qCWarning(lcFolderWatcher) << "ReadDirectoryChangesW error" << Utility::formatWinError(errorCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -99,47 +99,56 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
break;
|
||||
}
|
||||
if (result != 0) {
|
||||
qCWarning(lcFolderWatcher) << "WaitForMultipleObjects failed" << result << GetLastError();
|
||||
qCWarning(lcFolderWatcher) << "WaitForMultipleObjects failed" << result << Utility::formatLastWinError();
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = GetOverlappedResult(_directory, &overlapped, &dwBytesReturned, false);
|
||||
if (!ok) {
|
||||
DWORD errorCode = GetLastError();
|
||||
const DWORD errorCode = GetLastError();
|
||||
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
|
||||
qCDebug(lcFolderWatcher) << "The buffer for changes overflowed! Triggering a generic change and resizing";
|
||||
emit lostChanges();
|
||||
emit changed(_path);
|
||||
*increaseBufferSize = true;
|
||||
} else {
|
||||
qCWarning(lcFolderWatcher) << "GetOverlappedResult error" << errorCode;
|
||||
qCWarning(lcFolderWatcher) << "GetOverlappedResult error" << Utility::formatWinError(errorCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
||||
forever {
|
||||
size_t len = curEntry->FileNameLength / 2;
|
||||
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, OCC::Utility::convertSizeToInt(len));
|
||||
const int len = curEntry->FileNameLength / sizeof(wchar_t);
|
||||
QString longfile = longPath + QString::fromWCharArray(curEntry->FileName, len);
|
||||
|
||||
// Unless the file was removed or renamed, get its full long name
|
||||
// TODO: We could still try expanding the path in the tricky cases...
|
||||
QString longfile = file;
|
||||
if (curEntry->Action != FILE_ACTION_REMOVED
|
||||
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
||||
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
||||
const auto wfile = longfile.toStdWString();
|
||||
const int longNameSize = GetLongPathNameW(wfile.data(), fileNameBuffer, fileNameBufferSize);
|
||||
if (longNameSize > 0) {
|
||||
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), OCC::Utility::convertSizeToInt(longNameSize));
|
||||
longfile = QString::fromWCharArray(fileNameBuffer, longNameSize);
|
||||
} else {
|
||||
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
||||
qCWarning(lcFolderWatcher) << "Error converting file name" << longfile << "to full length, keeping original name." << Utility::formatLastWinError();
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
// The prefix is needed for native Windows functions before Windows 10, version 1607
|
||||
const bool hasLongPathPrefix = longPath.startsWith(QStringLiteral("\\\\?\\"));
|
||||
if (hasLongPathPrefix)
|
||||
{
|
||||
longfile.remove(0, 4);
|
||||
}
|
||||
#endif
|
||||
longfile = QDir::cleanPath(longfile);
|
||||
|
||||
// Skip modifications of folders: One of these is triggered for changes
|
||||
// and new files in a folder, probably because of the folder's mtime
|
||||
// changing. We don't need them.
|
||||
bool skip = curEntry->Action == FILE_ACTION_MODIFIED
|
||||
const bool skip = curEntry->Action == FILE_ACTION_MODIFIED
|
||||
&& QFileInfo(longfile).isDir();
|
||||
|
||||
if (!skip) {
|
||||
|
@ -151,7 +160,8 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||
if (curEntry->NextEntryOffset == 0) {
|
||||
break;
|
||||
}
|
||||
curEntry = (FILE_NOTIFY_INFORMATION *)((char *)curEntry + curEntry->NextEntryOffset);
|
||||
// FILE_NOTIFY_INFORMATION has no fixed size and the offset is in bytes therefor we first need to cast to char
|
||||
curEntry = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(reinterpret_cast<char*>(curEntry) + curEntry->NextEntryOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +185,7 @@ void WatcherThread::run()
|
|||
// If this buffer fills up before we've extracted its data we will lose
|
||||
// change information. Therefore start big.
|
||||
size_t bufferSize = 4096 * 10;
|
||||
size_t maxBuffer = 64 * 1024;
|
||||
const size_t maxBuffer = 64 * 1024;
|
||||
|
||||
while (!_done) {
|
||||
bool increaseBufferSize = false;
|
||||
|
|
|
@ -33,7 +33,7 @@ class WatcherThread : public QThread
|
|||
public:
|
||||
WatcherThread(const QString &path)
|
||||
: QThread()
|
||||
, _path(path)
|
||||
, _path(path + (path.endsWith(QLatin1Char('/')) ? QString() : QStringLiteral("/")))
|
||||
, _directory(0)
|
||||
, _resultEvent(0)
|
||||
, _stopEvent(0)
|
||||
|
|
Loading…
Reference in a new issue