Changeset View
Changeset View
Standalone View
Standalone View
src/core/chmodjob.cpp
Show All 18 Lines | 1 | /* This file is part of the KDE libraries | |||
---|---|---|---|---|---|
19 | Boston, MA 02110-1301, USA. | 19 | Boston, MA 02110-1301, USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "chmodjob.h" | 22 | #include "chmodjob.h" | ||
23 | #include "../pathhelpers_p.h" | 23 | #include "../pathhelpers_p.h" | ||
24 | 24 | | |||
25 | #include <KLocalizedString> | 25 | #include <KLocalizedString> | ||
26 | #include <KUser> | 26 | #include <KUser> | ||
27 | #include <QLinkedList> | | |||
28 | #include <QDebug> | 27 | #include <QDebug> | ||
29 | 28 | | |||
30 | 29 | | |||
31 | #include "listjob.h" | 30 | #include "listjob.h" | ||
32 | #include "job_p.h" | 31 | #include "job_p.h" | ||
33 | #include "jobuidelegatefactory.h" | 32 | #include "jobuidelegatefactory.h" | ||
34 | #include "kioglobal_p.h" | 33 | #include "kioglobal_p.h" | ||
35 | 34 | | |||
35 | #include <stack> | ||||
36 | | ||||
36 | namespace KIO | 37 | namespace KIO | ||
37 | { | 38 | { | ||
38 | 39 | | |||
39 | struct ChmodInfo { | 40 | struct ChmodInfo { | ||
40 | QUrl url; | 41 | QUrl url; | ||
41 | int permissions; | 42 | int permissions; | ||
42 | }; | 43 | }; | ||
43 | 44 | | |||
Show All 21 Lines | 52 | public: | |||
65 | ChmodJobState state; | 66 | ChmodJobState state; | ||
66 | int m_permissions; | 67 | int m_permissions; | ||
67 | int m_mask; | 68 | int m_mask; | ||
68 | KUserId m_newOwner; | 69 | KUserId m_newOwner; | ||
69 | KGroupId m_newGroup; | 70 | KGroupId m_newGroup; | ||
70 | bool m_recursive; | 71 | bool m_recursive; | ||
71 | bool m_bAutoSkipFiles; | 72 | bool m_bAutoSkipFiles; | ||
72 | KFileItemList m_lstItems; | 73 | KFileItemList m_lstItems; | ||
73 | QLinkedList<ChmodInfo> m_infos; // linkedlist since we keep removing the first item | 74 | std::stack<ChmodInfo> m_infos; | ||
74 | 75 | | |||
75 | void _k_chmodNextFile(); | 76 | void _k_chmodNextFile(); | ||
76 | void _k_slotEntries(KIO::Job *, const KIO::UDSEntryList &); | 77 | void _k_slotEntries(KIO::Job *, const KIO::UDSEntryList &); | ||
77 | void _k_processList(); | 78 | void _k_processList(); | ||
78 | 79 | | |||
79 | Q_DECLARE_PUBLIC(ChmodJob) | 80 | Q_DECLARE_PUBLIC(ChmodJob) | ||
80 | 81 | | |||
81 | static inline ChmodJob *newJob(const KFileItemList &lstItems, int permissions, int mask, | 82 | static inline ChmodJob *newJob(const KFileItemList &lstItems, int permissions, int mask, | ||
Show All 24 Lines | |||||
106 | } | 107 | } | ||
107 | 108 | | |||
108 | ChmodJob::~ChmodJob() | 109 | ChmodJob::~ChmodJob() | ||
109 | { | 110 | { | ||
110 | } | 111 | } | ||
111 | 112 | | |||
112 | void ChmodJobPrivate::_k_processList() | 113 | void ChmodJobPrivate::_k_processList() | ||
113 | { | 114 | { | ||
114 | Q_Q(ChmodJob); | 115 | Q_Q(ChmodJob); | ||
bruns: For efficiency, probably do a
`m_infos.reserve(m_infos.capacity() + m_lstItems.size());`
here. | |||||
nicolasfella: Does that make sense with a linked list? | |||||
115 | while (!m_lstItems.isEmpty()) { | 116 | while (!m_lstItems.isEmpty()) { | ||
116 | const KFileItem item = m_lstItems.first(); | 117 | const KFileItem item = m_lstItems.first(); | ||
117 | if (!item.isLink()) { // don't do anything with symlinks | 118 | if (!item.isLink()) { // don't do anything with symlinks | ||
118 | // File or directory -> remember to chmod | 119 | // File or directory -> remember to chmod | ||
119 | ChmodInfo info; | 120 | ChmodInfo info; | ||
120 | info.url = item.url(); | 121 | info.url = item.url(); | ||
121 | // This is a toplevel file, we apply changes directly (no +X emulation here) | 122 | // This is a toplevel file, we apply changes directly (no +X emulation here) | ||
122 | const mode_t permissions = item.permissions() & 0777; // get rid of "set gid" and other special flags | 123 | const mode_t permissions = item.permissions() & 0777; // get rid of "set gid" and other special flags | ||
123 | info.permissions = (m_permissions & m_mask) | (permissions & ~m_mask); | 124 | info.permissions = (m_permissions & m_mask) | (permissions & ~m_mask); | ||
124 | /*//qDebug() << "toplevel url:" << info.url << "\n current permissions=" << QString::number(permissions,8) | 125 | /*//qDebug() << "toplevel url:" << info.url << "\n current permissions=" << QString::number(permissions,8) | ||
125 | << "\n wanted permission=" << QString::number(m_permissions,8) | 126 | << "\n wanted permission=" << QString::number(m_permissions,8) | ||
126 | << "\n with mask=" << QString::number(m_mask,8) | 127 | << "\n with mask=" << QString::number(m_mask,8) | ||
127 | << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8) | 128 | << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8) | ||
128 | << "\n bits we keep =" << QString::number(permissions & ~m_mask,8) | 129 | << "\n bits we keep =" << QString::number(permissions & ~m_mask,8) | ||
129 | << "\n new permissions = " << QString::number(info.permissions,8);*/ | 130 | << "\n new permissions = " << QString::number(info.permissions,8);*/ | ||
130 | m_infos.prepend(info); | 131 | m_infos.push(std::move(info)); | ||
This could even be push_front(std::move(info)) since info isn't used anymore afterwards; dfaure: This could even be `push_front(std::move(info))` since `info` isn't used anymore afterwards; | |||||
131 | //qDebug() << "processList : Adding info for " << info.url; | 132 | //qDebug() << "processList : Adding info for " << info.url; | ||
132 | // Directory and recursive -> list | 133 | // Directory and recursive -> list | ||
133 | if (item.isDir() && m_recursive) { | 134 | if (item.isDir() && m_recursive) { | ||
134 | //qDebug() << "ChmodJob::processList dir -> listing"; | 135 | //qDebug() << "ChmodJob::processList dir -> listing"; | ||
135 | KIO::ListJob *listJob = KIO::listRecursive(item.url(), KIO::HideProgressInfo); | 136 | KIO::ListJob *listJob = KIO::listRecursive(item.url(), KIO::HideProgressInfo); | ||
136 | q->connect(listJob, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), | 137 | q->connect(listJob, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), | ||
137 | SLOT(_k_slotEntries(KIO::Job*,KIO::UDSEntryList))); | 138 | SLOT(_k_slotEntries(KIO::Job*,KIO::UDSEntryList))); | ||
138 | q->addSubjob(listJob); | 139 | q->addSubjob(listJob); | ||
139 | return; // we'll come back later, when this one's finished | 140 | return; // we'll come back later, when this one's finished | ||
140 | } | 141 | } | ||
141 | } | 142 | } | ||
142 | m_lstItems.removeFirst(); | 143 | m_lstItems.removeFirst(); | ||
143 | } | 144 | } | ||
144 | //qDebug() << "ChmodJob::processList -> going to STATE_CHMODING"; | 145 | //qDebug() << "ChmodJob::processList -> going to STATE_CHMODING"; | ||
145 | // We have finished, move on | 146 | // We have finished, move on | ||
146 | state = CHMODJOB_STATE_CHMODING; | 147 | state = CHMODJOB_STATE_CHMODING; | ||
147 | _k_chmodNextFile(); | 148 | _k_chmodNextFile(); | ||
148 | } | 149 | } | ||
149 | 150 | | |||
150 | void ChmodJobPrivate::_k_slotEntries(KIO::Job *, const KIO::UDSEntryList &list) | 151 | void ChmodJobPrivate::_k_slotEntries(KIO::Job *, const KIO::UDSEntryList &list) | ||
151 | { | 152 | { | ||
152 | KIO::UDSEntryList::ConstIterator it = list.begin(); | 153 | KIO::UDSEntryList::ConstIterator it = list.begin(); | ||
153 | KIO::UDSEntryList::ConstIterator end = list.end(); | 154 | KIO::UDSEntryList::ConstIterator end = list.end(); | ||
154 | for (; it != end; ++it) { | 155 | for (; it != end; ++it) { | ||
For efficiency, probably do a bruns: For efficiency, probably do a
`m_infos.reserve(m_infos.capacity() + list.size());`
here. | |||||
155 | const KIO::UDSEntry &entry = *it; | 156 | const KIO::UDSEntry &entry = *it; | ||
156 | const bool isLink = !entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST).isEmpty(); | 157 | const bool isLink = !entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST).isEmpty(); | ||
157 | const QString relativePath = entry.stringValue(KIO::UDSEntry::UDS_NAME); | 158 | const QString relativePath = entry.stringValue(KIO::UDSEntry::UDS_NAME); | ||
158 | if (!isLink && relativePath != QLatin1String("..")) { | 159 | if (!isLink && relativePath != QLatin1String("..")) { | ||
159 | const mode_t permissions = entry.numberValue(KIO::UDSEntry::UDS_ACCESS) | 160 | const mode_t permissions = entry.numberValue(KIO::UDSEntry::UDS_ACCESS) | ||
160 | & 0777; // get rid of "set gid" and other special flags | 161 | & 0777; // get rid of "set gid" and other special flags | ||
161 | 162 | | |||
162 | ChmodInfo info; | 163 | ChmodInfo info; | ||
Show All 16 Lines | |||||
179 | } | 180 | } | ||
180 | info.permissions = (m_permissions & mask) | (permissions & ~mask); | 181 | info.permissions = (m_permissions & mask) | (permissions & ~mask); | ||
181 | /*//qDebug() << info.url << "\n current permissions=" << QString::number(permissions,8) | 182 | /*//qDebug() << info.url << "\n current permissions=" << QString::number(permissions,8) | ||
182 | << "\n wanted permission=" << QString::number(m_permissions,8) | 183 | << "\n wanted permission=" << QString::number(m_permissions,8) | ||
183 | << "\n with mask=" << QString::number(mask,8) | 184 | << "\n with mask=" << QString::number(mask,8) | ||
184 | << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8) | 185 | << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8) | ||
185 | << "\n bits we keep =" << QString::number(permissions & ~mask,8) | 186 | << "\n bits we keep =" << QString::number(permissions & ~mask,8) | ||
186 | << "\n new permissions = " << QString::number(info.permissions,8);*/ | 187 | << "\n new permissions = " << QString::number(info.permissions,8);*/ | ||
187 | // Prepend this info in our todo list. | 188 | // Push this info on top of the stack so it's handled first. | ||
"Prepend" is confusing now since push is more of an append. This comment needs an update, like "Push this info on top of the stack so it's handled first" dfaure: "Prepend" is confusing now since push is more of an append. This comment needs an update, like… | |||||
188 | // This way, the toplevel dirs are done last. | 189 | // This way, the toplevel dirs are done last. | ||
189 | m_infos.prepend(info); | 190 | m_infos.push(std::move(info)); | ||
dfaure: same here | |||||
190 | } | 191 | } | ||
191 | } | 192 | } | ||
192 | } | 193 | } | ||
193 | 194 | | |||
194 | void ChmodJobPrivate::_k_chmodNextFile() | 195 | void ChmodJobPrivate::_k_chmodNextFile() | ||
195 | { | 196 | { | ||
196 | Q_Q(ChmodJob); | 197 | Q_Q(ChmodJob); | ||
197 | if (!m_infos.isEmpty()) { | 198 | if (!m_infos.empty()) { | ||
198 | ChmodInfo info = m_infos.takeFirst(); | 199 | ChmodInfo info = m_infos.top(); | ||
200 | m_infos.pop(); | ||||
199 | // First update group / owner (if local file) | 201 | // First update group / owner (if local file) | ||
200 | // (permissions have to set after, in case of suid and sgid) | 202 | // (permissions have to set after, in case of suid and sgid) | ||
201 | if (info.url.isLocalFile() && (m_newOwner.isValid() || m_newGroup.isValid())) { | 203 | if (info.url.isLocalFile() && (m_newOwner.isValid() || m_newGroup.isValid())) { | ||
202 | QString path = info.url.toLocalFile(); | 204 | QString path = info.url.toLocalFile(); | ||
203 | if (!KIOPrivate::changeOwnership(path, m_newOwner, m_newGroup)) { | 205 | if (!KIOPrivate::changeOwnership(path, m_newOwner, m_newGroup)) { | ||
204 | if (!m_uiDelegateExtension) { | 206 | if (!m_uiDelegateExtension) { | ||
205 | emit q->warning(q, i18n("Could not modify the ownership of file %1", path)); | 207 | emit q->warning(q, i18n("Could not modify the ownership of file %1", path)); | ||
206 | } else if (!m_bAutoSkipFiles) { | 208 | } else if (!m_bAutoSkipFiles) { | ||
207 | const QString errMsg = i18n("<qt>Could not modify the ownership of file <b>%1</b>. You have insufficient access to the file to perform the change.</qt>", path); | 209 | const QString errMsg = i18n("<qt>Could not modify the ownership of file <b>%1</b>. You have insufficient access to the file to perform the change.</qt>", path); | ||
208 | SkipDialog_Options options; | 210 | SkipDialog_Options options; | ||
209 | if (m_infos.count() > 1) { | 211 | if (m_infos.size() > 1) { | ||
210 | options |= SkipDialog_MultipleItems; | 212 | options |= SkipDialog_MultipleItems; | ||
211 | } | 213 | } | ||
212 | const SkipDialog_Result skipResult = m_uiDelegateExtension->askSkip(q, options, errMsg); | 214 | const SkipDialog_Result skipResult = m_uiDelegateExtension->askSkip(q, options, errMsg); | ||
213 | switch (skipResult) { | 215 | switch (skipResult) { | ||
214 | case Result_AutoSkip: | 216 | case Result_AutoSkip: | ||
215 | m_bAutoSkipFiles = true; | 217 | m_bAutoSkipFiles = true; | ||
216 | // fall through | 218 | // fall through | ||
217 | Q_FALLTHROUGH(); | 219 | Q_FALLTHROUGH(); | ||
218 | case Result_Skip: | 220 | case Result_Skip: | ||
219 | QMetaObject::invokeMethod(q, "_k_chmodNextFile", Qt::QueuedConnection); | 221 | QMetaObject::invokeMethod(q, "_k_chmodNextFile", Qt::QueuedConnection); | ||
220 | return; | 222 | return; | ||
221 | case Result_Retry: | 223 | case Result_Retry: | ||
222 | m_infos.prepend(info); | 224 | m_infos.push(std::move(info)); | ||
dfaure: same here | |||||
223 | QMetaObject::invokeMethod(q, "_k_chmodNextFile", Qt::QueuedConnection); | 225 | QMetaObject::invokeMethod(q, "_k_chmodNextFile", Qt::QueuedConnection); | ||
224 | return; | 226 | return; | ||
225 | case Result_Cancel: | 227 | case Result_Cancel: | ||
226 | default: | 228 | default: | ||
227 | q->setError(ERR_USER_CANCELED); | 229 | q->setError(ERR_USER_CANCELED); | ||
228 | q->emitResult(); | 230 | q->emitResult(); | ||
229 | return; | 231 | return; | ||
230 | } | 232 | } | ||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |
For efficiency, probably do a
m_infos.reserve(m_infos.capacity() + m_lstItems.size());
here.