1 /*
2 * Copyright (C) by Christian Kamm <mail@ckamm.de>
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 #include "vfs_suffix.h"
16
17 #include <QFile>
18
19 #include "syncfileitem.h"
20 #include "filesystem.h"
21 #include "common/syncjournaldb.h"
22
23 namespace OCC {
24
VfsSuffix(QObject * parent)25 VfsSuffix::VfsSuffix(QObject *parent)
26 : Vfs(parent)
27 {
28 }
29
~VfsSuffix()30 VfsSuffix::~VfsSuffix()
31 {
32 }
33
mode() const34 Vfs::Mode VfsSuffix::mode() const
35 {
36 return WithSuffix;
37 }
38
fileSuffix() const39 QString VfsSuffix::fileSuffix() const
40 {
41 return QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX);
42 }
43
startImpl(const VfsSetupParams & params)44 void VfsSuffix::startImpl(const VfsSetupParams ¶ms)
45 {
46 // It is unsafe for the database to contain any ".owncloud" file entries
47 // that are not marked as a virtual file. These could be real .owncloud
48 // files that were synced before vfs was enabled.
49 QByteArrayList toWipe;
50 params.journal->getFilesBelowPath("", [&toWipe](const SyncJournalFileRecord &rec) {
51 if (!rec.isVirtualFile() && rec._path.endsWith(APPLICATION_DOTVIRTUALFILE_SUFFIX))
52 toWipe.append(rec._path);
53 });
54 for (const auto &path : toWipe)
55 params.journal->deleteFileRecord(QString::fromUtf8(path));
56 }
57
stop()58 void VfsSuffix::stop()
59 {
60 }
61
unregisterFolder()62 void VfsSuffix::unregisterFolder()
63 {
64 }
65
isHydrating() const66 bool VfsSuffix::isHydrating() const
67 {
68 return false;
69 }
70
updateMetadata(const QString & filePath,time_t modtime,qint64,const QByteArray &)71 Result<void, QString> VfsSuffix::updateMetadata(const QString &filePath, time_t modtime, qint64, const QByteArray &)
72 {
73 FileSystem::setModTime(filePath, modtime);
74 return {};
75 }
76
createPlaceholder(const SyncFileItem & item)77 Result<void, QString> VfsSuffix::createPlaceholder(const SyncFileItem &item)
78 {
79 // The concrete shape of the placeholder is also used in isDehydratedPlaceholder() below
80 QString fn = _setupParams.filesystemPath + item._file;
81 if (!fn.endsWith(fileSuffix())) {
82 OC_ASSERT_X(false, "vfs file isn't ending with suffix");
83 return QStringLiteral("vfs file isn't ending with suffix");
84 }
85
86 QFile file(fn);
87 if (file.exists() && file.size() > 1
88 && !FileSystem::verifyFileUnchanged(fn, item._size, item._modtime)) {
89 return QStringLiteral("Cannot create a placeholder because a file with the placeholder name already exist");
90 }
91
92 if (!file.open(QFile::ReadWrite | QFile::Truncate))
93 return file.errorString();
94
95 file.write(" ");
96 file.close();
97 FileSystem::setModTime(fn, item._modtime);
98 return {};
99 }
100
dehydratePlaceholder(const SyncFileItem & item)101 Result<void, QString> VfsSuffix::dehydratePlaceholder(const SyncFileItem &item)
102 {
103 SyncFileItem virtualItem(item);
104 virtualItem._file = item._renameTarget;
105 auto r = createPlaceholder(virtualItem);
106 if (!r)
107 return r;
108
109 if (item._file != item._renameTarget) { // can be the same when renaming foo -> foo.owncloud to dehydrate
110 QFile::remove(_setupParams.filesystemPath + item._file);
111 }
112
113 // Move the item's pin state
114 auto pin = _setupParams.journal->internalPinStates().rawForPath(item._file.toUtf8());
115 if (pin && *pin != PinState::Inherited) {
116 setPinState(item._renameTarget, *pin);
117 setPinState(item._file, PinState::Inherited);
118 }
119
120 // Ensure the pin state isn't contradictory
121 pin = pinState(item._renameTarget);
122 if (pin && *pin == PinState::AlwaysLocal)
123 setPinState(item._renameTarget, PinState::Unspecified);
124 return {};
125 }
126
convertToPlaceholder(const QString &,const SyncFileItem &,const QString &)127 Result<void, QString> VfsSuffix::convertToPlaceholder(const QString &, const SyncFileItem &, const QString &)
128 {
129 // Nothing necessary
130 return {};
131 }
132
isDehydratedPlaceholder(const QString & filePath)133 bool VfsSuffix::isDehydratedPlaceholder(const QString &filePath)
134 {
135 if (!filePath.endsWith(fileSuffix()))
136 return false;
137 QFileInfo fi(filePath);
138 return fi.exists() && fi.size() == 1;
139 }
140
statTypeVirtualFile(csync_file_stat_t * stat,void *)141 bool VfsSuffix::statTypeVirtualFile(csync_file_stat_t *stat, void *)
142 {
143 if (stat->path.endsWith(fileSuffix().toUtf8())) {
144 stat->type = ItemTypeVirtualFile;
145 return true;
146 }
147 return false;
148 }
149
availability(const QString & folderPath)150 Vfs::AvailabilityResult VfsSuffix::availability(const QString &folderPath)
151 {
152 return availabilityInDb(folderPath);
153 }
154
155 } // namespace OCC
156