KIO

kfileitem.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 1999-2011 David Faure <[email protected]>
4  SPDX-FileCopyrightText: 2001 Carsten Pfeiffer <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kfileitem.h"
10 
11 #include "config-kiocore.h"
12 
13 #if HAVE_POSIX_ACL
14 #include "../aclhelpers_p.h"
15 #endif
16 
17 #include "../pathhelpers_p.h"
18 #include "kiocoredebug.h"
19 #include "kioglobal_p.h"
20 
21 #include <QDataStream>
22 #include <QDate>
23 #include <QDebug>
24 #include <QDir>
25 #include <QDirIterator>
26 #include <QLocale>
27 #include <QMimeDatabase>
28 
29 #include <KConfigGroup>
30 #include <KDesktopFile>
31 #include <KLocalizedString>
32 #include <kmountpoint.h>
33 #ifndef Q_OS_WIN
34 #include <knfsshare.h>
35 #include <ksambashare.h>
36 #endif
37 #include <KFileSystemType>
38 #include <KProtocolManager>
39 
40 #define KFILEITEM_DEBUG 0
41 
42 class KFileItemPrivate : public QSharedData
43 {
44 public:
45  KFileItemPrivate(const KIO::UDSEntry &entry,
46  mode_t mode,
47  mode_t permissions,
48  const QUrl &itemOrDirUrl,
49  bool urlIsDirectory,
50  bool delayedMimeTypes,
51  KFileItem::MimeTypeDetermination mimeTypeDetermination)
52  : m_entry(entry)
53  , m_url(itemOrDirUrl)
54  , m_strName()
55  , m_strText()
56  , m_iconName()
57  , m_strLowerCaseName()
58  , m_mimeType()
59  , m_fileMode(mode)
60  , m_permissions(permissions)
61  , m_addACL(false)
62  , m_bLink(false)
63  , m_bIsLocalUrl(itemOrDirUrl.isLocalFile())
64  , m_bMimeTypeKnown(false)
65  , m_delayedMimeTypes(delayedMimeTypes)
66  , m_useIconNameCache(false)
67  , m_hidden(Auto)
68  , m_slow(SlowUnknown)
69  , m_bSkipMimeTypeFromContent(mimeTypeDetermination == KFileItem::SkipMimeTypeFromContent)
70  , m_bInitCalled(false)
71  {
72  if (entry.count() != 0) {
73  readUDSEntry(urlIsDirectory);
74  } else {
75  Q_ASSERT(!urlIsDirectory);
76  m_strName = itemOrDirUrl.fileName();
77  m_strText = KIO::decodeFileName(m_strName);
78  }
79  }
80 
81  /**
82  * Call init() if not yet done.
83  */
84  void ensureInitialized() const;
85 
86  /**
87  * Computes the text and mode from the UDSEntry.
88  */
89  void init() const;
90 
91  QString localPath() const;
92  KIO::filesize_t size() const;
93  KIO::filesize_t recursiveSize() const;
94  QDateTime time(KFileItem::FileTimes which) const;
95  void setTime(KFileItem::FileTimes which, uint time_t_val) const;
96  void setTime(KFileItem::FileTimes which, const QDateTime &val) const;
97  bool cmp(const KFileItemPrivate &item) const;
98  void printCompareDebug(const KFileItemPrivate &item) const;
99  bool isSlow() const;
100 
101  /**
102  * Extracts the data from the UDSEntry member and updates the KFileItem
103  * accordingly.
104  */
105  void readUDSEntry(bool _urlIsDirectory);
106 
107  /**
108  * Parses the given permission set and provides it for access()
109  */
110  QString parsePermissions(mode_t perm) const;
111 
112  /**
113  * Mime type helper
114  */
115  void determineMimeTypeHelper(const QUrl &url) const;
116 
117  /**
118  * The UDSEntry that contains the data for this fileitem, if it came from a directory listing.
119  */
120  mutable KIO::UDSEntry m_entry;
121  /**
122  * The url of the file
123  */
124  QUrl m_url;
125 
126  /**
127  * The text for this item, i.e. the file name without path,
128  */
129  QString m_strName;
130 
131  /**
132  * The text for this item, i.e. the file name without path, decoded
133  * ('%%' becomes '%', '%2F' becomes '/')
134  */
135  QString m_strText;
136 
137  /**
138  * The icon name for this item.
139  */
140  mutable QString m_iconName;
141 
142  /**
143  * The filename in lower case (to speed up sorting)
144  */
145  mutable QString m_strLowerCaseName;
146 
147  /**
148  * The MIME type of the file
149  */
150  mutable QMimeType m_mimeType;
151 
152  /**
153  * The file mode
154  */
155  mutable mode_t m_fileMode;
156  /**
157  * The permissions
158  */
159  mutable mode_t m_permissions;
160 
161  /**
162  * Whether the UDSEntry ACL fields should be added to m_entry.
163  */
164  mutable bool m_addACL : 1;
165 
166  /**
167  * Whether the file is a link
168  */
169  mutable bool m_bLink : 1;
170  /**
171  * True if local file
172  */
173  bool m_bIsLocalUrl : 1;
174 
175  mutable bool m_bMimeTypeKnown : 1;
176  mutable bool m_delayedMimeTypes : 1;
177 
178  /** True if m_iconName should be used as cache. */
179  mutable bool m_useIconNameCache : 1;
180 
181  // Auto: check leading dot.
182  enum { Auto, Hidden, Shown } m_hidden : 3;
183 
184  // Slow? (nfs/smb/ssh)
185  mutable enum { SlowUnknown, Fast, Slow } m_slow : 3;
186 
187  /**
188  * True if MIME type determination by content should be skipped
189  */
190  bool m_bSkipMimeTypeFromContent : 1;
191 
192  /**
193  * True if init() was called on demand
194  */
195  mutable bool m_bInitCalled : 1;
196 
197  // For special case like link to dirs over FTP
198  QString m_guessedMimeType;
199  mutable QString m_access;
200 };
201 
202 void KFileItemPrivate::ensureInitialized() const
203 {
204  if (!m_bInitCalled) {
205  init();
206  }
207 }
208 
209 void KFileItemPrivate::init() const
210 {
211  m_access.clear();
212  // metaInfo = KFileMetaInfo();
213 
214  // stat() local files if needed
215  const bool shouldStat = (m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown || m_entry.count() == 0) && m_url.isLocalFile();
216  if (shouldStat) {
217  /* directories may not have a slash at the end if we want to stat()
218  * them; it requires that we change into it .. which may not be allowed
219  * stat("/is/unaccessible") -> rwx------
220  * stat("/is/unaccessible/") -> EPERM H.Z.
221  * This is the reason for the StripTrailingSlash
222  */
223  QT_STATBUF buf;
224  const QString path = m_url.adjusted(QUrl::StripTrailingSlash).toLocalFile();
225  const QByteArray pathBA = QFile::encodeName(path);
226  if (QT_LSTAT(pathBA.constData(), &buf) == 0) {
227  m_entry.reserve(9);
228  m_entry.replace(KIO::UDSEntry::UDS_DEVICE_ID, buf.st_dev);
229  m_entry.replace(KIO::UDSEntry::UDS_INODE, buf.st_ino);
230 
231  mode_t mode = buf.st_mode;
232  if ((buf.st_mode & QT_STAT_MASK) == QT_STAT_LNK) {
233  m_bLink = true;
234  if (QT_STAT(pathBA.constData(), &buf) == 0) {
235  mode = buf.st_mode;
236  } else { // link pointing to nowhere (see FileProtocol::createUDSEntry() in ioslaves/file/file.cpp)
237  mode = (QT_STAT_MASK - 1) | S_IRWXU | S_IRWXG | S_IRWXO;
238  }
239  }
240 
241  const mode_t type = mode & QT_STAT_MASK;
242 
243  m_entry.replace(KIO::UDSEntry::UDS_SIZE, buf.st_size);
244  m_entry.replace(KIO::UDSEntry::UDS_FILE_TYPE, type); // extract file type
245  m_entry.replace(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // extract permissions
246  m_entry.replace(KIO::UDSEntry::UDS_MODIFICATION_TIME, buf.st_mtime); // TODO: we could use msecs too...
247  m_entry.replace(KIO::UDSEntry::UDS_ACCESS_TIME, buf.st_atime);
248 #ifndef Q_OS_WIN
249  m_entry.replace(KIO::UDSEntry::UDS_USER, KUser(buf.st_uid).loginName());
250  m_entry.replace(KIO::UDSEntry::UDS_GROUP, KUserGroup(buf.st_gid).name());
251 #endif
252 
253  // TODO: these can be removed, we can use UDS_FILE_TYPE and UDS_ACCESS everywhere
254  if (m_fileMode == KFileItem::Unknown) {
255  m_fileMode = type; // extract file type
256  }
257  if (m_permissions == KFileItem::Unknown) {
258  m_permissions = mode & 07777; // extract permissions
259  }
260 
261 #if HAVE_POSIX_ACL
262  if (m_addACL) {
263  appendACLAtoms(pathBA, m_entry, type);
264  }
265 #endif
266  }
267  }
268 
269  m_bInitCalled = true;
270 }
271 
272 void KFileItemPrivate::readUDSEntry(bool _urlIsDirectory)
273 {
274  // extract fields from the KIO::UDS Entry
275 
276  m_fileMode = m_entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE, KFileItem::Unknown);
277  m_permissions = m_entry.numberValue(KIO::UDSEntry::UDS_ACCESS, KFileItem::Unknown);
278  m_strName = m_entry.stringValue(KIO::UDSEntry::UDS_NAME);
279 
280  const QString displayName = m_entry.stringValue(KIO::UDSEntry::UDS_DISPLAY_NAME);
281  if (!displayName.isEmpty()) {
282  m_strText = displayName;
283  } else {
284  m_strText = KIO::decodeFileName(m_strName);
285  }
286 
287  const QString urlStr = m_entry.stringValue(KIO::UDSEntry::UDS_URL);
288  const bool UDS_URL_seen = !urlStr.isEmpty();
289  if (UDS_URL_seen) {
290  m_url = QUrl(urlStr);
291  if (m_url.isLocalFile()) {
292  m_bIsLocalUrl = true;
293  }
294  }
295  QMimeDatabase db;
296  const QString mimeTypeStr = m_entry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
297  m_bMimeTypeKnown = !mimeTypeStr.isEmpty();
298  if (m_bMimeTypeKnown) {
299  m_mimeType = db.mimeTypeForName(mimeTypeStr);
300  }
301 
302  m_guessedMimeType = m_entry.stringValue(KIO::UDSEntry::UDS_GUESSED_MIME_TYPE);
303  m_bLink = !m_entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST).isEmpty(); // we don't store the link dest
304 
305  const int hiddenVal = m_entry.numberValue(KIO::UDSEntry::UDS_HIDDEN, -1);
306  m_hidden = hiddenVal == 1 ? Hidden : (hiddenVal == 0 ? Shown : Auto);
307 
308  if (_urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != QLatin1String(".")) {
309  m_url.setPath(concatPaths(m_url.path(), m_strName));
310  }
311 
312  m_iconName.clear();
313 }
314 
315 // Inlined because it is used only in one place
316 inline KIO::filesize_t KFileItemPrivate::size() const
317 {
318  ensureInitialized();
319 
320  // Extract it from the KIO::UDSEntry
321  long long fieldVal = m_entry.numberValue(KIO::UDSEntry::UDS_SIZE, -1);
322  if (fieldVal != -1) {
323  return fieldVal;
324  }
325 
326  // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
327  if (m_bIsLocalUrl) {
328  return QFileInfo(m_url.toLocalFile()).size();
329  }
330  return 0;
331 }
332 
333 KIO::filesize_t KFileItemPrivate::recursiveSize() const
334 {
335  // Extract it from the KIO::UDSEntry
336  long long fieldVal = m_entry.numberValue(KIO::UDSEntry::UDS_RECURSIVE_SIZE, -1);
337  if (fieldVal != -1) {
338  return static_cast<KIO::filesize_t>(fieldVal);
339  }
340 
341  return 0;
342 }
343 
344 static uint udsFieldForTime(KFileItem::FileTimes mappedWhich)
345 {
346  switch (mappedWhich) {
347  case KFileItem::ModificationTime:
349  case KFileItem::AccessTime:
351  case KFileItem::CreationTime:
353  }
354  return 0;
355 }
356 
357 void KFileItemPrivate::setTime(KFileItem::FileTimes mappedWhich, uint time_t_val) const
358 {
359  m_entry.replace(udsFieldForTime(mappedWhich), time_t_val);
360 }
361 
362 void KFileItemPrivate::setTime(KFileItem::FileTimes mappedWhich, const QDateTime &val) const
363 {
364  const QDateTime dt = val.toLocalTime(); // #160979
365  setTime(mappedWhich, dt.toSecsSinceEpoch());
366 }
367 
368 QDateTime KFileItemPrivate::time(KFileItem::FileTimes mappedWhich) const
369 {
370  ensureInitialized();
371 
372  // Extract it from the KIO::UDSEntry
373  const uint uds = udsFieldForTime(mappedWhich);
374  if (uds > 0) {
375  const long long fieldVal = m_entry.numberValue(uds, -1);
376  if (fieldVal != -1) {
377  return QDateTime::fromMSecsSinceEpoch(1000 * fieldVal);
378  }
379  }
380 
381  return QDateTime();
382 }
383 
384 void KFileItemPrivate::printCompareDebug(const KFileItemPrivate &item) const
385 {
386  Q_UNUSED(item);
387 
388 #if KFILEITEM_DEBUG
389  const KIO::UDSEntry &otherEntry = item.m_entry;
390 
391  qDebug() << "Comparing" << m_url << "and" << item.m_url;
392  qDebug() << " name" << (m_strName == item.m_strName);
393  qDebug() << " local" << (m_bIsLocalUrl == item.m_bIsLocalUrl);
394 
395  qDebug() << " mode" << (m_fileMode == item.m_fileMode);
396  qDebug() << " perm" << (m_permissions == item.m_permissions);
397  qDebug() << " group" << (m_entry.stringValue(KIO::UDSEntry::UDS_GROUP) == otherEntry.stringValue(KIO::UDSEntry::UDS_GROUP));
398  qDebug() << " user" << (m_entry.stringValue(KIO::UDSEntry::UDS_USER) == otherEntry.stringValue(KIO::UDSEntry::UDS_USER));
399 
400  qDebug() << " UDS_EXTENDED_ACL" << (m_entry.stringValue(KIO::UDSEntry::UDS_EXTENDED_ACL) == otherEntry.stringValue(KIO::UDSEntry::UDS_EXTENDED_ACL));
401  qDebug() << " UDS_ACL_STRING" << (m_entry.stringValue(KIO::UDSEntry::UDS_ACL_STRING) == otherEntry.stringValue(KIO::UDSEntry::UDS_ACL_STRING));
402  qDebug() << " UDS_DEFAULT_ACL_STRING"
404 
405  qDebug() << " m_bLink" << (m_bLink == item.m_bLink);
406  qDebug() << " m_hidden" << (m_hidden == item.m_hidden);
407 
408  qDebug() << " size" << (size() == item.size());
409 
410  qDebug() << " ModificationTime" << m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME)
412 
413  qDebug() << " UDS_ICON_NAME" << (m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME) == otherEntry.stringValue(KIO::UDSEntry::UDS_ICON_NAME));
414 #endif
415 }
416 
417 // Inlined because it is used only in one place
418 inline bool KFileItemPrivate::cmp(const KFileItemPrivate &item) const
419 {
420  if (item.m_bInitCalled) {
421  ensureInitialized();
422  }
423 
424  if (m_bInitCalled) {
425  item.ensureInitialized();
426  }
427 
428 #if KFILEITEM_DEBUG
429  printCompareDebug(item);
430 #endif
431 
432  /* clang-format off */
433  return (m_strName == item.m_strName
434  && m_bIsLocalUrl == item.m_bIsLocalUrl
435  && m_fileMode == item.m_fileMode
436  && m_permissions == item.m_permissions
437  && m_entry.stringValue(KIO::UDSEntry::UDS_GROUP) == item.m_entry.stringValue(KIO::UDSEntry::UDS_GROUP)
438  && m_entry.stringValue(KIO::UDSEntry::UDS_USER) == item.m_entry.stringValue(KIO::UDSEntry::UDS_USER)
439  && m_entry.stringValue(KIO::UDSEntry::UDS_EXTENDED_ACL) == item.m_entry.stringValue(KIO::UDSEntry::UDS_EXTENDED_ACL)
440  && m_entry.stringValue(KIO::UDSEntry::UDS_ACL_STRING) == item.m_entry.stringValue(KIO::UDSEntry::UDS_ACL_STRING)
441  && m_entry.stringValue(KIO::UDSEntry::UDS_DEFAULT_ACL_STRING) == item.m_entry.stringValue(KIO::UDSEntry::UDS_DEFAULT_ACL_STRING)
442  && m_bLink == item.m_bLink
443  && m_hidden == item.m_hidden
444  && size() == item.size()
445  && m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) == item.m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME)
446  && m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME) == item.m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME)
447  && m_entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL) == item.m_entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL)
448  && m_entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH) == item.m_entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH));
449  /* clang-format on */
450  // Don't compare the MIME types here. They might not be known, and we don't want to
451  // do the slow operation of determining them here.
452 }
453 
454 // Inlined because it is used only in one place
455 inline QString KFileItemPrivate::parsePermissions(mode_t perm) const
456 {
457  ensureInitialized();
458 
459  static char buffer[12];
460 
461  char uxbit;
462  char gxbit;
463  char oxbit;
464 
465  if ((perm & (S_IXUSR | S_ISUID)) == (S_IXUSR | S_ISUID)) {
466  uxbit = 's';
467  } else if ((perm & (S_IXUSR | S_ISUID)) == S_ISUID) {
468  uxbit = 'S';
469  } else if ((perm & (S_IXUSR | S_ISUID)) == S_IXUSR) {
470  uxbit = 'x';
471  } else {
472  uxbit = '-';
473  }
474 
475  if ((perm & (S_IXGRP | S_ISGID)) == (S_IXGRP | S_ISGID)) {
476  gxbit = 's';
477  } else if ((perm & (S_IXGRP | S_ISGID)) == S_ISGID) {
478  gxbit = 'S';
479  } else if ((perm & (S_IXGRP | S_ISGID)) == S_IXGRP) {
480  gxbit = 'x';
481  } else {
482  gxbit = '-';
483  }
484 
485  if ((perm & (S_IXOTH | S_ISVTX)) == (S_IXOTH | S_ISVTX)) {
486  oxbit = 't';
487  } else if ((perm & (S_IXOTH | S_ISVTX)) == S_ISVTX) {
488  oxbit = 'T';
489  } else if ((perm & (S_IXOTH | S_ISVTX)) == S_IXOTH) {
490  oxbit = 'x';
491  } else {
492  oxbit = '-';
493  }
494 
495  // Include the type in the first char like ls does; people are more used to seeing it,
496  // even though it's not really part of the permissions per se.
497  if (m_bLink) {
498  buffer[0] = 'l';
499  } else if (m_fileMode != KFileItem::Unknown) {
500  if ((m_fileMode & QT_STAT_MASK) == QT_STAT_DIR) {
501  buffer[0] = 'd';
502  }
503 #ifdef Q_OS_UNIX
504  else if (S_ISSOCK(m_fileMode)) {
505  buffer[0] = 's';
506  } else if (S_ISCHR(m_fileMode)) {
507  buffer[0] = 'c';
508  } else if (S_ISBLK(m_fileMode)) {
509  buffer[0] = 'b';
510  } else if (S_ISFIFO(m_fileMode)) {
511  buffer[0] = 'p';
512  }
513 #endif // Q_OS_UNIX
514  else {
515  buffer[0] = '-';
516  }
517  } else {
518  buffer[0] = '-';
519  }
520 
521  buffer[1] = (((perm & S_IRUSR) == S_IRUSR) ? 'r' : '-');
522  buffer[2] = (((perm & S_IWUSR) == S_IWUSR) ? 'w' : '-');
523  buffer[3] = uxbit;
524  buffer[4] = (((perm & S_IRGRP) == S_IRGRP) ? 'r' : '-');
525  buffer[5] = (((perm & S_IWGRP) == S_IWGRP) ? 'w' : '-');
526  buffer[6] = gxbit;
527  buffer[7] = (((perm & S_IROTH) == S_IROTH) ? 'r' : '-');
528  buffer[8] = (((perm & S_IWOTH) == S_IWOTH) ? 'w' : '-');
529  buffer[9] = oxbit;
530  // if (hasExtendedACL())
531  if (m_entry.contains(KIO::UDSEntry::UDS_EXTENDED_ACL)) {
532  buffer[10] = '+';
533  buffer[11] = 0;
534  } else {
535  buffer[10] = 0;
536  }
537 
538  return QString::fromLatin1(buffer);
539 }
540 
541 void KFileItemPrivate::determineMimeTypeHelper(const QUrl &url) const
542 {
543  QMimeDatabase db;
544  if (m_bSkipMimeTypeFromContent) {
545  const QString scheme = url.scheme();
546  if (scheme.startsWith(QLatin1String("http")) || scheme == QLatin1String("mailto")) {
547  m_mimeType = db.mimeTypeForName(QLatin1String("application/octet-stream"));
548  } else {
549  m_mimeType = db.mimeTypeForFile(url.path(), QMimeDatabase::MatchMode::MatchExtension);
550  }
551  } else {
552  m_mimeType = db.mimeTypeForUrl(url);
553  }
554 }
555 
556 ///////
557 
559  : d(nullptr)
560 {
561 }
562 
563 KFileItem::KFileItem(const KIO::UDSEntry &entry, const QUrl &itemOrDirUrl, bool delayedMimeTypes, bool urlIsDirectory)
564  : d(new KFileItemPrivate(entry,
565  KFileItem::Unknown,
566  KFileItem::Unknown,
567  itemOrDirUrl,
568  urlIsDirectory,
569  delayedMimeTypes,
570  KFileItem::NormalMimeTypeDetermination))
571 {
572 }
573 
574 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 0)
575 KFileItem::KFileItem(mode_t mode, mode_t permissions, const QUrl &url, bool delayedMimeTypes)
576  : d(new KFileItemPrivate(KIO::UDSEntry(), mode, permissions, url, false, delayedMimeTypes, KFileItem::NormalMimeTypeDetermination))
577 {
578 }
579 #endif
580 
581 KFileItem::KFileItem(const QUrl &url, const QString &mimeType, mode_t mode)
582  : d(new KFileItemPrivate(KIO::UDSEntry(), mode, KFileItem::Unknown, url, false, false, KFileItem::NormalMimeTypeDetermination))
583 {
584  d->m_bMimeTypeKnown = !mimeType.isEmpty();
585  if (d->m_bMimeTypeKnown) {
586  QMimeDatabase db;
587  d->m_mimeType = db.mimeTypeForName(mimeType);
588  }
589 }
590 
591 KFileItem::KFileItem(const QUrl &url, KFileItem::MimeTypeDetermination mimeTypeDetermination)
592  : d(new KFileItemPrivate(KIO::UDSEntry(), KFileItem::Unknown, KFileItem::Unknown, url, false, false, mimeTypeDetermination))
593 {
594 }
595 
596 // Default implementations for:
597 // - Copy constructor
598 // - Move constructor
599 // - Copy assignment
600 // - Move assignment
601 // - Destructor
602 // The compiler will now generate the content of those.
603 KFileItem::KFileItem(const KFileItem &) = default;
604 KFileItem::~KFileItem() = default;
605 KFileItem::KFileItem(KFileItem &&) = default;
606 KFileItem &KFileItem::operator=(const KFileItem &) = default;
608 
610 {
611  if (!d) {
612  qCWarning(KIO_CORE) << "null item";
613  return;
614  }
615 
616  d->m_fileMode = KFileItem::Unknown;
617  d->m_permissions = KFileItem::Unknown;
618  d->m_hidden = KFileItemPrivate::Auto;
619  refreshMimeType();
620 
621 #if HAVE_POSIX_ACL
622  // If the item had ACL, re-add them in init()
623  d->m_addACL = !d->m_entry.stringValue(KIO::UDSEntry::UDS_ACL_STRING).isEmpty();
624 #endif
625 
626  // Basically, we can't trust any information we got while listing.
627  // Everything could have changed...
628  // Clearing m_entry makes it possible to detect changes in the size of the file,
629  // the time information, etc.
630  d->m_entry.clear();
631  d->init(); // re-populates d->m_entry
632 }
633 
635 {
636  if (!d) {
637  return;
638  }
639 
640  d->m_mimeType = QMimeType();
641  d->m_bMimeTypeKnown = false;
642  d->m_iconName.clear();
643 }
644 
646 {
647  if (!d) {
648  return;
649  }
650  d->m_delayedMimeTypes = b;
651 }
652 
653 void KFileItem::setUrl(const QUrl &url)
654 {
655  if (!d) {
656  qCWarning(KIO_CORE) << "null item";
657  return;
658  }
659 
660  d->m_url = url;
661  setName(url.fileName());
662 }
663 
665 {
666  if (!d) {
667  qCWarning(KIO_CORE) << "null item";
668  return;
669  }
670 
671  d->m_entry.replace(KIO::UDSEntry::UDS_LOCAL_PATH, path);
672 }
673 
675 {
676  if (!d) {
677  qCWarning(KIO_CORE) << "null item";
678  return;
679  }
680 
681  d->ensureInitialized();
682 
683  d->m_strName = name;
684  if (!d->m_strName.isEmpty()) {
685  d->m_strText = KIO::decodeFileName(d->m_strName);
686  }
687  if (d->m_entry.contains(KIO::UDSEntry::UDS_NAME)) {
688  d->m_entry.replace(KIO::UDSEntry::UDS_NAME, d->m_strName); // #195385
689  }
690 }
691 
693 {
694  if (!d) {
695  return QString();
696  }
697 
698  d->ensureInitialized();
699 
700  // Extract it from the KIO::UDSEntry
701  const QString linkStr = d->m_entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST);
702  if (!linkStr.isEmpty()) {
703  return linkStr;
704  }
705 
706  // If not in the KIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL]
707  if (d->m_bIsLocalUrl) {
708  return QFile::symLinkTarget(d->m_url.adjusted(QUrl::StripTrailingSlash).toLocalFile());
709  }
710  return QString();
711 }
712 
713 QString KFileItemPrivate::localPath() const
714 {
715  if (m_bIsLocalUrl) {
716  return m_url.toLocalFile();
717  }
718 
719  ensureInitialized();
720 
721  // Extract the local path from the KIO::UDSEntry
722  return m_entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
723 }
724 
726 {
727  if (!d) {
728  return QString();
729  }
730 
731  return d->localPath();
732 }
733 
735 {
736  if (!d) {
737  return 0;
738  }
739 
740  return d->size();
741 }
742 
744 {
745  if (!d) {
746  return 0;
747  }
748 
749  return d->recursiveSize();
750 }
751 
753 {
754  if (!d) {
755  return false;
756  }
757 
758  // Check if the field exists; its value doesn't matter
760 }
761 
763 {
764  if (!d) {
765  return KACL();
766  }
767 
768  if (hasExtendedACL()) {
769  // Extract it from the KIO::UDSEntry
770  const QString fieldVal = d->m_entry.stringValue(KIO::UDSEntry::UDS_ACL_STRING);
771  if (!fieldVal.isEmpty()) {
772  return KACL(fieldVal);
773  }
774  }
775 
776  // create one from the basic permissions
777  return KACL(d->m_permissions);
778 }
779 
781 {
782  if (!d) {
783  return KACL();
784  }
785 
786  // Extract it from the KIO::UDSEntry
788  if (!fieldVal.isEmpty()) {
789  return KACL(fieldVal);
790  } else {
791  return KACL();
792  }
793 }
794 
796 {
797  if (!d) {
798  return QDateTime();
799  }
800 
801  return d->time(which);
802 }
803 
805 {
806  if (!d) {
807  return QString();
808  }
809 
811 }
812 
814 {
815  if (!d) {
816  return QString();
817  }
818 
820 }
821 
822 bool KFileItemPrivate::isSlow() const
823 {
824  if (m_slow == SlowUnknown) {
825  const QString path = localPath();
826  if (!path.isEmpty()) {
828  m_slow = (fsType == KFileSystemType::Nfs || fsType == KFileSystemType::Smb) ? Slow : Fast;
829  } else {
830  m_slow = Slow;
831  }
832  }
833  return m_slow == Slow;
834 }
835 
836 bool KFileItem::isSlow() const
837 {
838  if (!d) {
839  return false;
840  }
841 
842  return d->isSlow();
843 }
844 
846 {
847  if (!d) {
848  return QString();
849  }
850 
851  KFileItem *that = const_cast<KFileItem *>(this);
852  return that->determineMimeType().name();
853 }
854 
856 {
857  if (!d) {
858  return QMimeType();
859  }
860 
861  if (!d->m_mimeType.isValid() || !d->m_bMimeTypeKnown) {
862  QMimeDatabase db;
863  if (isDir()) {
864  d->m_mimeType = db.mimeTypeForName(QStringLiteral("inode/directory"));
865  } else {
866  bool isLocalUrl;
867  const QUrl url = mostLocalUrl(&isLocalUrl);
868  d->determineMimeTypeHelper(url);
869 
870  // was: d->m_mimeType = KMimeType::findByUrl( url, d->m_fileMode, isLocalUrl );
871  // => we are no longer using d->m_fileMode for remote URLs.
872  Q_ASSERT(d->m_mimeType.isValid());
873  // qDebug() << d << "finding final MIME type for" << url << ":" << d->m_mimeType.name();
874  }
875  d->m_bMimeTypeKnown = true;
876  }
877 
878  if (d->m_delayedMimeTypes) { // if we delayed getting the iconName up till now, this is the right point in time to do so
879  d->m_delayedMimeTypes = false;
880  d->m_useIconNameCache = false;
881  (void)iconName();
882  }
883 
884  return d->m_mimeType;
885 }
886 
888 {
889  if (!d) {
890  return false;
891  }
892 
893  // The MIME type isn't known if determineMimeType was never called (on-demand determination)
894  // or if this fileitem has a guessed MIME type (e.g. ftp symlink) - in which case
895  // it always remains "not fully determined"
896  return d->m_bMimeTypeKnown && d->m_guessedMimeType.isEmpty();
897 }
898 
899 static bool isDirectoryMounted(const QUrl &url)
900 {
901  // Stating .directory files can cause long freezes when e.g. /home
902  // uses autofs for every user's home directory, i.e. opening /home
903  // in a file dialog will mount every single home directory.
904  // These non-mounted directories can be identified by having 0 size.
905  // There are also other directories with 0 size, such as /proc, that may
906  // be mounted, but those are unlikely to contain .directory (and checking
907  // this would require checking with KMountPoint).
908 
909  // TODO: maybe this could be checked with KFileSystemType instead?
910  QFileInfo info(url.toLocalFile());
911  if (info.isDir() && info.size() == 0) {
912  return false;
913  }
914  return true;
915 }
916 
918 {
919  if (!d) {
920  return false;
921  }
922  return d->m_bMimeTypeKnown && (!d->m_delayedMimeTypes);
923 }
924 
925 // KDE5 TODO: merge with comment()? Need to see what lxr says about the usage of both.
927 {
928  if (!d) {
929  return QString();
930  }
931 
932  const QString displayType = d->m_entry.stringValue(KIO::UDSEntry::UDS_DISPLAY_TYPE);
933  if (!displayType.isEmpty()) {
934  return displayType;
935  }
936 
937  bool isLocalUrl;
938  QUrl url = mostLocalUrl(&isLocalUrl);
939 
940  QMimeType mime = currentMimeType();
941  // This cannot move to kio_file (with UDS_DISPLAY_TYPE) because it needs
942  // the MIME type to be determined, which is done here, and possibly delayed...
943  if (isLocalUrl && !d->isSlow() && mime.inherits(QStringLiteral("application/x-desktop"))) {
944  KDesktopFile cfg(url.toLocalFile());
945  QString comment = cfg.desktopGroup().readEntry("Comment");
946  if (!comment.isEmpty()) {
947  return comment;
948  }
949  }
950 
951  // Support for .directory file in directories
952  if (isLocalUrl && isDir() && !d->isSlow() && isDirectoryMounted(url)) {
953  QUrl u(url);
954  u.setPath(concatPaths(u.path(), QStringLiteral(".directory")));
955  const KDesktopFile cfg(u.toLocalFile());
956  const QString comment = cfg.readComment();
957  if (!comment.isEmpty()) {
958  return comment;
959  }
960  }
961 
962  const QString comment = mime.comment();
963  // qDebug() << "finding comment for " << url.url() << " : " << d->m_mimeType->name();
964  if (!comment.isEmpty()) {
965  return comment;
966  } else {
967  return mime.name();
968  }
969 }
970 
971 static QString iconFromDirectoryFile(const QString &path)
972 {
973  const QString filePath = path + QLatin1String("/.directory");
974  if (!QFileInfo(filePath).isFile()) { // exists -and- is a file
975  return QString();
976  }
977 
978  KDesktopFile cfg(filePath);
979  QString icon = cfg.readIcon();
980 
981  const KConfigGroup group = cfg.desktopGroup();
982  const QString emptyIcon = group.readEntry("EmptyIcon");
983  if (!emptyIcon.isEmpty()) {
984  bool isDirEmpty = true;
986  while (dirIt.hasNext()) {
987  dirIt.next();
988  if (dirIt.fileName() != QLatin1String(".directory")) {
989  isDirEmpty = false;
990  break;
991  }
992  }
993  if (isDirEmpty) {
994  icon = emptyIcon;
995  }
996  }
997 
998  if (icon.startsWith(QLatin1String("./"))) {
999  // path is relative with respect to the location of the .directory file (#73463)
1000  return path + QStringView(icon).mid(1);
1001  }
1002  return icon;
1003 }
1004 
1005 static QString iconFromDesktopFile(const QString &path)
1006 {
1007  KDesktopFile cfg(path);
1008  const QString icon = cfg.readIcon();
1009  if (cfg.hasLinkType()) {
1010  const KConfigGroup group = cfg.desktopGroup();
1011  const QString emptyIcon = group.readEntry("EmptyIcon");
1012  if (!emptyIcon.isEmpty()) {
1013  const QString u = cfg.readUrl();
1014  const QUrl url(u);
1015  if (url.scheme() == QLatin1String("trash")) {
1016  // We need to find if the trash is empty, preferably without using a KIO job.
1017  // So instead kio_trash leaves an entry in its config file for us.
1018  KConfig trashConfig(QStringLiteral("trashrc"), KConfig::SimpleConfig);
1019  if (trashConfig.group("Status").readEntry("Empty", true)) {
1020  return emptyIcon;
1021  }
1022  }
1023  }
1024  }
1025  return icon;
1026 }
1027 
1029 {
1030  if (!d) {
1031  return QString();
1032  }
1033 
1034  if (d->m_useIconNameCache && !d->m_iconName.isEmpty()) {
1035  return d->m_iconName;
1036  }
1037 
1038  d->m_iconName = d->m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME);
1039  if (!d->m_iconName.isEmpty()) {
1040  d->m_useIconNameCache = d->m_bMimeTypeKnown;
1041  return d->m_iconName;
1042  }
1043 
1044  bool isLocalUrl;
1045  QUrl url = mostLocalUrl(&isLocalUrl);
1046 
1047  QMimeDatabase db;
1048  QMimeType mime;
1049  // Use guessed MIME type for the icon
1050  if (!d->m_guessedMimeType.isEmpty()) {
1051  mime = db.mimeTypeForName(d->m_guessedMimeType);
1052  } else {
1053  mime = currentMimeType();
1054  }
1055 
1056  const bool delaySlowOperations = d->m_delayedMimeTypes;
1057 
1058  if (isLocalUrl && !delaySlowOperations && mime.inherits(QStringLiteral("application/x-desktop"))) {
1059  d->m_iconName = iconFromDesktopFile(url.toLocalFile());
1060  if (!d->m_iconName.isEmpty()) {
1061  d->m_useIconNameCache = d->m_bMimeTypeKnown;
1062  return d->m_iconName;
1063  }
1064  }
1065 
1066  if (isLocalUrl && !delaySlowOperations && isDir()) {
1067  if (isDirectoryMounted(url)) {
1068  d->m_iconName = iconFromDirectoryFile(url.toLocalFile());
1069  if (!d->m_iconName.isEmpty()) {
1070  d->m_useIconNameCache = d->m_bMimeTypeKnown;
1071  return d->m_iconName;
1072  }
1073  }
1074 
1075  d->m_iconName = KIOPrivate::iconForStandardPath(url.toLocalFile());
1076  if (!d->m_iconName.isEmpty()) {
1077  d->m_useIconNameCache = d->m_bMimeTypeKnown;
1078  return d->m_iconName;
1079  }
1080  }
1081 
1082  d->m_iconName = mime.iconName();
1083  d->m_useIconNameCache = d->m_bMimeTypeKnown;
1084  return d->m_iconName;
1085 }
1086 
1087 /**
1088  * Returns true if this is a desktop file.
1089  * MIME type determination is optional.
1090  */
1091 static bool checkDesktopFile(const KFileItem &item, bool _determineMimeType)
1092 {
1093  // only local files
1094  bool isLocalUrl;
1095  item.mostLocalUrl(&isLocalUrl);
1096  if (!isLocalUrl) {
1097  return false;
1098  }
1099 
1100  // only regular files
1101  if (!item.isRegularFile()) {
1102  return false;
1103  }
1104 
1105  // only if readable
1106  if (!item.isReadable()) {
1107  return false;
1108  }
1109 
1110  // return true if desktop file
1111  QMimeType mime = _determineMimeType ? item.determineMimeType() : item.currentMimeType();
1112  return mime.inherits(QStringLiteral("application/x-desktop"));
1113 }
1114 
1116 {
1117  if (!d) {
1118  return QStringList();
1119  }
1120 
1121  d->ensureInitialized();
1122 
1123  QStringList names = d->m_entry.stringValue(KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES).split(QLatin1Char(','), Qt::SkipEmptyParts);
1124 
1125  if (d->m_bLink) {
1126  names.append(QStringLiteral("emblem-symbolic-link"));
1127  }
1128 
1129  if (!isReadable()) {
1130  names.append(QStringLiteral("emblem-locked"));
1131  }
1132 
1133  if (checkDesktopFile(*this, false)) {
1134  KDesktopFile cfg(localPath());
1135  const KConfigGroup group = cfg.desktopGroup();
1136 
1137  // Add a warning emblem if this is an executable desktop file
1138  // which is untrusted.
1139  if (group.hasKey("Exec") && !KDesktopFile::isAuthorizedDesktopFile(localPath())) {
1140  names.append(QStringLiteral("emblem-important"));
1141  }
1142 
1143 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 82)
1144  if (cfg.hasDeviceType()) {
1145  QT_WARNING_PUSH
1146  QT_WARNING_DISABLE_DEPRECATED
1147  const QString dev = cfg.readDevice();
1148  QT_WARNING_POP
1149  if (!dev.isEmpty()) {
1151  if (mountPoint) { // mounted?
1152  names.append(QStringLiteral("emblem-mounted"));
1153  }
1154  }
1155  }
1156 #endif
1157  }
1158 
1159  if (isHidden()) {
1160  names.append(QStringLiteral("hidden"));
1161  }
1162 #ifndef Q_OS_WIN
1163  if (isDir()) {
1164  bool isLocalUrl;
1165  const QUrl url = mostLocalUrl(&isLocalUrl);
1166  if (isLocalUrl) {
1167  const QString path = url.toLocalFile();
1168  if (KSambaShare::instance()->isDirectoryShared(path) || KNFSShare::instance()->isDirectoryShared(path)) {
1169  names.append(QStringLiteral("emblem-shared"));
1170  }
1171  }
1172  }
1173 #endif // Q_OS_WIN
1174 
1175  return names;
1176 }
1177 
1179 {
1180  if (!d) {
1181  return QString();
1182  }
1183 
1184  return d->m_entry.stringValue(KIO::UDSEntry::UDS_COMMENT);
1185 }
1186 
1188 {
1189  if (!d) {
1190  return false;
1191  }
1192 
1193  d->ensureInitialized();
1194 
1195  /*
1196  struct passwd * user = getpwuid( geteuid() );
1197  bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == d->m_user);
1198  // This gets ugly for the group....
1199  // Maybe we want a static QString for the user and a static QStringList
1200  // for the groups... then we need to handle the deletion properly...
1201  */
1202 
1203  if (d->m_permissions != KFileItem::Unknown) {
1204  const mode_t readMask = S_IRUSR | S_IRGRP | S_IROTH;
1205  // No read permission at all
1206  if ((d->m_permissions & readMask) == 0) {
1207  return false;
1208  }
1209 
1210  // Read permissions for all: save a stat call
1211  if ((d->m_permissions & readMask) == readMask) {
1212  return true;
1213  }
1214  }
1215 
1216  // Or if we can't read it - not network transparent
1217  if (d->m_bIsLocalUrl && !QFileInfo(d->m_url.toLocalFile()).isReadable()) {
1218  return false;
1219  }
1220 
1221  return true;
1222 }
1223 
1225 {
1226  if (!d) {
1227  return false;
1228  }
1229 
1230  d->ensureInitialized();
1231 
1232  /*
1233  struct passwd * user = getpwuid( geteuid() );
1234  bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == d->m_user);
1235  // This gets ugly for the group....
1236  // Maybe we want a static QString for the user and a static QStringList
1237  // for the groups... then we need to handle the deletion properly...
1238  */
1239 
1240  if (d->m_permissions != KFileItem::Unknown) {
1241  // No write permission at all
1242  if (!(S_IWUSR & d->m_permissions) && !(S_IWGRP & d->m_permissions) && !(S_IWOTH & d->m_permissions)) {
1243  return false;
1244  }
1245  }
1246 
1247  // Or if we can't write it - not network transparent
1248  if (d->m_bIsLocalUrl) {
1249  return QFileInfo(d->m_url.toLocalFile()).isWritable();
1250  } else {
1251  return KProtocolManager::supportsWriting(d->m_url);
1252  }
1253 }
1254 
1256 {
1257  if (!d) {
1258  return false;
1259  }
1260 
1261  // The kioslave can specify explicitly that a file is hidden or shown
1262  if (d->m_hidden != KFileItemPrivate::Auto) {
1263  return d->m_hidden == KFileItemPrivate::Hidden;
1264  }
1265 
1266  // Prefer the filename that is part of the URL, in case the display name is different.
1267  QString fileName = d->m_url.fileName();
1268  if (fileName.isEmpty()) { // e.g. "trash:/"
1269  fileName = d->m_strName;
1270  }
1271  return fileName.length() > 1 && fileName[0] == QLatin1Char('.'); // Just "." is current directory, not hidden.
1272 }
1273 
1274 void KFileItem::setHidden()
1275 {
1276  if (d) {
1277  d->m_hidden = KFileItemPrivate::Hidden;
1278  }
1279 }
1280 
1281 bool KFileItem::isDir() const
1282 {
1283  if (!d) {
1284  return false;
1285  }
1286 
1287  if (d->m_bSkipMimeTypeFromContent) {
1288  return false;
1289  }
1290 
1291  d->ensureInitialized();
1292 
1293  if (d->m_fileMode == KFileItem::Unknown) {
1294  // Probably the file was deleted already, and KDirLister hasn't told the world yet.
1295  // qDebug() << d << url() << "can't say -> false";
1296  return false; // can't say for sure, so no
1297  }
1298  return (d->m_fileMode & QT_STAT_MASK) == QT_STAT_DIR;
1299 }
1300 
1301 bool KFileItem::isFile() const
1302 {
1303  if (!d) {
1304  return false;
1305  }
1306 
1307  return !isDir();
1308 }
1309 
1310 #if KIOCORE_BUILD_DEPRECATED_SINCE(4, 0)
1312 {
1313  // A directory ?
1314  if (isDir()) {
1315  return isWritable();
1316  }
1317 
1318  // But only local .desktop files and executables
1319  if (!d->m_bIsLocalUrl) {
1320  return false;
1321  }
1322 
1323  if (mimetype() == QLatin1String("application/x-desktop")) {
1324  return true;
1325  }
1326 
1327  // Executable, shell script ... ?
1328  if (QFileInfo(d->m_url.toLocalFile()).isExecutable()) {
1329  return true;
1330  }
1331 
1332  return false;
1333 }
1334 #endif
1335 
1337 {
1338  if (!d) {
1339  return QString();
1340  }
1341 
1342  QString text = d->m_strText;
1343  const QString comment = mimeComment();
1344 
1345  if (d->m_bLink) {
1346  text += QLatin1Char(' ');
1347  if (comment.isEmpty()) {
1348  text += i18n("(Symbolic Link to %1)", linkDest());
1349  } else {
1350  text += i18n("(%1, Link to %2)", comment, linkDest());
1351  }
1352  } else if (targetUrl() != url()) {
1353  text += i18n(" (Points to %1)", targetUrl().toDisplayString());
1354  } else if ((d->m_fileMode & QT_STAT_MASK) == QT_STAT_REG) {
1355  text += QStringLiteral(" (%1, %2)").arg(comment, KIO::convertSize(size()));
1356  } else {
1357  text += QStringLiteral(" (%1)").arg(comment);
1358  }
1359  return text;
1360 }
1361 
1362 bool KFileItem::cmp(const KFileItem &item) const
1363 {
1364  if (!d && !item.d) {
1365  return true;
1366  }
1367 
1368  if (!d || !item.d) {
1369  return false;
1370  }
1371 
1372  return d->cmp(*item.d);
1373 }
1374 
1375 bool KFileItem::operator==(const KFileItem &other) const
1376 {
1377  if (!d && !other.d) {
1378  return true;
1379  }
1380 
1381  if (!d || !other.d) {
1382  return false;
1383  }
1384 
1385  return d->m_url == other.d->m_url;
1386 }
1387 
1388 bool KFileItem::operator!=(const KFileItem &other) const
1389 {
1390  return !operator==(other);
1391 }
1392 
1393 bool KFileItem::operator<(const KFileItem &other) const
1394 {
1395  if (!other.d) {
1396  return false;
1397  }
1398  if (!d) {
1399  return other.d->m_url.isValid();
1400  }
1401  return d->m_url < other.d->m_url;
1402 }
1403 
1404 bool KFileItem::operator<(const QUrl &other) const
1405 {
1406  if (!d) {
1407  return other.isValid();
1408  }
1409  return d->m_url < other;
1410 }
1411 
1412 KFileItem::operator QVariant() const
1413 {
1414  return QVariant::fromValue(*this);
1415 }
1416 
1418 {
1419  if (!d) {
1420  return QString();
1421  }
1422 
1423  d->ensureInitialized();
1424 
1425  if (d->m_access.isNull() && d->m_permissions != KFileItem::Unknown) {
1426  d->m_access = d->parsePermissions(d->m_permissions);
1427  }
1428 
1429  return d->m_access;
1430 }
1431 
1432 // check if we need to cache this
1434 {
1435  if (!d) {
1436  return QString();
1437  }
1438 
1439  return QLocale::system().toString(d->time(which), QLocale::LongFormat);
1440 }
1441 
1442 #if KIOCORE_BUILD_DEPRECATED_SINCE(4, 0)
1443 QString KFileItem::timeString(unsigned int which) const
1444 {
1445  if (!d) {
1446  return QString();
1447  }
1448 
1449  switch (which) {
1451  return timeString(AccessTime);
1453  return timeString(CreationTime);
1455  default:
1456  return timeString(ModificationTime);
1457  }
1458 }
1459 #endif
1460 
1461 #if KIOCORE_BUILD_DEPRECATED_SINCE(4, 0)
1462 void KFileItem::assign(const KFileItem &item)
1463 {
1464  *this = item;
1465 }
1466 #endif
1467 
1468 QUrl KFileItem::mostLocalUrl(bool *local) const
1469 {
1470  if (!d) {
1471  return QUrl();
1472  }
1473 
1474  const QString local_path = localPath();
1475  if (!local_path.isEmpty()) {
1476  if (local) {
1477  *local = true;
1478  }
1479  return QUrl::fromLocalFile(local_path);
1480  } else {
1481  if (local) {
1482  *local = d->m_bIsLocalUrl;
1483  }
1484  return d->m_url;
1485  }
1486 }
1487 
1488 KFileItem::MostLocalUrlResult KFileItem::isMostLocalUrl() const
1489 {
1490  if (!d) {
1491  return {QUrl(), false};
1492  }
1493 
1494  const QString local_path = localPath();
1495  if (!local_path.isEmpty()) {
1496  return {QUrl::fromLocalFile(local_path), true};
1497  } else {
1498  return {d->m_url, d->m_bIsLocalUrl};
1499  }
1500 }
1501 
1502 QDataStream &operator<<(QDataStream &s, const KFileItem &a)
1503 {
1504  if (a.d) {
1505  // We don't need to save/restore anything that refresh() invalidates,
1506  // since that means we can re-determine those by ourselves.
1507  s << a.d->m_url;
1508  s << a.d->m_strName;
1509  s << a.d->m_strText;
1510  } else {
1511  s << QUrl();
1512  s << QString();
1513  s << QString();
1514  }
1515 
1516  return s;
1517 }
1518 
1519 QDataStream &operator>>(QDataStream &s, KFileItem &a)
1520 {
1521  QUrl url;
1522  QString strName;
1523  QString strText;
1524 
1525  s >> url;
1526  s >> strName;
1527  s >> strText;
1528 
1529  if (!a.d) {
1530  qCWarning(KIO_CORE) << "null item";
1531  return s;
1532  }
1533 
1534  if (url.isEmpty()) {
1535  a.d = nullptr;
1536  return s;
1537  }
1538 
1539  a.d->m_url = url;
1540  a.d->m_strName = strName;
1541  a.d->m_strText = strText;
1542  a.d->m_bIsLocalUrl = a.d->m_url.isLocalFile();
1543  a.d->m_bMimeTypeKnown = false;
1544  a.refresh();
1545 
1546  return s;
1547 }
1548 
1550 {
1551  if (!d) {
1552  return QUrl();
1553  }
1554 
1555  return d->m_url;
1556 }
1557 
1559 {
1560  if (!d) {
1561  return 0;
1562  }
1563 
1564  d->ensureInitialized();
1565 
1566  return d->m_permissions;
1567 }
1568 
1569 mode_t KFileItem::mode() const
1570 {
1571  if (!d) {
1572  return 0;
1573  }
1574 
1575  d->ensureInitialized();
1576 
1577  return d->m_fileMode;
1578 }
1579 
1580 bool KFileItem::isLink() const
1581 {
1582  if (!d) {
1583  return false;
1584  }
1585 
1586  d->ensureInitialized();
1587 
1588  return d->m_bLink;
1589 }
1590 
1592 {
1593  if (!d) {
1594  return false;
1595  }
1596 
1597  return d->m_bIsLocalUrl;
1598 }
1599 
1601 {
1602  if (!d) {
1603  return QString();
1604  }
1605 
1606  return d->m_strText;
1607 }
1608 
1609 QString KFileItem::name(bool lowerCase) const
1610 {
1611  if (!d) {
1612  return QString();
1613  }
1614 
1615  if (!lowerCase) {
1616  return d->m_strName;
1617  } else if (d->m_strLowerCaseName.isNull()) {
1618  d->m_strLowerCaseName = d->m_strName.toLower();
1619  }
1620  return d->m_strLowerCaseName;
1621 }
1622 
1624 {
1625  if (!d) {
1626  return QUrl();
1627  }
1628 
1629  const QString targetUrlStr = d->m_entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL);
1630  if (!targetUrlStr.isEmpty()) {
1631  return QUrl(targetUrlStr);
1632  } else {
1633  return url();
1634  }
1635 }
1636 
1637 /*
1638  * MIME type handling.
1639  *
1640  * Initial state: m_mimeType = QMimeType().
1641  * When currentMimeType() is called first: fast MIME type determination,
1642  * might either find an accurate MIME type (-> Final state), otherwise we
1643  * set m_mimeType but not m_bMimeTypeKnown (-> Intermediate state)
1644  * Intermediate state: determineMimeType() does the real determination -> Final state.
1645  *
1646  * If delayedMimeTypes isn't set, then we always go to the Final state directly.
1647  */
1648 
1650 {
1651  if (!d || d->m_url.isEmpty()) {
1652  return QMimeType();
1653  }
1654 
1655  if (!d->m_mimeType.isValid()) {
1656  // On-demand fast (but not always accurate) MIME type determination
1657  QMimeDatabase db;
1658  if (isDir()) {
1659  d->m_mimeType = db.mimeTypeForName(QStringLiteral("inode/directory"));
1660  return d->m_mimeType;
1661  }
1662  const QUrl url = mostLocalUrl();
1663  if (d->m_delayedMimeTypes) {
1664  const QList<QMimeType> mimeTypes = db.mimeTypesForFileName(url.path());
1665  if (mimeTypes.isEmpty()) {
1666  d->m_mimeType = db.mimeTypeForName(QStringLiteral("application/octet-stream"));
1667  d->m_bMimeTypeKnown = false;
1668  } else {
1669  d->m_mimeType = mimeTypes.first();
1670  // If there were conflicting globs. determineMimeType will be able to do better.
1671  d->m_bMimeTypeKnown = (mimeTypes.count() == 1);
1672  }
1673  } else {
1674  // ## d->m_fileMode isn't used anymore (for remote urls)
1675  d->determineMimeTypeHelper(url);
1676  d->m_bMimeTypeKnown = true;
1677  }
1678  }
1679  return d->m_mimeType;
1680 }
1681 
1683 {
1684  if (!d) {
1685  return KIO::UDSEntry();
1686  }
1687 
1688  d->ensureInitialized();
1689 
1690  return d->m_entry;
1691 }
1692 
1693 bool KFileItem::isNull() const
1694 {
1695  return d == nullptr;
1696 }
1697 
1699 {
1700 }
1701 
1703  : QList<KFileItem>(items)
1704 {
1705 }
1706 
1707 KFileItemList::KFileItemList(std::initializer_list<KFileItem> items)
1708  : QList<KFileItem>(items)
1709 {
1710 }
1711 
1713 {
1714  auto it = std::find_if(cbegin(), cend(), [&fileName](const KFileItem &item) {
1715  return item.name() == fileName;
1716  });
1717 
1718  return it != cend() ? *it : KFileItem();
1719 }
1720 
1722 {
1723  auto it = std::find_if(cbegin(), cend(), [&url](const KFileItem &item) {
1724  return item.url() == url;
1725  });
1726 
1727  return it != cend() ? *it : KFileItem();
1728 }
1729 
1731 {
1732  QList<QUrl> lst;
1733  lst.reserve(size());
1734 
1735  for (const auto &item : *this) {
1736  lst.append(item.url());
1737  }
1738  return lst;
1739 }
1740 
1742 {
1743  QList<QUrl> lst;
1744  lst.reserve(size());
1745 
1746  for (const auto &item : *this) {
1747  lst.append(item.targetUrl());
1748  }
1749  return lst;
1750 }
1751 
1753 {
1754  return checkDesktopFile(*this, true);
1755 }
1756 
1758 {
1759  if (!d) {
1760  return false;
1761  }
1762 
1763  d->ensureInitialized();
1764 
1765  return (d->m_fileMode & QT_STAT_MASK) == QT_STAT_REG;
1766 }
1767 
1768 QDebug operator<<(QDebug stream, const KFileItem &item)
1769 {
1770  QDebugStateSaver saver(stream);
1771  stream.nospace();
1772  if (item.isNull()) {
1773  stream << "[null KFileItem]";
1774  } else {
1775  stream << "[KFileItem for " << item.url() << "]";
1776  }
1777  return stream;
1778 }
An alternative URL (If different from the caption).
Definition: udsentry.h:276
QString next()
StripTrailingSlash
For folders, the recursize size of its content.
Definition: udsentry.h:334
qulonglong filesize_t
64-bit file size
Definition: global.h:39
bool isWritable() const
Checks whether the file or directory is writable.
Definition: kfileitem.cpp:1224
KFileItemList()
Creates an empty list of file items.
Definition: kfileitem.cpp:1698
void setUrl(const QUrl &url)
Sets the item&#39;s URL.
Definition: kfileitem.cpp:653
This file is a shortcut or mount, pointing to an URL in a different hierarchy.
Definition: udsentry.h:301
void setDelayedMimeTypes(bool b)
Sets MIME type determination to be immediate or on demand.
Definition: kfileitem.cpp:645
bool isDir() const
Returns true if this item represents a directory.
Definition: kfileitem.cpp:1281
FileTimes
The timestamps associated with a file.
Definition: kfileitem.h:46
QList< QMimeType > mimeTypesForFileName(const QString &fileName) const const
QString toString(qlonglong i) const const
QString name() const
KCOREADDONS_EXPORT Type fileSystemType(const QString &path)
QString getStatusBarInfo() const
Returns the string to be displayed in the statusbar, e.g.
Definition: kfileitem.cpp:1336
Device number for this file, used to detect hardlinks.
Definition: udsentry.h:327
Universal Directory Service.
Definition: udsentry.h:77
QString mimetype() const
Returns the MIME type of the file item.
Definition: kfileitem.cpp:845
QString user() const
Returns the owner of the file.
Definition: kfileitem.cpp:804
The access control list serialized into a single string.
Definition: udsentry.h:289
A namespace for KIO globals.
static List currentMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
Returns a list of all current mountpoints.
void setLocalPath(const QString &path)
Sets the item&#39;s local path (UDS_LOCAL_PATH).
Definition: kfileitem.cpp:664
QList< QUrl > targetUrlList() const
Definition: kfileitem.cpp:1741
void reserve(int alloc)
bool isNull() const
Return true if default-constructed.
Definition: kfileitem.cpp:1693
bool isFinalIconKnown() const
Definition: kfileitem.cpp:917
The default access control list serialized into a single string.
Definition: udsentry.h:292
void refresh()
Throw away and re-read (for local files) all information about the file.
Definition: kfileitem.cpp:609
File type, part of the mode returned by stat (for a link, this returns the file type of the pointed i...
Definition: udsentry.h:267
Ptr findByDevice(const QString &device) const
Returns the mount point associated with device, i.e.
QDebug & nospace()
bool inherits(const QString &mimeTypeName) const const
static KSambaShare * instance()
QString fileName() const const
A local file path if the ioslave display files sitting on the local filesystem (but in another hierar...
Definition: udsentry.h:252
QString comment() const
A comment which can contain anything - even rich text.
Definition: kfileitem.cpp:1178
void setName(const QString &name)
Sets the item&#39;s name (i.e.
Definition: kfileitem.cpp:674
mode_t permissions() const
Returns the permissions of the file (stat.st_mode containing only permissions).
Definition: kfileitem.cpp:1558
bool operator!=(const KFileItem &other) const
Returns true if both items do not share the same URL.
Definition: kfileitem.cpp:1388
QUrl targetUrl() const
Returns the target url of the file, which is the same as url() in cases where the slave doesn&#39;t speci...
Definition: kfileitem.cpp:1623
bool isReadable() const
Checks whether the file or directory is readable.
Definition: kfileitem.cpp:1187
KIOCORE_EXPORT QString convertSize(KIO::filesize_t size)
Converts size from bytes to the string representation.
Definition: global.cpp:43
KFileItem()
Null KFileItem.
Definition: kfileitem.cpp:558
QDateTime fromMSecsSinceEpoch(qint64 msecs)
Treat the file as a hidden file (if set to 1) or as a normal file (if set to 0).
Definition: udsentry.h:255
int size() const const
QDateTime time(FileTimes which) const
Requests the modification, access or creation time, depending on which.
Definition: kfileitem.cpp:795
QLocale system()
27 was used by the now removed UDS_NEPOMUK_QUERY
Definition: udsentry.h:323
User-readable type of file (if not specified, the MIME type&#39;s description is used) ...
Definition: udsentry.h:306
A MIME type to be used for displaying only.
Definition: udsentry.h:282
KIO::filesize_t recursiveSize() const
For folders, its recursive size: the size of its files plus the recursiveSize of its folder...
Definition: kfileitem.cpp:743
QMimeType mimeTypeForFile(const QString &fileName, QMimeDatabase::MatchMode mode) const const
static bool isAuthorizedDesktopFile(const QString &path)
bool isLocalFile() const
Returns true if the file is a local file.
Definition: kfileitem.cpp:1591
void setPath(const QString &path, QUrl::ParsingMode mode)
QMimeType determineMimeType() const
Returns the MIME type of the file item.
Definition: kfileitem.cpp:855
bool isRegularFile() const
Return true if this item is a regular file, false otherwise (directory, link, character/block device...
Definition: kfileitem.cpp:1757
User ID of the file owner.
Definition: udsentry.h:234
KACL ACL() const
Returns the access control list for the file.
Definition: kfileitem.cpp:762
int count(const T &value) const const
int count() const
count fields
Definition: udsentry.cpp:445
void append(const T &value)
PartitionTable::TableType type
QString readDevice() const
KFileItem findByName(const QString &fileName) const
Find a KFileItem by name and return it.
Definition: kfileitem.cpp:1712
long long numberValue(uint field, long long defaultValue=0) const
Definition: udsentry.cpp:379
QMimeType mimeTypeForUrl(const QUrl &url) const const
bool hasDeviceType() const
void assign(const KFileItem &item)
Definition: kfileitem.cpp:1462
QString loginName() const
QString symLinkTarget() const const
bool isEmpty() const const
QString localPath() const
Returns the local path if isLocalFile() == true or the KIO item has a UDS_LOCAL_PATH atom...
Definition: kfileitem.cpp:725
QString linkDest() const
Returns the link destination if isLink() == true.
Definition: kfileitem.cpp:692
bool isEmpty() const const
const char * constData() const const
The last time the file was opened. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:261
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QMimeType currentMimeType() const
Returns the currently known MIME type of the file item.
Definition: kfileitem.cpp:1649
QString stringValue(uint field) const
Definition: udsentry.cpp:374
QString path(QUrl::ComponentFormattingOptions options) const const
QString mimeComment() const
Returns the user-readable string representing the type of this file, like "OpenDocument Text File"...
Definition: kfileitem.cpp:926
bool acceptsDrops() const
Returns true if files can be dropped over this item.
Definition: kfileitem.cpp:1311
KIOCORE_EXPORT QString decodeFileName(const QString &str)
Decodes (from the filename to the text displayed) This doesn&#39;t do anything anymore, it used to do the opposite of encodeFileName when encodeFileName was using %2F for &#39;/&#39;.
Definition: global.cpp:146
~KFileItem()
Destructor.
T & first()
bool operator==(const KFileItem &other) const
Returns true if both items share the same URL.
Definition: kfileitem.cpp:1375
bool isFile() const
Returns true if this item represents a file (and not a directory)
Definition: kfileitem.cpp:1301
QString group() const
Returns the group of the file.
Definition: kfileitem.cpp:813
bool operator<(const KFileItem &other) const
Returns true if this item&#39;s URL is lexically less than other&#39;s URL; otherwise returns false...
Definition: kfileitem.cpp:1393
QString readUrl() const
KIO::filesize_t size() const
Returns the size of the file, if known.
Definition: kfileitem.cpp:734
QString iconName() const
Returns the full path name to the icon that represents this MIME type.
Definition: kfileitem.cpp:1028
QString scheme() const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QString permissionsString() const
Returns the access permissions for the file as a string.
Definition: kfileitem.cpp:1417
void refreshMimeType()
Re-reads MIME type information.
Definition: kfileitem.cpp:634
QList< QUrl > urlList() const
Definition: kfileitem.cpp:1730
Inode number for this file, used to detect hardlinks.
Definition: udsentry.h:330
QString toLocalFile() const const
The last time the file was modified. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:259
bool hasLinkType() const
QString text() const
Returns the text of the file item.
Definition: kfileitem.cpp:1600
bool isDesktopFile() const
Checks whether the file is a readable local .desktop file, i.e.
Definition: kfileitem.cpp:1752
bool isLink() const
Returns true if this item represents a link in the UNIX sense of a link.
Definition: kfileitem.cpp:1580
SkipEmptyParts
25 was used by the now removed UDS_NEPOMUK_URI
Definition: udsentry.h:315
bool contains(uint field) const
check existence of a field
Definition: udsentry.cpp:450
QVariant fromValue(const T &value)
QCA_EXPORT void init()
bool hasKey(const QString &key) const
QString i18n(const char *text, const TYPE &arg...)
KConfigGroup group(const QString &group)
QList::const_iterator cend() const const
bool isValid() const const
bool hasExtendedACL() const
Tells if the file has extended access level information ( Posix ACL )
Definition: kfileitem.cpp:752
QList::const_iterator cbegin() const const
Access permissions (part of the mode returned by stat)
Definition: udsentry.h:257
KACL defaultACL() const
Returns the default access control list for the directory.
Definition: kfileitem.cpp:780
QList< KFileItem > & operator<<(const KFileItem &value)
qint64 toSecsSinceEpoch() const const
QString name(bool lowerCase=false) const
Return the name of the file item (without a path).
Definition: kfileitem.cpp:1609
KFileItem findByUrl(const QUrl &url) const
Find a KFileItem by URL and return it.
Definition: kfileitem.cpp:1721
Filename - as displayed in directory listings etc.
Definition: udsentry.h:249
The KACL class encapsulates a POSIX Access Control List.
Definition: kacl.h:35
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Name of the file where the link points to Allows to check for a symlink (don&#39;t use S_ISLNK !) ...
Definition: udsentry.h:270
QUrl mostLocalUrl(bool *local=nullptr) const
Tries to give a local URL for this file item if possible.
Definition: kfileitem.cpp:1468
bool cmp(const KFileItem &item) const
Somewhat like a comparison operator, but more explicit, and it can detect that two fileitems differ i...
Definition: kfileitem.cpp:1362
The time the file was created. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:263
bool isHidden() const
Checks whether the file is hidden.
Definition: kfileitem.cpp:1255
int length() const const
Group ID of the file owner.
Definition: udsentry.h:239
MostLocalUrlResult isMostLocalUrl() const
Returns a MostLocalUrlResult, with the local Url for this item if possible (otherwise an empty Url)...
Definition: kfileitem.cpp:1488
QString timeString(FileTimes which=ModificationTime) const
Requests the modification, access or creation time as a string, depending on which.
Definition: kfileitem.cpp:1433
If set, contains the label to display instead of the &#39;real name&#39; in UDS_NAME.
Definition: udsentry.h:297
QString readIcon() const
QString fromLatin1(const char *str, int size)
static bool supportsWriting(const QUrl &url)
Returns whether the protocol can store data to URLs.
mode_t mode() const
Returns the file type (stat.st_mode containing only S_IFDIR, S_IFLNK, ...).
Definition: kfileitem.cpp:1569
Indicates that the entry has extended ACL entries.
Definition: udsentry.h:287
QDateTime toLocalTime() const const
A MIME type; the slave should set it if it&#39;s known.
Definition: udsentry.h:278
QUrl url() const
Returns the url of the file.
Definition: kfileitem.cpp:1549
bool isMimeTypeKnown() const
Definition: kfileitem.cpp:887
KFileItem & operator=(const KFileItem &)
Copy assignment.
bool isSlow() const
Definition: kfileitem.cpp:836
KIO::UDSEntry entry() const
Returns the UDS entry.
Definition: kfileitem.cpp:1682
static KNFSShare * instance()
Returns the one and only instance of KNFSShare.
Definition: knfsshare.cpp:215
bool hasNext() const const
T readEntry(const QString &key, const T &aDefault) const
Size of the file.
Definition: udsentry.h:230
QString fileName(QUrl::ComponentFormattingOptions options) const const
QStringList overlays() const
Returns the overlays (bitfield of KIconLoader::*Overlay flags) that are used for this item&#39;s pixmap...
Definition: kfileitem.cpp:1115
QByteArray encodeName(const QString &fileName)
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:35
QStringView mid(qsizetype start) const const
QUrl fromLocalFile(const QString &localFile)
Name of the icon, that should be used for displaying.
Definition: udsentry.h:237
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Nov 29 2021 22:53:07 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.