Lnk: Work around QFile::rename() #2792

QFile::rename() fails if the source file is a shortcut to a file
or directory that does not exist.
This commit is contained in:
Christian Kamm 2015-03-11 10:51:36 +01:00
parent db7919dc2f
commit efe9f1b442
7 changed files with 72 additions and 22 deletions

View file

@ -21,6 +21,7 @@
#include "account.h"
#include "accountmigrator.h"
#include "accountstate.h"
#include "filesystem.h"
#ifdef Q_OS_MAC
#include <CoreServices/CoreServices.h>
@ -852,9 +853,10 @@ bool FolderMan::startFromScratch( const QString& localFolder )
// Make a backup of the folder/file.
QString newName = getBackupName( parentDir.absoluteFilePath( folderName ) );
if( !parentDir.rename( fi.absoluteFilePath(), newName ) ) {
QString renameError;
if( !FileSystem::rename( fi.absoluteFilePath(), newName, &renameError ) ) {
qDebug() << "startFromScratch: Could not rename" << fi.absoluteFilePath()
<< "to" << newName;
<< "to" << newName << "error:" << renameError;
return false;
}
}

View file

@ -107,6 +107,54 @@ bool FileSystem::setModTime(const QString& filename, time_t modTime)
return true;
}
#ifdef Q_OS_WIN
static bool isLnkFile(const QString& filename)
{
return filename.endsWith(".lnk");
}
#endif
bool FileSystem::rename(const QString &originFileName,
const QString &destinationFileName,
QString *errorString)
{
bool success = false;
QString error;
#ifdef Q_OS_WIN
if (isLnkFile(originFileName) || isLnkFile(destinationFileName)) {
success = MoveFileEx((wchar_t*)originFileName.utf16(),
(wchar_t*)destinationFileName.utf16(),
MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH);
if (!success) {
wchar_t *string = 0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&string, 0, NULL);
error = QString::fromWCharArray(string);
LocalFree((HLOCAL)string);
}
} else
#endif
{
QFile orig(originFileName);
success = orig.rename(destinationFileName);
if (!success) {
error = orig.errorString();
}
}
if (!success) {
qDebug() << "FAIL: renaming file" << originFileName
<< "to" << destinationFileName
<< "failed: " << error;
if (errorString) {
*errorString = error;
}
}
return success;
}
bool FileSystem::renameReplace(const QString& originFileName, const QString& destinationFileName, QString* errorString)
{
#ifndef Q_OS_WIN
@ -215,16 +263,6 @@ bool FileSystem::openFileSharedRead(QFile* file, QString* error)
}
#ifdef Q_OS_WIN
static bool isLnkFile(const QString& filename)
{
return filename.endsWith(".lnk");
}
static bool isLnkFile(const QFileInfo& fi)
{
return fi.suffix() == "lnk";
}
static qint64 getSizeWithCsync(const QString& filename)
{
qint64 result = 0;

View file

@ -59,6 +59,14 @@ qint64 OWNCLOUDSYNC_EXPORT getSize(const QString& filename);
*/
bool OWNCLOUDSYNC_EXPORT fileExists(const QString& filename);
/**
* Rename the file \a originFileName to \a destinationFileName.
*
* It behaves as QFile::rename() but handles .lnk files correctly on Windows.
*/
bool OWNCLOUDSYNC_EXPORT rename(const QString& originFileName,
const QString& destinationFileName,
QString* errorString = NULL);
/**
* Rename the file \a originFileName to \a destinationFileName, and overwrite the destination if it
* already exists

View file

@ -492,11 +492,11 @@ void PropagateDownloadFileQNAM::downloadFinished()
bool isConflict = _item._instruction == CSYNC_INSTRUCTION_CONFLICT
&& !FileSystem::fileEquals(fn, _tmpFile.fileName());
if (isConflict) {
QFile f(fn);
QString renameError;
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime));
if (!f.rename(conflictFileName)) {
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
//If the rename fails, don't replace it.
done(SyncFileItem::SoftError, f.errorString());
done(SyncFileItem::SoftError, renameError);
return;
}
}

View file

@ -16,6 +16,7 @@
#include "owncloudpropagator_p.h"
#include "account.h"
#include "syncjournalfilerecord.h"
#include "filesystem.h"
#include <QFile>
#include <QStringList>
@ -81,7 +82,8 @@ void PropagateRemoteMove::start()
QString originalFile(_propagator->getFilePath(QLatin1String("Shared")));
_propagator->addTouchedFile(originalFile);
_propagator->addTouchedFile(targetFile);
if( QFile::rename( targetFile, originalFile) ) {
QString renameError;
if( FileSystem::rename(targetFile, originalFile, &renameError) ) {
done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name."));
} else {
done(SyncFileItem::NormalError, tr("This folder must not be renamed. Please name it back to Shared."));

View file

@ -695,11 +695,11 @@ void PropagateDownloadFileLegacy::start()
&& !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict.
//In case of conflict, make a backup of the old file
if (isConflict) {
QFile f(fn);
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime));
if (!f.rename(conflictFileName)) {
QString renameError;
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
//If the rename fails, don't replace it.
done(SyncFileItem::NormalError, f.errorString());
done(SyncFileItem::NormalError, renameError);
return;
}
}

View file

@ -155,9 +155,9 @@ void PropagateLocalRename::start()
_propagator->addTouchedFile(existingFile);
_propagator->addTouchedFile(targetFile);
QFile file(existingFile);
if (!file.rename(targetFile)) {
done(SyncFileItem::NormalError, file.errorString());
QString renameError;
if (!FileSystem::rename(existingFile, targetFile, &renameError)) {
done(SyncFileItem::NormalError, renameError);
return;
}
}