File indexing completed on 2024-04-14 03:53:00

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 "mkpathjob.h"
0010 #include "../utils_p.h"
0011 #include "job_p.h"
0012 #include "mkdirjob.h"
0013 
0014 #include <QFileInfo>
0015 #include <QTimer>
0016 
0017 using namespace KIO;
0018 
0019 class KIO::MkpathJobPrivate : public KIO::JobPrivate
0020 {
0021 public:
0022     MkpathJobPrivate(const QUrl &url, const QUrl &baseUrl, JobFlags flags)
0023         : JobPrivate()
0024         , m_url(url)
0025         , m_pathComponents(url.path().split(QLatin1Char('/'), Qt::SkipEmptyParts))
0026         , m_pathIterator()
0027         , m_flags(flags)
0028     {
0029         const QStringList basePathComponents = baseUrl.path().split(QLatin1Char('/'), Qt::SkipEmptyParts);
0030 
0031 #ifdef Q_OS_WIN
0032         const QString startPath;
0033 #else
0034         const QString startPath = QLatin1String("/");
0035 #endif
0036         m_url.setPath(startPath);
0037         int i = 0;
0038         for (; i < basePathComponents.count() && i < m_pathComponents.count(); ++i) {
0039             const QString pathComponent = m_pathComponents.at(i);
0040             if (pathComponent == basePathComponents.at(i)) {
0041                 m_url.setPath(Utils::concatPaths(m_url.path(), pathComponent));
0042             } else {
0043                 break;
0044             }
0045         }
0046         if (i > 0) {
0047             m_pathComponents.erase(m_pathComponents.begin(), m_pathComponents.begin() + i);
0048         }
0049 
0050         // fast path for local files using QFileInfo::isDir
0051         if (m_url.isLocalFile()) {
0052             i = 0;
0053             for (; i < m_pathComponents.count(); ++i) {
0054                 const QString localFile = m_url.toLocalFile();
0055                 QString testDir;
0056                 if (localFile == startPath) {
0057                     testDir = localFile + m_pathComponents.at(i);
0058                 } else {
0059                     testDir = localFile + QLatin1Char('/') + m_pathComponents.at(i);
0060                 }
0061                 if (QFileInfo(testDir).isDir()) {
0062                     m_url.setPath(testDir);
0063                 } else {
0064                     break;
0065                 }
0066             }
0067             if (i > 0) {
0068                 m_pathComponents.erase(m_pathComponents.begin(), m_pathComponents.begin() + i);
0069             }
0070         }
0071 
0072         m_pathIterator = m_pathComponents.constBegin();
0073     }
0074 
0075     QUrl m_url;
0076     QUrl m_baseUrl;
0077     QStringList m_pathComponents;
0078     QStringList::const_iterator m_pathIterator;
0079     const JobFlags m_flags;
0080     Q_DECLARE_PUBLIC(MkpathJob)
0081 
0082     void slotStart();
0083 
0084     static inline MkpathJob *newJob(const QUrl &url, const QUrl &baseUrl, JobFlags flags)
0085     {
0086         MkpathJob *job = new MkpathJob(*new MkpathJobPrivate(url, baseUrl, flags));
0087         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0088         if (!(flags & HideProgressInfo)) {
0089             KIO::getJobTracker()->registerJob(job);
0090         }
0091         if (!(flags & NoPrivilegeExecution)) {
0092             job->d_func()->m_privilegeExecutionEnabled = true;
0093             job->d_func()->m_operationType = MkDir;
0094         }
0095         return job;
0096     }
0097 };
0098 
0099 MkpathJob::MkpathJob(MkpathJobPrivate &dd)
0100     : Job(dd)
0101 {
0102     Q_D(MkpathJob);
0103     QTimer::singleShot(0, this, [d]() {
0104         d->slotStart();
0105     });
0106 }
0107 
0108 MkpathJob::~MkpathJob()
0109 {
0110 }
0111 
0112 void MkpathJobPrivate::slotStart()
0113 {
0114     Q_Q(MkpathJob);
0115 
0116     if (m_pathIterator == m_pathComponents.constBegin()) { // first time: emit total
0117         q->setTotalAmount(KJob::Directories, m_pathComponents.count());
0118     }
0119 
0120     if (m_pathIterator != m_pathComponents.constEnd()) {
0121         m_url.setPath(Utils::concatPaths(m_url.path(), *m_pathIterator));
0122         KIO::Job *job = KIO::mkdir(m_url);
0123         job->setParentJob(q);
0124         q->addSubjob(job);
0125         q->setProcessedAmount(KJob::Directories, q->processedAmount(KJob::Directories) + 1);
0126     } else {
0127         q->emitResult();
0128     }
0129 }
0130 
0131 void MkpathJob::slotResult(KJob *job)
0132 {
0133     Q_D(MkpathJob);
0134     if (job->error() && job->error() != KIO::ERR_DIR_ALREADY_EXIST) {
0135         KIO::Job::slotResult(job); // will set the error and emit result(this)
0136         return;
0137     }
0138     removeSubjob(job);
0139 
0140     Q_EMIT directoryCreated(d->m_url);
0141 
0142     // Move on to next one
0143     ++d->m_pathIterator;
0144     emitPercent(d->m_pathIterator - d->m_pathComponents.constBegin(), d->m_pathComponents.count());
0145     d->slotStart();
0146 }
0147 
0148 MkpathJob *KIO::mkpath(const QUrl &url, const QUrl &baseUrl, KIO::JobFlags flags)
0149 {
0150     return MkpathJobPrivate::newJob(url, baseUrl, flags);
0151 }
0152 
0153 #include "moc_mkpathjob.cpp"