File indexing completed on 2024-04-28 07:43:58

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
0004     SPDX-FileCopyrightText: 2000-2009 David Faure <faure@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "statjob.h"
0010 
0011 #include "job_p.h"
0012 #include "scheduler.h"
0013 #include "worker_p.h"
0014 #include <KProtocolInfo>
0015 #include <QTimer>
0016 #include <kurlauthorized.h>
0017 
0018 using namespace KIO;
0019 
0020 class KIO::StatJobPrivate : public SimpleJobPrivate
0021 {
0022 public:
0023     inline StatJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs)
0024         : SimpleJobPrivate(url, command, packedArgs)
0025         , m_bSource(true)
0026         , m_details(KIO::StatDefaultDetails)
0027     {
0028     }
0029 
0030     UDSEntry m_statResult;
0031     QUrl m_redirectionURL;
0032     bool m_bSource;
0033     KIO::StatDetails m_details;
0034     void slotStatEntry(const KIO::UDSEntry &entry);
0035     void slotRedirection(const QUrl &url);
0036 
0037     /**
0038      * @internal
0039      * Called by the scheduler when a @p worker gets to
0040      * work on this job.
0041      * @param worker the worker that starts working on this job
0042      */
0043     void start(Worker *worker) override;
0044 
0045     Q_DECLARE_PUBLIC(StatJob)
0046 
0047     static inline StatJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, JobFlags flags)
0048     {
0049         StatJob *job = new StatJob(*new StatJobPrivate(url, command, packedArgs));
0050         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0051         if (!(flags & HideProgressInfo)) {
0052             job->setFinishedNotificationHidden();
0053             KIO::getJobTracker()->registerJob(job);
0054             emitStating(job, url);
0055         }
0056         return job;
0057     }
0058 };
0059 
0060 StatJob::StatJob(StatJobPrivate &dd)
0061     : SimpleJob(dd)
0062 {
0063     setTotalAmount(Items, 1);
0064 }
0065 
0066 StatJob::~StatJob()
0067 {
0068 }
0069 
0070 void StatJob::setSide(StatSide side)
0071 {
0072     d_func()->m_bSource = side == SourceSide;
0073 }
0074 
0075 void StatJob::setDetails(KIO::StatDetails details)
0076 {
0077     d_func()->m_details = details;
0078 }
0079 
0080 const UDSEntry &StatJob::statResult() const
0081 {
0082     return d_func()->m_statResult;
0083 }
0084 
0085 QUrl StatJob::mostLocalUrl() const
0086 {
0087     const QUrl _url = url();
0088 
0089     if (_url.isLocalFile()) {
0090         return _url;
0091     }
0092 
0093     const UDSEntry &udsEntry = d_func()->m_statResult;
0094     const QString path = udsEntry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
0095 
0096     if (path.isEmpty()) { // Return url as-is
0097         return _url;
0098     }
0099 
0100     const QString protoClass = KProtocolInfo::protocolClass(_url.scheme());
0101     if (protoClass != QLatin1String(":local")) { // UDS_LOCAL_PATH was set but wrong Class
0102         qCWarning(KIO_CORE) << "The protocol Class of the url that was being stat'ed" << _url << ", is" << protoClass
0103                             << ", however UDS_LOCAL_PATH was set; if you use UDS_LOCAL_PATH, the protocolClass"
0104                                " should be :local, see KProtocolInfo API docs for more details.";
0105         return _url;
0106     }
0107 
0108     return QUrl::fromLocalFile(path);
0109 }
0110 
0111 void StatJobPrivate::start(Worker *worker)
0112 {
0113     Q_Q(StatJob);
0114     m_outgoingMetaData.insert(QStringLiteral("statSide"), m_bSource ? QStringLiteral("source") : QStringLiteral("dest"));
0115     m_outgoingMetaData.insert(QStringLiteral("details"), QString::number(m_details));
0116 
0117     q->connect(worker, &KIO::WorkerInterface::statEntry, q, [this](const KIO::UDSEntry &entry) {
0118         slotStatEntry(entry);
0119     });
0120     q->connect(worker, &KIO::WorkerInterface::redirection, q, [this](const QUrl &url) {
0121         slotRedirection(url);
0122     });
0123 
0124     SimpleJobPrivate::start(worker);
0125 }
0126 
0127 void StatJobPrivate::slotStatEntry(const KIO::UDSEntry &entry)
0128 {
0129     // qCDebug(KIO_CORE);
0130     m_statResult = entry;
0131 }
0132 
0133 // Worker got a redirection request
0134 void StatJobPrivate::slotRedirection(const QUrl &url)
0135 {
0136     Q_Q(StatJob);
0137     // qCDebug(KIO_CORE) << m_url << "->" << url;
0138     if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), m_url, url)) {
0139         qCWarning(KIO_CORE) << "Redirection from" << m_url << "to" << url << "REJECTED!";
0140         q->setError(ERR_ACCESS_DENIED);
0141         q->setErrorText(url.toDisplayString());
0142         return;
0143     }
0144     m_redirectionURL = url; // We'll remember that when the job finishes
0145     // Tell the user that we haven't finished yet
0146     Q_EMIT q->redirection(q, m_redirectionURL);
0147 }
0148 
0149 void StatJob::slotFinished()
0150 {
0151     Q_D(StatJob);
0152 
0153     if (!d->m_redirectionURL.isEmpty() && d->m_redirectionURL.isValid()) {
0154         // qCDebug(KIO_CORE) << "StatJob: Redirection to " << m_redirectionURL;
0155         if (queryMetaData(QStringLiteral("permanent-redirect")) == QLatin1String("true")) {
0156             Q_EMIT permanentRedirection(this, d->m_url, d->m_redirectionURL);
0157         }
0158 
0159         if (d->m_redirectionHandlingEnabled) {
0160             d->m_packedArgs.truncate(0);
0161             QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
0162             stream << d->m_redirectionURL;
0163 
0164             d->restartAfterRedirection(&d->m_redirectionURL);
0165             return;
0166         }
0167     }
0168 
0169     // Return worker to the scheduler
0170     SimpleJob::slotFinished();
0171 }
0172 
0173 static bool isUrlValid(const QUrl &url)
0174 {
0175     if (!url.isValid()) {
0176         qCWarning(KIO_CORE) << "Invalid url:" << url << ", cancelling job.";
0177         return false;
0178     }
0179 
0180     if (url.isLocalFile()) {
0181         qCWarning(KIO_CORE) << "Url" << url << "already represents a local file, cancelling job.";
0182         return false;
0183     }
0184 
0185     if (KProtocolInfo::protocolClass(url.scheme()) != QLatin1String(":local")) {
0186         qCWarning(KIO_CORE) << "Protocol Class of url" << url << ", isn't ':local', cancelling job.";
0187         return false;
0188     }
0189 
0190     return true;
0191 }
0192 
0193 StatJob *KIO::mostLocalUrl(const QUrl &url, JobFlags flags)
0194 {
0195     StatJob *job = stat(url, StatJob::SourceSide, KIO::StatDefaultDetails, flags);
0196     if (!isUrlValid(url)) {
0197         QTimer::singleShot(0, job, &StatJob::slotFinished);
0198         Scheduler::cancelJob(job); // deletes the worker if not 0
0199     }
0200     return job;
0201 }
0202 
0203 StatJob *KIO::stat(const QUrl &url, JobFlags flags)
0204 {
0205     // Assume SourceSide. Gets are more common than puts.
0206     return stat(url, StatJob::SourceSide, KIO::StatDefaultDetails, flags);
0207 }
0208 
0209 StatJob *KIO::stat(const QUrl &url, KIO::StatJob::StatSide side, KIO::StatDetails details, JobFlags flags)
0210 {
0211     // qCDebug(KIO_CORE) << "stat" << url;
0212     KIO_ARGS << url;
0213     StatJob *job = StatJobPrivate::newJob(url, CMD_STAT, packedArgs, flags);
0214     job->setSide(side);
0215     job->setDetails(details);
0216     return job;
0217 }
0218 
0219 #include "moc_statjob.cpp"