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
15#ifndef SYNCFILEITEM_H
16#define SYNCFILEITEM_H
17
18#include <QVector>
19#include <QString>
20#include <QDateTime>
21#include <QMetaType>
22#include <QSharedPointer>
23
24#include <csync.h>
25
26namespace OCC {
27
28class SyncFileItem;
29class SyncJournalFileRecord;
30typedef QSharedPointer<SyncFileItem> SyncFileItemPtr;
31
32/**
33 * @brief The SyncFileItem class
34 * @ingroup libsync
35 */
36class SyncFileItem
37{
38public:
39 enum Direction {
40 None = 0,
41 Up,
42 Down
43 };
44
45 enum Status { // stored in 4 bits
46 NoStatus,
47
48 FatalError, ///< Error that causes the sync to stop
49 NormalError, ///< Error attached to a particular file
50 SoftError, ///< More like an information
51
52 Success, ///< The file was properly synced
53
54 /** Marks a conflict, old or new.
55 *
56 * With instruction:IGNORE: detected an old unresolved old conflict
57 * With instruction:CONFLICT: a new conflict this sync run
58 */
59 Conflict,
60
61 FileIgnored, ///< The file is in the ignored list (or blacklisted with no retries left)
62 Restoration, ///< The file was restored because what should have been done was not allowed
63
64 /** For errors that should only appear in the error view.
65 *
66 * Some errors also produce a summary message. Usually displaying that message is
67 * sufficient, but the individual errors should still appear in the issues tab.
68 *
69 * These errors do cause the sync to fail.
70 *
71 * A NormalError that isn't as prominent.
72 */
73 DetailError,
74
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 };
84
85 SyncJournalFileRecord toSyncJournalFileRecordWithInode(const QString &localFileName);
86
87 /** Creates a basic SyncFileItem from a DB record
88 *
89 * This is intended in particular for read-update-write cycles that need
90 * to go through a a SyncFileItem, like PollJob.
91 */
92 static SyncFileItemPtr fromSyncJournalFileRecord(const SyncJournalFileRecord &rec);
93
94
95 SyncFileItem()
96 : _type(ItemTypeSkip)
97 , _direction(None)
98 , _serverHasIgnoredFiles(false)
99 , _hasBlacklistEntry(false)
100 , _errorMayBeBlacklisted(false)
101 , _status(NoStatus)
102 , _isRestoration(false)
103 , _httpErrorCode(0)
104 , _affectedItems(1)
105 , _instruction(CSYNC_INSTRUCTION_NONE)
106 , _modtime(0)
107 , _size(0)
108 , _inode(0)
109 , _previousSize(0)
110 , _previousModtime(0)
111 {
112 }
113
114 friend bool operator==(const SyncFileItem &item1, const SyncFileItem &item2)
115 {
116 return item1._originalFile == item2._originalFile;
117 }
118
119 friend bool operator<(const SyncFileItem &item1, const SyncFileItem &item2)
120 {
121 // Sort by destination
122 auto d1 = item1.destination();
123 auto d2 = item2.destination();
124
125 // But this we need to order it so the slash come first. It should be this order:
126 // "foo", "foo/bar", "foo-bar"
127 // This is important since we assume that the contents of a folder directly follows
128 // its contents
129
130 auto data1 = d1.constData();
131 auto data2 = d2.constData();
132
133 // Find the length of the largest prefix
134 int prefixL = 0;
135 auto minSize = std::min(d1.size(), d2.size());
136 while (prefixL < minSize && data1[prefixL] == data2[prefixL]) {
137 prefixL++;
138 }
139
140 if (prefixL == d2.size())
141 return false;
142 if (prefixL == d1.size())
143 return true;
144
145 if (data1[prefixL] == '/')
146 return true;
147 if (data2[prefixL] == '/')
148 return false;
149
150 return data1[prefixL] < data2[prefixL];
151 }
152
153 QString destination() const
154 {
155 if (!_renameTarget.isEmpty()) {
156 return _renameTarget;
157 }
158 return _file;
159 }
160
161 bool isEmpty() const
162 {
163 return _file.isEmpty();
164 }
165
166 bool isDirectory() const
167 {
168 return _type == ItemTypeDirectory;
169 }
170
171 /**
172 * True if the item had any kind of error.
173 */
174 bool hasErrorStatus() const
175 {
176 return _status == SyncFileItem::SoftError
177 || _status == SyncFileItem::NormalError
178 || _status == SyncFileItem::FatalError
179 || !_errorString.isEmpty();
180 }
181
182 /**
183 * Whether this item should appear on the issues tab.
184 */
185 bool showInIssuesTab() const
186 {
187 return hasErrorStatus() || _status == SyncFileItem::Conflict;
188 }
189
190 /**
191 * Whether this item should appear on the protocol tab.
192 */
193 bool showInProtocolTab() const
194 {
195 return !showInIssuesTab()
196 // Don't show conflicts that were resolved as "not a conflict after all"
197 && !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
198 }
199
200 // Variables useful for everybody
201 QString _file;
202 QString _renameTarget;
203 ItemType _type BITFIELD(3);
204 Direction _direction BITFIELD(3);
205 bool _serverHasIgnoredFiles BITFIELD(1);
206
207 /// Whether there's an entry in the blacklist table.
208 /// Note: that entry may have retries left, so this can be true
209 /// without the status being FileIgnored.
210 bool _hasBlacklistEntry BITFIELD(1);
211
212 /** If true and NormalError, this error may be blacklisted
213 *
214 * Note that non-local errors (httpErrorCode!=0) may also be
215 * blacklisted independently of this flag.
216 */
217 bool _errorMayBeBlacklisted BITFIELD(1);
218
219 // Variables useful to report to the user
220 Status _status BITFIELD(4);
221 bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
222 quint16 _httpErrorCode;
223 RemotePermissions _remotePerm;
224 QString _errorString; // Contains a string only in case of error
225 QByteArray _responseTimeStamp;
226 QByteArray _requestId; // X-Request-Id of the failed request
227 quint32 _affectedItems; // the number of affected items by the operation on this item.
228 // usually this value is 1, but for removes on dirs, it might be much higher.
229
230 // Variables used by the propagator
231 csync_instructions_e _instruction;
232 QString _originalFile; // as it is in the csync tree
233 time_t _modtime;
234 QByteArray _etag;
235 quint64 _size;
236 quint64 _inode;
237 QByteArray _fileId;
238
239 // This is the value for the 'new' side, matching with _size and _modtime.
240 //
241 // When is this set, and is it the local or the remote checksum?
242 // - if mtime or size changed locally for *.eml files (local checksum)
243 // - for potential renames of local files (local checksum)
244 // - for conflicts (remote checksum)
245 QByteArray _checksumHeader;
246
247 // The size and modtime of the file getting overwritten (on the disk for downloads, on the server for uploads).
248 quint64 _previousSize;
249 time_t _previousModtime;
250
251 QString _directDownloadUrl;
252 QString _directDownloadCookies;
253};
254
255inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2)
256{
257 return *item1 < *item2;
258}
259
260typedef QVector<SyncFileItemPtr> SyncFileItemVector;
261}
262
263Q_DECLARE_METATYPE(OCC::SyncFileItem)
264Q_DECLARE_METATYPE(OCC::SyncFileItemPtr)
265
266#endif // SYNCFILEITEM_H
267