Warning, file /utilities/kio-stash/src/kioworker/filestash.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 * Copyright (C) 2016 by Arnav Dhamija <arnav.dhamija@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the * 0016 * Free Software Foundation, Inc., * 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 0018 ***************************************************************************/ 0019 0020 #include "filestash.h" 0021 0022 #include <QCoreApplication> 0023 #include <QDBusConnection> 0024 #include <QDBusMessage> 0025 #include <QDBusMetaType> 0026 #include <QDBusReply> 0027 #include <QDebug> 0028 #include <QDir> 0029 #include <QFile> 0030 #include <QMetaType> 0031 #include <QMimeDatabase> 0032 #include <QMimeType> 0033 #include <QUrl> 0034 0035 #include <KConfigGroup> 0036 #include <KFileItem> 0037 #include <KIO/Job> 0038 #include <KIO/StatJob> 0039 #include <KLocalizedString> 0040 0041 class KIOPluginForMetaData : public QObject 0042 { 0043 Q_OBJECT 0044 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.filestash" FILE "filestash.json") 0045 }; 0046 0047 extern "C" { 0048 int Q_DECL_EXPORT kdemain(int argc, char **argv) 0049 { 0050 QCoreApplication app(argc, argv); 0051 FileStash worker(argv[2], argv[3]); 0052 worker.dispatchLoop(); 0053 return 0; 0054 } 0055 } 0056 0057 FileStash::FileStash(const QByteArray &pool, const QByteArray &app, const QString &daemonService, const QString &daemonPath) 0058 : KIO::ForwardingWorkerBase("stash", pool, app) 0059 , m_daemonService(daemonService) 0060 , m_daemonPath(daemonPath) 0061 { 0062 } 0063 0064 FileStash::~FileStash() 0065 { 0066 } 0067 0068 bool FileStash::rewriteUrl(const QUrl &url, QUrl &newUrl) 0069 { 0070 if (url.scheme() != "file") { 0071 newUrl.setScheme("file"); 0072 newUrl.setPath(url.path()); 0073 } else { 0074 newUrl = url; 0075 } 0076 return true; 0077 } 0078 0079 void FileStash::createTopLevelDirEntry(KIO::UDSEntry &entry) 0080 { 0081 entry.clear(); 0082 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral(".")); 0083 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, 0040000); 0084 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); 0085 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory")); 0086 } 0087 0088 QStringList FileStash::setFileList(const QUrl &url) 0089 { 0090 QDBusMessage msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "fileList"); 0091 msg << url.path(); 0092 QDBusReply<QStringList> received = QDBusConnection::sessionBus().call(msg); 0093 return received.value(); 0094 } 0095 0096 QString FileStash::setFileInfo(const QUrl &url) 0097 { 0098 QDBusMessage msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "fileInfo"); 0099 msg << url.path(); 0100 QDBusReply<QString> received = QDBusConnection::sessionBus().call(msg); 0101 return received.value(); 0102 } 0103 0104 KIO::WorkerResult FileStash::stat(const QUrl &url) 0105 { 0106 KIO::UDSEntry entry; 0107 if (isRoot(url.path())) { 0108 createTopLevelDirEntry(entry); 0109 } else { 0110 QString fileInfo = setFileInfo(url); 0111 FileStash::dirList item = createDirListItem(fileInfo); 0112 if (!createUDSEntry(entry, item)) { 0113 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); 0114 } 0115 } 0116 statEntry(entry); 0117 return KIO::WorkerResult::pass(); 0118 } 0119 0120 bool FileStash::statUrl(const QUrl &url, KIO::UDSEntry &entry) 0121 { 0122 KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); 0123 bool ok = statJob->exec(); 0124 if (ok) { 0125 entry = statJob->statResult(); 0126 } 0127 return ok; 0128 } 0129 0130 bool FileStash::createUDSEntry(KIO::UDSEntry &entry, const FileStash::dirList &fileItem) 0131 { 0132 QMimeType fileMimetype; 0133 QMimeDatabase mimeDatabase; 0134 QString stringFilePath = fileItem.filePath; 0135 0136 switch (fileItem.type) { 0137 case NodeType::DirectoryNode: 0138 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, 0040000); 0139 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QString("inode/directory")); 0140 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QUrl(stringFilePath).fileName()); 0141 entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, QUrl(stringFilePath).fileName()); 0142 break; 0143 case NodeType::InvalidNode: 0144 return false; 0145 default: 0146 QByteArray physicalPath_c = QFile::encodeName(fileItem.source); 0147 QT_STATBUF buff; 0148 QT_LSTAT(physicalPath_c, &buff); 0149 mode_t access = buff.st_mode & 07777; 0150 0151 QFileInfo entryInfo; 0152 entryInfo = QFileInfo(fileItem.source); 0153 fileMimetype = mimeDatabase.mimeTypeForFile(fileItem.source); 0154 entry.fastInsert(KIO::UDSEntry::UDS_TARGET_URL, QUrl::fromLocalFile(fileItem.source).toString()); 0155 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, fileMimetype.name()); 0156 entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, QUrl(stringFilePath).fileName()); 0157 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QUrl(stringFilePath).fileName()); 0158 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, access); 0159 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, entryInfo.size()); 0160 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime); 0161 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime); 0162 0163 if (fileItem.type == NodeType::FileNode) { 0164 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, 0100000); 0165 } else if (fileItem.type == NodeType::SymlinkNode) { 0166 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, 0120000); 0167 } else { 0168 return false; 0169 } 0170 } 0171 return true; 0172 } 0173 0174 FileStash::dirList FileStash::createDirListItem(const QString &fileInfo) 0175 { 0176 QStringList strings = fileInfo.split("::", Qt::KeepEmptyParts); 0177 FileStash::dirList item; 0178 if (strings.at(0) == "dir") { 0179 item.type = FileStash::NodeType::DirectoryNode; 0180 } else if (strings.at(0) == "file") { 0181 item.type = FileStash::NodeType::FileNode; 0182 } else if (strings.at(0) == "symlink") { 0183 item.type = FileStash::NodeType::SymlinkNode; 0184 } else if (strings.at(0) == "invalid") { 0185 item.type = FileStash::NodeType::InvalidNode; 0186 } 0187 item.filePath = strings.at(1); 0188 item.source = strings.at(2); 0189 return item; 0190 } 0191 0192 KIO::WorkerResult FileStash::listDir(const QUrl &url) 0193 { 0194 QStringList fileList = setFileList(url); 0195 if (!fileList.size()) { 0196 return KIO::WorkerResult::pass(); 0197 } 0198 FileStash::dirList item; 0199 KIO::UDSEntry entry; 0200 if (isRoot(url.path())) { 0201 createTopLevelDirEntry(entry); 0202 listEntry(entry); 0203 } 0204 if (fileList.at(0) == "error::error::InvalidNode") { 0205 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("The file either does not exist or has not been stashed yet.")); 0206 } 0207 for (auto it = fileList.begin(); it != fileList.end(); ++it) { 0208 entry.clear(); 0209 item = createDirListItem(*it); 0210 if (createUDSEntry(entry, item)) { 0211 listEntry(entry); 0212 } else { 0213 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("The UDS Entry could not be created.")); 0214 } 0215 } 0216 return KIO::WorkerResult::pass(); 0217 } 0218 0219 KIO::WorkerResult FileStash::mkdir(const QUrl &url, int permissions) 0220 { 0221 Q_UNUSED(permissions) 0222 0223 QDBusMessage replyMessage; 0224 QDBusMessage msg; 0225 msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "addPath"); 0226 QString destinationPath = url.path(); 0227 msg << "" << destinationPath << NodeType::DirectoryNode; 0228 replyMessage = QDBusConnection::sessionBus().call(msg); 0229 if (replyMessage.type() == QDBusMessage::ErrorMessage) { 0230 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not create a directory")); 0231 } 0232 return KIO::WorkerResult::pass(); 0233 } 0234 0235 bool FileStash::copyFileToStash(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 0236 { 0237 Q_UNUSED(flags) 0238 0239 NodeType fileType; 0240 QFileInfo fileInfo = QFileInfo(src.path()); 0241 if (fileInfo.isFile()) { 0242 fileType = NodeType::FileNode; 0243 } else if (fileInfo.isSymLink()) { 0244 fileType = NodeType::SymlinkNode; 0245 } else if (fileInfo.isDir()) { // if I'm not wrong, this can never happen, but we should handle it anyway 0246 fileType = NodeType::DirectoryNode; 0247 } else { 0248 return false; 0249 } 0250 0251 QDBusMessage replyMessage; 0252 QDBusMessage msg; 0253 msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "addPath"); 0254 QString destinationPath = dest.path(); 0255 0256 msg << src.path() << destinationPath << (int)fileType; 0257 replyMessage = QDBusConnection::sessionBus().call(msg); 0258 if (replyMessage.type() != QDBusMessage::ErrorMessage) { 0259 return true; 0260 } else { 0261 return false; 0262 } 0263 } 0264 0265 bool FileStash::copyStashToFile(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 0266 { 0267 const QString destInfo = setFileInfo(src); 0268 const FileStash::dirList fileItem = createDirListItem(destInfo); 0269 0270 if (fileItem.type != NodeType::DirectoryNode) { 0271 QByteArray physicalPath_c = QFile::encodeName(fileItem.source); 0272 QT_STATBUF buff; 0273 QT_LSTAT(physicalPath_c, &buff); 0274 mode_t access = buff.st_mode & 07777; 0275 const auto result = KIO::ForwardingWorkerBase::copy(QUrl::fromLocalFile(fileItem.source), dest, access, flags); 0276 return result.success(); 0277 } 0278 return false; 0279 } 0280 0281 bool FileStash::copyStashToStash(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 0282 { 0283 Q_UNUSED(flags) 0284 0285 KIO::UDSEntry entry; 0286 0287 statUrl(src, entry); 0288 KFileItem fileItem(entry, src); 0289 0290 const dirList item = createDirListItem(setFileInfo(src)); 0291 NodeType fileType; 0292 if (fileItem.isFile()) { 0293 fileType = NodeType::FileNode; 0294 } else if (fileItem.isLink()) { 0295 fileType = NodeType::SymlinkNode; 0296 } else if (fileItem.isDir()) { 0297 fileType = NodeType::DirectoryNode; 0298 } else { 0299 return false; 0300 } 0301 0302 QDBusMessage replyMessage; 0303 QDBusMessage msg; 0304 msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "addPath"); 0305 msg << item.source << dest.path() << fileType; 0306 replyMessage = QDBusConnection::sessionBus().call(msg); 0307 if (replyMessage.type() != QDBusMessage::ErrorMessage) { 0308 return true; 0309 } else { 0310 return false; 0311 } 0312 } 0313 0314 KIO::WorkerResult FileStash::copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags) 0315 { 0316 KIO::UDSEntry entry; 0317 statUrl(src, entry); 0318 KFileItem item(entry, src); 0319 QUrl newDestPath; 0320 newDestPath = QUrl(dest.adjusted(QUrl::RemoveFilename).toString() + item.name()); 0321 0322 if (src.scheme() != "stash" && dest.scheme() == "stash") { 0323 if (copyFileToStash(src, newDestPath, flags)) { 0324 return KIO::WorkerResult::pass(); 0325 } 0326 0327 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not copy.")); 0328 } 0329 if (src.scheme() == "stash" && dest.scheme() != "stash") { 0330 if (copyStashToFile(src, newDestPath, flags)) { 0331 return KIO::WorkerResult::pass(); 0332 } 0333 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not copy.")); 0334 } 0335 if (src.scheme() == "stash" && dest.scheme() == "stash") { 0336 if (copyStashToStash(src, newDestPath, flags)) { 0337 return KIO::WorkerResult::pass(); 0338 } 0339 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not copy.")); 0340 } 0341 if (dest.scheme() == "mtp") { 0342 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Copying to mtp workers is still under development!")); 0343 } 0344 return KIO::ForwardingWorkerBase::copy(item.targetUrl(), newDestPath, permissions, flags); 0345 } 0346 0347 KIO::WorkerResult FileStash::del(const QUrl &url, bool isFile) 0348 { 0349 Q_UNUSED(isFile) 0350 0351 if (deletePath(url)) { 0352 return KIO::WorkerResult::pass(); 0353 } 0354 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, QString("Could not reach the stash daemon")); 0355 } 0356 0357 bool FileStash::deletePath(const QUrl &url) 0358 { 0359 NodeType fileType; 0360 0361 QDBusMessage replyMessage; 0362 QDBusMessage msg; 0363 msg = QDBusMessage::createMethodCall(m_daemonService, m_daemonPath, "", "removePath"); 0364 0365 if (isRoot(url.adjusted(QUrl::RemoveFilename).toString())) { 0366 msg << url.fileName(); 0367 } else { 0368 msg << url.path(); 0369 } 0370 0371 replyMessage = QDBusConnection::sessionBus().call(msg); 0372 if (replyMessage.type() != QDBusMessage::ErrorMessage) { 0373 return true; 0374 } else { 0375 return false; 0376 } 0377 } 0378 0379 KIO::WorkerResult FileStash::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 0380 { 0381 if (src.scheme() == "stash" && dest.scheme() == "stash") { 0382 if (copyStashToStash(src, dest, flags)) { 0383 if (deletePath(src)) { 0384 return KIO::WorkerResult::pass(); 0385 } 0386 } 0387 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not rename.")); 0388 } 0389 if (src.scheme() == "file" && dest.scheme() == "stash") { 0390 if (copyFileToStash(src, dest, flags)) { 0391 return KIO::WorkerResult::pass(); 0392 } 0393 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not rename.")); 0394 } 0395 if (src.scheme() == "stash" && dest.scheme() == "file") { 0396 if (copyStashToFile(src, dest, flags)) { 0397 if (deletePath(src)) { 0398 return KIO::WorkerResult::pass(); 0399 } 0400 } 0401 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Could not rename.")); 0402 } 0403 return KIO::WorkerResult::fail(); 0404 } 0405 0406 bool FileStash::isRoot(const QString &string) 0407 { 0408 if (string.isEmpty() || string == "/") { 0409 return true; 0410 } 0411 return false; 0412 } 0413 0414 #include "filestash.moc"