folder.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
  3. * Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
  4. * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. */
  16. #ifndef MIRALL_FOLDER_H
  17. #define MIRALL_FOLDER_H
  18. #include "syncresult.h"
  19. #include "progressdispatcher.h"
  20. #include "common/syncjournaldb.h"
  21. #include "networkjobs.h"
  22. #include "syncoptions.h"
  23. #include <QObject>
  24. #include <QStringList>
  25. #include <QUuid>
  26. #include <set>
  27. #include <chrono>
  28. #include <memory>
  29. class QThread;
  30. class QSettings;
  31. namespace OCC {
  32. class Vfs;
  33. class SyncEngine;
  34. class AccountState;
  35. class SyncRunFileLog;
  36. class FolderWatcher;
  37. class LocalDiscoveryTracker;
  38. /**
  39. * @brief The FolderDefinition class
  40. * @ingroup gui
  41. */
  42. class FolderDefinition
  43. {
  44. public:
  45. /// The name of the folder in the ui and internally
  46. QString alias;
  47. /// path on local machine (always trailing /)
  48. QString localPath;
  49. /// path to the journal, usually relative to localPath
  50. QString journalPath;
  51. /// path on remote (usually no trailing /, exception "/")
  52. QString targetPath;
  53. /// whether the folder is paused
  54. bool paused = false;
  55. /// whether the folder syncs hidden files
  56. bool ignoreHiddenFiles = false;
  57. /// Which virtual files setting the folder uses
  58. Vfs::Mode virtualFilesMode = Vfs::Off;
  59. /// The CLSID where this folder appears in registry for the Explorer navigation pane entry.
  60. QUuid navigationPaneClsid;
  61. /// Whether the vfs mode shall silently be updated if possible
  62. bool upgradeVfsMode = false;
  63. /// Saves the folder definition into the current settings group.
  64. static void save(QSettings &settings, const FolderDefinition &folder);
  65. /// Reads a folder definition from the current settings group.
  66. static bool load(QSettings &settings, const QString &alias,
  67. FolderDefinition *folder);
  68. /** The highest version in the settings that load() can read
  69. *
  70. * Version 1: initial version (default if value absent in settings)
  71. * Version 2: introduction of metadata_parent hash in 2.6.0
  72. * (version remains readable by 2.5.1)
  73. * Version 3: introduction of new windows vfs mode in 2.6.0
  74. */
  75. static int maxSettingsVersion() { return 3; }
  76. /// Ensure / as separator and trailing /.
  77. static QString prepareLocalPath(const QString &path);
  78. /// Remove ending /, then ensure starting '/': so "/foo/bar" and "/".
  79. static QString prepareTargetPath(const QString &path);
  80. /// journalPath relative to localPath.
  81. QString absoluteJournalPath() const;
  82. /// Returns the relative journal path that's appropriate for this folder and account.
  83. QString defaultJournalPath(AccountPtr account);
  84. };
  85. /**
  86. * @brief The Folder class
  87. * @ingroup gui
  88. */
  89. class Folder : public QObject
  90. {
  91. Q_OBJECT
  92. public:
  93. enum class ChangeReason {
  94. Other,
  95. UnLock
  96. };
  97. Q_ENUM(ChangeReason)
  98. /** Create a new Folder
  99. */
  100. Folder(const FolderDefinition &definition, AccountState *accountState, std::unique_ptr<Vfs> vfs, QObject *parent = nullptr);
  101. ~Folder() override;
  102. using Map = QMap<QString, Folder *>;
  103. using MapIterator = QMapIterator<QString, Folder *>;
  104. /**
  105. * The account the folder is configured on.
  106. */
  107. AccountState *accountState() const { return _accountState.data(); }
  108. /**
  109. * alias or nickname
  110. */
  111. QString alias() const;
  112. QString shortGuiRemotePathOrAppName() const; // since 2.0 we don't want to show aliases anymore, show the path instead
  113. /**
  114. * short local path to display on the GUI (native separators)
  115. */
  116. QString shortGuiLocalPath() const;
  117. /**
  118. * canonical local folder path, always ends with /
  119. */
  120. QString path() const;
  121. /**
  122. * cleaned canonical folder path, like path() but never ends with a /
  123. *
  124. * Wrapper for QDir::cleanPath(path()) except for "Z:/",
  125. * where it returns "Z:" instead of "Z:/".
  126. */
  127. QString cleanPath() const;
  128. /**
  129. * remote folder path, usually without trailing /, exception "/"
  130. */
  131. QString remotePath() const;
  132. /**
  133. * remote folder path, always with a trailing /
  134. */
  135. QString remotePathTrailingSlash() const;
  136. void setNavigationPaneClsid(const QUuid &clsid) { _definition.navigationPaneClsid = clsid; }
  137. QUuid navigationPaneClsid() const { return _definition.navigationPaneClsid; }
  138. /**
  139. * remote folder path with server url
  140. */
  141. QUrl remoteUrl() const;
  142. /**
  143. * switch sync on or off
  144. */
  145. void setSyncPaused(bool);
  146. bool syncPaused() const;
  147. /**
  148. * Returns true when the folder may sync.
  149. */
  150. bool canSync() const;
  151. void prepareToSync();
  152. /**
  153. * True if the folder is busy and can't initiate
  154. * a synchronization
  155. */
  156. virtual bool isBusy() const;
  157. /** True if the folder is currently synchronizing */
  158. bool isSyncRunning() const;
  159. /**
  160. * return the last sync result with error message and status
  161. */
  162. SyncResult syncResult() const;
  163. /**
  164. * This is called when the sync folder definition is removed. Do cleanups here.
  165. *
  166. * It removes the database, among other things.
  167. *
  168. * The folder is not in a valid state afterwards!
  169. */
  170. virtual void wipeForRemoval();
  171. void onAssociatedAccountRemoved();
  172. void setSyncState(SyncResult::Status state);
  173. void setDirtyNetworkLimits();
  174. /**
  175. * Ignore syncing of hidden files or not. This is defined in the
  176. * folder definition
  177. */
  178. bool ignoreHiddenFiles();
  179. void setIgnoreHiddenFiles(bool ignore);
  180. // Used by the Socket API
  181. SyncJournalDb *journalDb() { return &_journal; }
  182. SyncEngine &syncEngine() { return *_engine; }
  183. Vfs &vfs() { return *_vfs; }
  184. RequestEtagJob *etagJob() { return _requestEtagJob; }
  185. std::chrono::milliseconds msecSinceLastSync() const { return std::chrono::milliseconds(_timeSinceLastSyncDone.elapsed()); }
  186. std::chrono::milliseconds msecLastSyncDuration() const { return _lastSyncDuration; }
  187. int consecutiveFollowUpSyncs() const { return _consecutiveFollowUpSyncs; }
  188. int consecutiveFailingSyncs() const { return _consecutiveFailingSyncs; }
  189. /// Saves the folder data in the account's settings.
  190. void saveToSettings() const;
  191. /// Removes the folder from the account's settings.
  192. void removeFromSettings() const;
  193. /**
  194. * Returns whether a file inside this folder should be excluded.
  195. */
  196. bool isFileExcludedAbsolute(const QString &fullPath) const;
  197. /**
  198. * Returns whether a file inside this folder should be excluded.
  199. */
  200. bool isFileExcludedRelative(const QString &relativePath) const;
  201. /** Calls schedules this folder on the FolderMan after a short delay.
  202. *
  203. * This should be used in situations where a sync should be triggered
  204. * because a local file was modified. Syncs don't upload files that were
  205. * modified too recently, and this delay ensures the modification is
  206. * far enough in the past.
  207. *
  208. * The delay doesn't reset with subsequent calls.
  209. */
  210. void scheduleThisFolderSoon();
  211. /**
  212. * Migration: When this flag is true, this folder will save to
  213. * the backwards-compatible 'Folders' section in the config file.
  214. */
  215. void setSaveBackwardsCompatible(bool save);
  216. /** Used to have placeholders: save in placeholder config section */
  217. void setSaveInFoldersWithPlaceholders() { _saveInFoldersWithPlaceholders = true; }
  218. /**
  219. * Sets up this folder's folderWatcher if possible.
  220. *
  221. * May be called several times.
  222. */
  223. void registerFolderWatcher();
  224. /** virtual files of some kind are enabled
  225. *
  226. * This is independent of whether new files will be virtual. It's possible to have this enabled
  227. * and never have an automatic virtual file. But when it's on, the shell context menu will allow
  228. * users to make existing files virtual.
  229. */
  230. bool virtualFilesEnabled() const;
  231. void setVirtualFilesEnabled(bool enabled);
  232. void setRootPinState(PinState state);
  233. /** Whether user desires a switch that couldn't be executed yet, see member */
  234. bool isVfsOnOffSwitchPending() const { return _vfsOnOffPending; }
  235. void setVfsOnOffSwitchPending(bool pending) { _vfsOnOffPending = pending; }
  236. /** Whether this folder should show selective sync ui */
  237. bool supportsSelectiveSync() const;
  238. QString fileFromLocalPath(const QString &localPath) const;
  239. signals:
  240. void syncStateChange();
  241. void syncStarted();
  242. void syncFinished(const SyncResult &result);
  243. void progressInfo(const ProgressInfo &progress);
  244. void newBigFolderDiscovered(const QString &); // A new folder bigger than the threshold was discovered
  245. void syncPausedChanged(Folder *, bool paused);
  246. void canSyncChanged();
  247. /**
  248. * Fires for each change inside this folder that wasn't caused
  249. * by sync activity.
  250. */
  251. void watchedFileChangedExternally(const QString &path);
  252. public slots:
  253. /**
  254. * terminate the current sync run
  255. */
  256. void slotTerminateSync();
  257. // connected to the corresponding signals in the SyncEngine
  258. void slotAboutToRemoveAllFiles(SyncFileItem::Direction, std::function<void(bool)> callback);
  259. /**
  260. * Starts a sync operation
  261. *
  262. * If the list of changed files is known, it is passed.
  263. */
  264. void startSync(const QStringList &pathList = QStringList());
  265. int slotDiscardDownloadProgress();
  266. int downloadInfoCount();
  267. int slotWipeErrorBlacklist();
  268. int errorBlackListEntryCount();
  269. /**
  270. * Triggered by the folder watcher when a file/dir in this folder
  271. * changes. Needs to check whether this change should trigger a new
  272. * sync run to be scheduled.
  273. */
  274. void slotWatchedPathChanged(const QString &path, ChangeReason reason);
  275. /**
  276. * Mark a virtual file as being requested for download, and start a sync.
  277. *
  278. * "implicit" here means that this download request comes from the user wanting
  279. * to access the file's data. The user did not change the file's pin state.
  280. * If the file is currently OnlineOnly its state will change to Unspecified.
  281. *
  282. * The download request is stored by setting ItemTypeVirtualFileDownload
  283. * in the database. This is necessary since the hydration is not driven by
  284. * the pin state.
  285. *
  286. * relativepath is the folder-relative path to the file (including the extension)
  287. *
  288. * Note, passing directories is not supported. Files only.
  289. */
  290. void implicitlyHydrateFile(const QString &relativepath);
  291. /** Adds the path to the local discovery list
  292. *
  293. * A weaker version of slotNextSyncFullLocalDiscovery() that just
  294. * schedules all parent and child items of the path for local
  295. * discovery.
  296. */
  297. void schedulePathForLocalDiscovery(const QString &relativePath);
  298. /** Ensures that the next sync performs a full local discovery. */
  299. void slotNextSyncFullLocalDiscovery();
  300. private slots:
  301. void slotSyncStarted();
  302. void slotSyncFinished(bool);
  303. /** Adds a error message that's not tied to a specific item.
  304. */
  305. void slotSyncError(const QString &message, ErrorCategory category = ErrorCategory::Normal);
  306. void slotAddErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject = {});
  307. void slotTransmissionProgress(const ProgressInfo &pi);
  308. void slotItemCompleted(const SyncFileItemPtr &);
  309. void slotRunEtagJob();
  310. void etagRetrieved(const QByteArray &, const QDateTime &tp);
  311. void etagRetrievedFromSyncEngine(const QByteArray &, const QDateTime &time);
  312. void slotEmitFinishedDelayed();
  313. void slotNewBigFolderDiscovered(const QString &, bool isExternal);
  314. void slotLogPropagationStart();
  315. /** Adds this folder to the list of scheduled folders in the
  316. * FolderMan.
  317. */
  318. void slotScheduleThisFolder();
  319. /** Adjust sync result based on conflict data from IssuesWidget.
  320. *
  321. * This is pretty awkward, but IssuesWidget just keeps better track
  322. * of conflicts across partial local discovery.
  323. */
  324. void slotFolderConflicts(const QString &folder, const QStringList &conflictPaths);
  325. /** Warn users if they create a file or folder that is selective-sync excluded */
  326. void warnOnNewExcludedItem(const SyncJournalFileRecord &record, const QStringRef &path);
  327. /** Warn users about an unreliable folder watcher */
  328. void slotWatcherUnreliable(const QString &message);
  329. /** Aborts any running sync and blocks it until hydration is finished.
  330. *
  331. * Hydration circumvents the regular SyncEngine and both mustn't be running
  332. * at the same time.
  333. */
  334. void slotHydrationStarts();
  335. /** Unblocks normal sync operation */
  336. void slotHydrationDone();
  337. private:
  338. void connectSyncRoot();
  339. bool reloadExcludes();
  340. void showSyncResultPopup();
  341. void checkLocalPath();
  342. void setSyncOptions();
  343. enum LogStatus {
  344. LogStatusRemove,
  345. LogStatusRename,
  346. LogStatusMove,
  347. LogStatusNew,
  348. LogStatusError,
  349. LogStatusConflict,
  350. LogStatusUpdated,
  351. LogStatusFileLocked
  352. };
  353. void createGuiLog(const QString &filename, LogStatus status, int count,
  354. const QString &renameTarget = QString());
  355. void startVfs();
  356. AccountStatePtr _accountState;
  357. FolderDefinition _definition;
  358. QString _canonicalLocalPath; // As returned with QFileInfo:canonicalFilePath. Always ends with "/"
  359. SyncResult _syncResult;
  360. QScopedPointer<SyncEngine> _engine;
  361. QPointer<RequestEtagJob> _requestEtagJob;
  362. QByteArray _lastEtag;
  363. QElapsedTimer _timeSinceLastSyncDone;
  364. QElapsedTimer _timeSinceLastSyncStart;
  365. QElapsedTimer _timeSinceLastFullLocalDiscovery;
  366. std::chrono::milliseconds _lastSyncDuration;
  367. /// The number of syncs that failed in a row.
  368. /// Reset when a sync is successful.
  369. int _consecutiveFailingSyncs;
  370. /// The number of requested follow-up syncs.
  371. /// Reset when no follow-up is requested.
  372. int _consecutiveFollowUpSyncs;
  373. mutable SyncJournalDb _journal;
  374. QScopedPointer<SyncRunFileLog> _fileLog;
  375. QTimer _scheduleSelfTimer;
  376. /**
  377. * When the same local path is synced to multiple accounts, only one
  378. * of them can be stored in the settings in a way that's compatible
  379. * with old clients that don't support it. This flag marks folders
  380. * that shall be written in a backwards-compatible way, by being set
  381. * on the *first* Folder instance that was configured for each local
  382. * path.
  383. */
  384. bool _saveBackwardsCompatible = false;
  385. /** Whether the folder should be saved in that settings group
  386. *
  387. * If it was read from there it had virtual files enabled at some
  388. * point and might still have db entries or suffix-virtual files even
  389. * if they are disabled right now. This flag ensures folders that
  390. * were in that group once never go back.
  391. */
  392. bool _saveInFoldersWithPlaceholders = false;
  393. /** Whether a vfs mode switch is pending
  394. *
  395. * When the user desires that vfs be switched on/off but it hasn't been
  396. * executed yet (syncs are still running), some options should be hidden,
  397. * disabled or different.
  398. */
  399. bool _vfsOnOffPending = false;
  400. /**
  401. * Watches this folder's local directory for changes.
  402. *
  403. * Created by registerFolderWatcher(), triggers slotWatchedPathChanged()
  404. */
  405. QScopedPointer<FolderWatcher> _folderWatcher;
  406. /**
  407. * Keeps track of locally dirty files so we can skip local discovery sometimes.
  408. */
  409. QScopedPointer<LocalDiscoveryTracker> _localDiscoveryTracker;
  410. /**
  411. * The vfs mode instance (created by plugin) to use. Never null.
  412. */
  413. QSharedPointer<Vfs> _vfs;
  414. };
  415. }
  416. #endif