nextcloud-desktop/src/libsync/syncfileitem.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

295 lines
9 KiB
C
Raw Normal View History

/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
2013-01-15 23:41:52 +04:00
#ifndef SYNCFILEITEM_H
#define SYNCFILEITEM_H
#include <QVector>
#include <QString>
#include <QDateTime>
2013-05-16 15:54:22 +04:00
#include <QMetaType>
#include <QSharedPointer>
2013-01-15 23:41:52 +04:00
#include <csync.h>
2018-10-20 14:25:22 +03:00
#include <owncloudlib.h>
2014-11-10 00:34:07 +03:00
namespace OCC {
2013-01-15 23:41:52 +04:00
class SyncFileItem;
class SyncJournalFileRecord;
using SyncFileItemPtr = QSharedPointer<SyncFileItem>;
2015-06-29 19:56:09 +03:00
/**
* @brief The SyncFileItem class
* @ingroup libsync
*/
2018-10-20 14:25:22 +03:00
class OWNCLOUDSYNC_EXPORT SyncFileItem
2013-01-15 23:41:52 +04:00
{
Q_GADGET
2013-01-15 23:41:52 +04:00
public:
enum Direction {
None = 0,
Up,
Down
};
Q_ENUM(Direction)
enum Status { // stored in 4 bits
NoStatus,
FatalError, ///< Error that causes the sync to stop
NormalError, ///< Error attached to a particular file
SoftError, ///< More like an information
Success, ///< The file was properly synced
/** Marks a conflict, old or new.
*
* With instruction:IGNORE: detected an old unresolved old conflict
* With instruction:CONFLICT: a new conflict this sync run
*/
Conflict,
FileIgnored, ///< The file is in the ignored list (or blacklisted with no retries left)
FileLocked, ///< The file is locked
Restoration, ///< The file was restored because what should have been done was not allowed
/**
* The filename is invalid on this platform and could not created.
*/
FileNameInvalid,
/** For errors that should only appear in the error view.
*
* Some errors also produce a summary message. Usually displaying that message is
* sufficient, but the individual errors should still appear in the issues tab.
*
* These errors do cause the sync to fail.
*
* A NormalError that isn't as prominent.
*/
DetailError,
/** For files whose errors were blacklisted
*
* If an file is blacklisted due to an error it isn't even reattempted. These
* errors should appear in the issues tab but should be silent otherwise.
*
* A SoftError caused by blacklisting.
*/
BlacklistedError
};
Q_ENUM(Status)
SyncJournalFileRecord toSyncJournalFileRecordWithInode(const QString &localFileName) const;
/** Creates a basic SyncFileItem from a DB record
*
* This is intended in particular for read-update-write cycles that need
* to go through a a SyncFileItem, like PollJob.
*/
static SyncFileItemPtr fromSyncJournalFileRecord(const SyncJournalFileRecord &rec);
SyncFileItem()
: _type(ItemTypeSkip)
, _direction(None)
, _serverHasIgnoredFiles(false)
, _hasBlacklistEntry(false)
, _errorMayBeBlacklisted(false)
, _status(NoStatus)
csync: Use an explicit instruction for should_update_metadata The current way of tracking the need to update the metadata without propagation using a separate flag makes it difficult to track priorities between the local and remote tree. The logic is also difficult to logically cover since the possibilities matrix isn't 100% covered, leaving the flag only used in a few situations (mostly involving folders, but not only). The reason we need to change this is to be able to track the sync state of files for overlay icons. The instruction alone can't be used since CSYNC_INSTRUCTION_SYNC is used for folders even though they won't be propagated. Removing this logic is however not possible without using something else than CSYNC_INSTRUCTION_NONE since too many codepath interpret (rightfully) this as meaning "nothing to do". This patch adds a new CSYNC_INSTRUCTION_UPDATE_METADATA instruction to let the update and reconcile steps tell the SyncEngine to update the metadata of a file without any propagation. Other flags are left to be interpretted by the implementation as implicitly needing metadata update or not, as this was already the case for most file propagation jobs. For example, CSYNC_INSTRUCTION_NEW for directories now also implicitly update the metadata. Since it's not impossible for folders to emit CSYNC_INSTRUCTION_SYNC or CSYNC_INSTRUCTION_CONFLICT, the corresponding code paths in the sync engine have been removed. Since the reconcile step can now know if the local tree needs metadata update while the remote side might want propagation, the localMetadataUpdate logic in SyncEngine::treewalkFile now simply use a CSYNC_INSTRUCTION_UPDATE_METADATA for the local side, which is now implemented as a different database query.
2016-08-15 15:17:51 +03:00
, _isRestoration(false)
, _isSelectiveSync(false)
, _isEncrypted(false)
{
}
2013-01-15 23:41:52 +04:00
friend bool operator==(const SyncFileItem &item1, const SyncFileItem &item2)
{
return item1._originalFile == item2._originalFile;
}
friend bool operator<(const SyncFileItem &item1, const SyncFileItem &item2)
{
// Sort by destination
auto d1 = item1.destination();
auto d2 = item2.destination();
// But this we need to order it so the slash come first. It should be this order:
// "foo", "foo/bar", "foo-bar"
// This is important since we assume that the contents of a folder directly follows
// its contents
auto data1 = d1.constData();
auto data2 = d2.constData();
// Find the length of the largest prefix
int prefixL = 0;
auto minSize = std::min(d1.size(), d2.size());
while (prefixL < minSize && data1[prefixL] == data2[prefixL]) {
prefixL++;
}
if (prefixL == d2.size())
return false;
if (prefixL == d1.size())
return true;
if (data1[prefixL] == '/')
return true;
if (data2[prefixL] == '/')
return false;
return data1[prefixL] < data2[prefixL];
2013-01-15 23:41:52 +04:00
}
QString destination() const
{
if (!_renameTarget.isEmpty()) {
return _renameTarget;
}
return _file;
}
bool isEmpty() const
{
return _file.isEmpty();
}
bool isDirectory() const
{
return _type == ItemTypeDirectory;
}
/**
* True if the item had any kind of error.
*/
bool hasErrorStatus() const
{
return _status == SyncFileItem::SoftError
|| _status == SyncFileItem::NormalError
|| _status == SyncFileItem::FatalError
|| !_errorString.isEmpty();
}
/**
* Whether this item should appear on the issues tab.
*/
bool showInIssuesTab() const
{
return hasErrorStatus() || _status == SyncFileItem::Conflict;
}
/**
* Whether this item should appear on the protocol tab.
*/
bool showInProtocolTab() const
{
return (!showInIssuesTab() || _status == SyncFileItem::Restoration)
// Don't show conflicts that were resolved as "not a conflict after all"
&& !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
}
// Variables useful for everybody
/** The syncfolder-relative filesystem path that the operation is about
*
* For rename operation this is the rename source and the target is in _renameTarget.
*/
2013-01-15 23:41:52 +04:00
QString _file;
/** for renames: the name _file should be renamed to
* for dehydrations: the name _file should become after dehydration (like adding a suffix)
* otherwise empty. Use destination() to find the sync target.
*/
2013-01-15 23:41:52 +04:00
QString _renameTarget;
/** The db-path of this item.
*
* This can easily differ from _file and _renameTarget if parts of the path were renamed.
*/
QString _originalFile;
/// Whether there's end to end encryption on this file.
/// If the file is encrypted, the _encryptedFilename is
/// the encrypted name on the server.
QString _encryptedFileName;
ItemType _type BITFIELD(3);
Direction _direction BITFIELD(3);
bool _serverHasIgnoredFiles BITFIELD(1);
/// Whether there's an entry in the blacklist table.
/// Note: that entry may have retries left, so this can be true
/// without the status being FileIgnored.
bool _hasBlacklistEntry BITFIELD(1);
/** If true and NormalError, this error may be blacklisted
*
* Note that non-local errors (httpErrorCode!=0) may also be
* blacklisted independently of this flag.
*/
bool _errorMayBeBlacklisted BITFIELD(1);
// Variables useful to report to the user
Status _status BITFIELD(4);
bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
bool _isSelectiveSync BITFIELD(1); // The file is removed or ignored because it is in the selective sync list
bool _isEncrypted BITFIELD(1); // The file is E2EE or the content of the directory should be E2EE
quint16 _httpErrorCode = 0;
RemotePermissions _remotePerm;
QString _errorString; // Contains a string only in case of error
QByteArray _responseTimeStamp;
QByteArray _requestId; // X-Request-Id of the failed request
quint32 _affectedItems = 1; // the number of affected items by the operation on this item.
// usually this value is 1, but for removes on dirs, it might be much higher.
// Variables used by the propagator
SyncInstructions _instruction = CSYNC_INSTRUCTION_NONE;
time_t _modtime = 0;
QByteArray _etag;
qint64 _size = 0;
quint64 _inode = 0;
QByteArray _fileId;
// This is the value for the 'new' side, matching with _size and _modtime.
//
// When is this set, and is it the local or the remote checksum?
// - if mtime or size changed locally for *.eml files (local checksum)
// - for potential renames of local files (local checksum)
// - for conflicts (remote checksum)
QByteArray _checksumHeader;
// The size and modtime of the file getting overwritten (on the disk for downloads, on the server for uploads).
qint64 _previousSize = 0;
time_t _previousModtime = 0;
QString _directDownloadUrl;
QString _directDownloadCookies;
2013-01-15 23:41:52 +04:00
};
inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2)
{
return *item1 < *item2;
}
using SyncFileItemVector = QVector<SyncFileItemPtr>;
2013-01-15 23:41:52 +04:00
}
2014-11-10 00:34:07 +03:00
Q_DECLARE_METATYPE(OCC::SyncFileItem)
Q_DECLARE_METATYPE(OCC::SyncFileItemPtr)
2013-05-16 15:54:22 +04:00
2013-01-15 23:41:52 +04:00
#endif // SYNCFILEITEM_H