Propagator: Use FILE_SHARE_DELETE on Windows. #2070 #2597

This commit is contained in:
Christian Kamm 2015-01-14 12:35:28 +01:00
parent 3ec19ee355
commit b3c02798a3
3 changed files with 71 additions and 2 deletions

View file

@ -25,6 +25,7 @@
#ifdef Q_OS_WIN
#include <windef.h>
#include <winbase.h>
#include <fcntl.h>
#endif
// We use some internals of csync:
@ -149,6 +150,62 @@ bool FileSystem::renameReplace(const QString& originFileName, const QString& des
return true;
}
bool FileSystem::openFileSharedRead(QFile* file, QString* error)
{
bool ok = false;
if (error) {
error->clear();
}
#ifdef Q_OS_WIN
//
// The following code is adapted from Qt's QFSFileEnginePrivate::nativeOpen()
// by including the FILE_SHARE_DELETE share mode.
//
// Enable full sharing.
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
int accessRights = GENERIC_READ;
DWORD creationDisp = OPEN_EXISTING;
// Create the file handle.
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
HANDLE fileHandle = CreateFileW(
(const wchar_t*)file->fileName().utf16(),
accessRights,
shareMode,
&securityAtts,
creationDisp,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Bail out on error.
if (fileHandle == INVALID_HANDLE_VALUE) {
if (error) {
*error = qt_error_string();
}
return false;
}
// Convert the HANDLE to an fd and pass it to QFile's foreign-open
// function. The fd owns the handle, so when QFile later closes
// the fd the handle will be closed too.
int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY);
if (fd == -1) {
if (error) {
*error = "could not make fd from handle";
}
return false;
}
ok = file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle);
#else
ok = file->open(QFile::ReadOnly);
#endif
if (! ok && error) {
*error = file->errorString();
}
return ok;
}
}

View file

@ -14,6 +14,7 @@
#pragma once
#include <QString>
#include <QFile>
#include <ctime>
#include <owncloudlib.h>
@ -49,4 +50,13 @@ bool setModTime(const QString &filename, time_t modTime);
bool renameReplace(const QString &originFileName, const QString &destinationFileName,
QString *errorString);
/**
* Replacement for QFile::open(ReadOnly) that sets a more permissive sharing mode
* on Windows.
*
* Warning: The resuting file may have an empty fileName and be unsuitable for use
* with QFileInfo!
*/
bool openFileSharedRead(QFile* file, QString* error);
}}

View file

@ -348,9 +348,11 @@ void PropagateUploadFileQNAM::startNextChunk()
QString path = _item._file;
QFile file(_propagator->getFilePath(_item._file), this);
if (!file.open(QIODevice::ReadOnly)) {
QString openError;
// Warning: this clears file->fileName() and makes it unsuitable for QFileInfo!
if (!FileSystem::openFileSharedRead(&file, &openError)) {
// Soft error because this is likely caused by the user modifying his files while syncing
abortWithError(SyncFileItem::SoftError, file.errorString());
abortWithError(SyncFileItem::SoftError, openError);
return;
}