syncfileitem.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. * for more details.
  13. */
  14. #ifndef SYNCFILEITEM_H
  15. #define SYNCFILEITEM_H
  16. #include <QVector>
  17. #include <QString>
  18. #include <QDateTime>
  19. #include <QMetaType>
  20. #include <QSharedPointer>
  21. #include <csync.h>
  22. #include <owncloudlib.h>
  23. namespace OCC {
  24. class SyncFileItem;
  25. class SyncJournalFileRecord;
  26. using SyncFileItemPtr = QSharedPointer<SyncFileItem>;
  27. /**
  28. * @brief The SyncFileItem class
  29. * @ingroup libsync
  30. */
  31. class OWNCLOUDSYNC_EXPORT SyncFileItem
  32. {
  33. Q_GADGET
  34. public:
  35. enum Direction {
  36. None = 0,
  37. Up,
  38. Down
  39. };
  40. Q_ENUM(Direction)
  41. // Note: the order of these statuses is used for ordering in the SortedActivityListModel
  42. enum Status { // stored in 4 bits
  43. NoStatus,
  44. FatalError, ///< Error that causes the sync to stop
  45. NormalError, ///< Error attached to a particular file
  46. SoftError, ///< More like an information
  47. /** Marks a conflict, old or new.
  48. *
  49. * With instruction:IGNORE: detected an old unresolved old conflict
  50. * With instruction:CONFLICT: a new conflict this sync run
  51. */
  52. Conflict,
  53. FileIgnored, ///< The file is in the ignored list (or blacklisted with no retries left)
  54. FileLocked, ///< The file is locked
  55. Restoration, ///< The file was restored because what should have been done was not allowed
  56. /**
  57. * The filename is invalid on this platform and could not created.
  58. */
  59. FileNameInvalid,
  60. /**
  61. * There is a file name clash (e.g. attempting to download test.txt when TEST.TXT already exists
  62. * on a platform where the filesystem is case-insensitive
  63. */
  64. FileNameClash,
  65. /** For errors that should only appear in the error view.
  66. *
  67. * Some errors also produce a summary message. Usually displaying that message is
  68. * sufficient, but the individual errors should still appear in the issues tab.
  69. *
  70. * These errors do cause the sync to fail.
  71. *
  72. * A NormalError that isn't as prominent.
  73. */
  74. DetailError,
  75. /** For files whose errors were blacklisted
  76. *
  77. * If an file is blacklisted due to an error it isn't even reattempted. These
  78. * errors should appear in the issues tab but should be silent otherwise.
  79. *
  80. * A SoftError caused by blacklisting.
  81. */
  82. BlacklistedError,
  83. Success, ///< The file was properly synced
  84. };
  85. Q_ENUM(Status)
  86. enum class LockStatus {
  87. UnlockedItem = 0,
  88. LockedItem = 1,
  89. };
  90. Q_ENUM(LockStatus)
  91. enum class LockOwnerType : int{
  92. UserLock = 0,
  93. AppLock = 1,
  94. TokenLock = 2,
  95. };
  96. Q_ENUM(LockOwnerType)
  97. [[nodiscard]] SyncJournalFileRecord toSyncJournalFileRecordWithInode(const QString &localFileName) const;
  98. /** Creates a basic SyncFileItem from a DB record
  99. *
  100. * This is intended in particular for read-update-write cycles that need
  101. * to go through a a SyncFileItem, like PollJob.
  102. */
  103. static SyncFileItemPtr fromSyncJournalFileRecord(const SyncJournalFileRecord &rec);
  104. /** Creates a basic SyncFileItem from remote properties
  105. */
  106. [[nodiscard]] static SyncFileItemPtr fromProperties(const QString &filePath, const QMap<QString, QString> &properties);
  107. SyncFileItem()
  108. : _type(ItemTypeSkip)
  109. , _direction(None)
  110. , _serverHasIgnoredFiles(false)
  111. , _hasBlacklistEntry(false)
  112. , _errorMayBeBlacklisted(false)
  113. , _status(NoStatus)
  114. , _isRestoration(false)
  115. , _isSelectiveSync(false)
  116. , _isEncrypted(false)
  117. {
  118. }
  119. friend bool operator==(const SyncFileItem &item1, const SyncFileItem &item2)
  120. {
  121. return item1._originalFile == item2._originalFile;
  122. }
  123. friend bool operator<(const SyncFileItem &item1, const SyncFileItem &item2)
  124. {
  125. // Sort by destination
  126. auto d1 = item1.destination();
  127. auto d2 = item2.destination();
  128. // But this we need to order it so the slash come first. It should be this order:
  129. // "foo", "foo/bar", "foo-bar"
  130. // This is important since we assume that the contents of a folder directly follows
  131. // its contents
  132. auto data1 = d1.constData();
  133. auto data2 = d2.constData();
  134. // Find the length of the largest prefix
  135. int prefixL = 0;
  136. auto minSize = std::min(d1.size(), d2.size());
  137. while (prefixL < minSize && data1[prefixL] == data2[prefixL]) {
  138. prefixL++;
  139. }
  140. if (prefixL == d2.size())
  141. return false;
  142. if (prefixL == d1.size())
  143. return true;
  144. if (data1[prefixL] == '/')
  145. return true;
  146. if (data2[prefixL] == '/')
  147. return false;
  148. return data1[prefixL] < data2[prefixL];
  149. }
  150. [[nodiscard]] QString destination() const
  151. {
  152. if (!_renameTarget.isEmpty()) {
  153. return _renameTarget;
  154. }
  155. return _file;
  156. }
  157. [[nodiscard]] bool isEmpty() const
  158. {
  159. return _file.isEmpty();
  160. }
  161. [[nodiscard]] bool isDirectory() const
  162. {
  163. return _type == ItemTypeDirectory;
  164. }
  165. /**
  166. * True if the item had any kind of error.
  167. */
  168. [[nodiscard]] bool hasErrorStatus() const
  169. {
  170. return _status == SyncFileItem::SoftError
  171. || _status == SyncFileItem::NormalError
  172. || _status == SyncFileItem::FatalError
  173. || !_errorString.isEmpty();
  174. }
  175. /**
  176. * Whether this item should appear on the issues tab.
  177. */
  178. [[nodiscard]] bool showInIssuesTab() const
  179. {
  180. return hasErrorStatus() || _status == SyncFileItem::Conflict;
  181. }
  182. /**
  183. * Whether this item should appear on the protocol tab.
  184. */
  185. [[nodiscard]] bool showInProtocolTab() const
  186. {
  187. return (!showInIssuesTab() || _status == SyncFileItem::Restoration)
  188. // Don't show conflicts that were resolved as "not a conflict after all"
  189. && !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
  190. }
  191. // Variables useful for everybody
  192. /** The syncfolder-relative filesystem path that the operation is about
  193. *
  194. * For rename operation this is the rename source and the target is in _renameTarget.
  195. */
  196. QString _file;
  197. /** for renames: the name _file should be renamed to
  198. * for dehydrations: the name _file should become after dehydration (like adding a suffix)
  199. * otherwise empty. Use destination() to find the sync target.
  200. */
  201. QString _renameTarget;
  202. /** The db-path of this item.
  203. *
  204. * This can easily differ from _file and _renameTarget if parts of the path were renamed.
  205. */
  206. QString _originalFile;
  207. /// Whether there's end to end encryption on this file.
  208. /// If the file is encrypted, the _encryptedFilename is
  209. /// the encrypted name on the server.
  210. QString _encryptedFileName;
  211. ItemType _type BITFIELD(3);
  212. Direction _direction BITFIELD(3);
  213. bool _serverHasIgnoredFiles BITFIELD(1);
  214. /// Whether there's an entry in the blacklist table.
  215. /// Note: that entry may have retries left, so this can be true
  216. /// without the status being FileIgnored.
  217. bool _hasBlacklistEntry BITFIELD(1);
  218. /** If true and NormalError, this error may be blacklisted
  219. *
  220. * Note that non-local errors (httpErrorCode!=0) may also be
  221. * blacklisted independently of this flag.
  222. */
  223. bool _errorMayBeBlacklisted BITFIELD(1);
  224. // Variables useful to report to the user
  225. Status _status BITFIELD(4);
  226. bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
  227. bool _isSelectiveSync BITFIELD(1); // The file is removed or ignored because it is in the selective sync list
  228. bool _isEncrypted BITFIELD(1); // The file is E2EE or the content of the directory should be E2EE
  229. quint16 _httpErrorCode = 0;
  230. RemotePermissions _remotePerm;
  231. QString _errorString; // Contains a string only in case of error
  232. QByteArray _responseTimeStamp;
  233. QByteArray _requestId; // X-Request-Id of the failed request
  234. quint32 _affectedItems = 1; // the number of affected items by the operation on this item.
  235. // usually this value is 1, but for removes on dirs, it might be much higher.
  236. // Variables used by the propagator
  237. SyncInstructions _instruction = CSYNC_INSTRUCTION_NONE;
  238. time_t _modtime = 0;
  239. QByteArray _etag;
  240. qint64 _size = 0;
  241. quint64 _inode = 0;
  242. QByteArray _fileId;
  243. // This is the value for the 'new' side, matching with _size and _modtime.
  244. //
  245. // When is this set, and is it the local or the remote checksum?
  246. // - if mtime or size changed locally for *.eml files (local checksum)
  247. // - for potential renames of local files (local checksum)
  248. // - for conflicts (remote checksum)
  249. QByteArray _checksumHeader;
  250. // The size and modtime of the file getting overwritten (on the disk for downloads, on the server for uploads).
  251. qint64 _previousSize = 0;
  252. time_t _previousModtime = 0;
  253. QString _directDownloadUrl;
  254. QString _directDownloadCookies;
  255. LockStatus _locked = LockStatus::UnlockedItem;
  256. QString _lockOwnerId;
  257. QString _lockOwnerDisplayName;
  258. LockOwnerType _lockOwnerType = LockOwnerType::UserLock;
  259. QString _lockEditorApp;
  260. qint64 _lockTime = 0;
  261. qint64 _lockTimeout = 0;
  262. bool _isShared = false;
  263. time_t _lastShareStateFetchedTimestamp = 0;
  264. bool _sharedByMe = false;
  265. };
  266. inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2)
  267. {
  268. return *item1 < *item2;
  269. }
  270. using SyncFileItemVector = QVector<SyncFileItemPtr>;
  271. }
  272. Q_DECLARE_METATYPE(OCC::SyncFileItem)
  273. Q_DECLARE_METATYPE(OCC::SyncFileItemPtr)
  274. #endif // SYNCFILEITEM_H