1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org> |
4 | SPDX-FileCopyrightText: 2000-2009 David Faure <faure@kde.org> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "mkpathjob.h" |
10 | #include "../utils_p.h" |
11 | #include "job_p.h" |
12 | #include "mkdirjob.h" |
13 | |
14 | #include <QFileInfo> |
15 | #include <QTimer> |
16 | |
17 | using namespace KIO; |
18 | |
19 | class KIO::MkpathJobPrivate : public KIO::JobPrivate |
20 | { |
21 | public: |
22 | MkpathJobPrivate(const QUrl &url, const QUrl &baseUrl, JobFlags flags) |
23 | : JobPrivate() |
24 | , m_url(url) |
25 | , m_pathComponents(url.path().split(sep: QLatin1Char('/'), behavior: Qt::SkipEmptyParts)) |
26 | , m_pathIterator() |
27 | , m_flags(flags) |
28 | { |
29 | const QStringList basePathComponents = baseUrl.path().split(sep: QLatin1Char('/'), behavior: Qt::SkipEmptyParts); |
30 | |
31 | #ifdef Q_OS_WIN |
32 | const QString startPath; |
33 | #else |
34 | const QString startPath = QLatin1String("/" ); |
35 | #endif |
36 | m_url.setPath(path: startPath); |
37 | int i = 0; |
38 | for (; i < basePathComponents.count() && i < m_pathComponents.count(); ++i) { |
39 | const QString pathComponent = m_pathComponents.at(i); |
40 | if (pathComponent == basePathComponents.at(i)) { |
41 | m_url.setPath(path: Utils::concatPaths(path1: m_url.path(), path2: pathComponent)); |
42 | } else { |
43 | break; |
44 | } |
45 | } |
46 | if (i > 0) { |
47 | m_pathComponents.erase(abegin: m_pathComponents.begin(), aend: m_pathComponents.begin() + i); |
48 | } |
49 | |
50 | // fast path for local files using QFileInfo::isDir |
51 | if (m_url.isLocalFile()) { |
52 | i = 0; |
53 | for (; i < m_pathComponents.count(); ++i) { |
54 | const QString localFile = m_url.toLocalFile(); |
55 | QString testDir; |
56 | if (localFile == startPath) { |
57 | testDir = localFile + m_pathComponents.at(i); |
58 | } else { |
59 | testDir = localFile + QLatin1Char('/') + m_pathComponents.at(i); |
60 | } |
61 | if (QFileInfo(testDir).isDir()) { |
62 | m_url.setPath(path: testDir); |
63 | } else { |
64 | break; |
65 | } |
66 | } |
67 | if (i > 0) { |
68 | m_pathComponents.erase(abegin: m_pathComponents.begin(), aend: m_pathComponents.begin() + i); |
69 | } |
70 | } |
71 | |
72 | m_pathIterator = m_pathComponents.constBegin(); |
73 | } |
74 | |
75 | QUrl m_url; |
76 | QUrl m_baseUrl; |
77 | QStringList m_pathComponents; |
78 | QStringList::const_iterator m_pathIterator; |
79 | const JobFlags m_flags; |
80 | Q_DECLARE_PUBLIC(MkpathJob) |
81 | |
82 | void slotStart(); |
83 | |
84 | static inline MkpathJob *newJob(const QUrl &url, const QUrl &baseUrl, JobFlags flags) |
85 | { |
86 | MkpathJob *job = new MkpathJob(*new MkpathJobPrivate(url, baseUrl, flags)); |
87 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
88 | if (!(flags & HideProgressInfo)) { |
89 | KIO::getJobTracker()->registerJob(job); |
90 | } |
91 | if (!(flags & NoPrivilegeExecution)) { |
92 | job->d_func()->m_privilegeExecutionEnabled = true; |
93 | job->d_func()->m_operationType = MkDir; |
94 | } |
95 | return job; |
96 | } |
97 | }; |
98 | |
99 | MkpathJob::MkpathJob(MkpathJobPrivate &dd) |
100 | : Job(dd) |
101 | { |
102 | Q_D(MkpathJob); |
103 | QTimer::singleShot(interval: 0, receiver: this, slot: [d]() { |
104 | d->slotStart(); |
105 | }); |
106 | } |
107 | |
108 | MkpathJob::~MkpathJob() |
109 | { |
110 | } |
111 | |
112 | void MkpathJobPrivate::slotStart() |
113 | { |
114 | Q_Q(MkpathJob); |
115 | |
116 | if (m_pathIterator == m_pathComponents.constBegin()) { // first time: emit total |
117 | q->setTotalAmount(unit: KJob::Directories, amount: m_pathComponents.count()); |
118 | } |
119 | |
120 | if (m_pathIterator != m_pathComponents.constEnd()) { |
121 | m_url.setPath(path: Utils::concatPaths(path1: m_url.path(), path2: *m_pathIterator)); |
122 | KIO::Job *job = KIO::mkdir(url: m_url); |
123 | job->setParentJob(q); |
124 | q->addSubjob(job); |
125 | q->setProcessedAmount(unit: KJob::Directories, amount: q->processedAmount(unit: KJob::Directories) + 1); |
126 | } else { |
127 | q->emitResult(); |
128 | } |
129 | } |
130 | |
131 | void MkpathJob::slotResult(KJob *job) |
132 | { |
133 | Q_D(MkpathJob); |
134 | if (job->error() && job->error() != KIO::ERR_DIR_ALREADY_EXIST) { |
135 | KIO::Job::slotResult(job); // will set the error and emit result(this) |
136 | return; |
137 | } |
138 | removeSubjob(job); |
139 | |
140 | Q_EMIT directoryCreated(url: d->m_url); |
141 | |
142 | // Move on to next one |
143 | ++d->m_pathIterator; |
144 | emitPercent(processedAmount: d->m_pathIterator - d->m_pathComponents.constBegin(), totalAmount: d->m_pathComponents.count()); |
145 | d->slotStart(); |
146 | } |
147 | |
148 | MkpathJob *KIO::mkpath(const QUrl &url, const QUrl &baseUrl, KIO::JobFlags flags) |
149 | { |
150 | return MkpathJobPrivate::newJob(url, baseUrl, flags); |
151 | } |
152 | |
153 | #include "moc_mkpathjob.cpp" |
154 | |