1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qplatformdefs.h"
41#include "qfileinfo.h"
42#include "qglobal.h"
43#include "qdir.h"
44#include "qfileinfo_p.h"
45#include "qdebug.h"
46
47QT_BEGIN_NAMESPACE
48
49QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
50{
51 if (cache_enabled && !fileNames[(int)name].isNull())
52 return fileNames[(int)name];
53
54 QString ret;
55 if (fileEngine == nullptr) { // local file; use the QFileSystemEngine directly
56 switch (name) {
57 case QAbstractFileEngine::CanonicalName:
58 case QAbstractFileEngine::CanonicalPathName: {
59 QFileSystemEntry entry = QFileSystemEngine::canonicalName(fileEntry, metaData);
60 if (cache_enabled) { // be smart and store both
61 fileNames[QAbstractFileEngine::CanonicalName] = entry.filePath();
62 fileNames[QAbstractFileEngine::CanonicalPathName] = entry.path();
63 }
64 if (name == QAbstractFileEngine::CanonicalName)
65 ret = entry.filePath();
66 else
67 ret = entry.path();
68 break;
69 }
70 case QAbstractFileEngine::LinkName:
71 ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
72 break;
73 case QAbstractFileEngine::BundleName:
74 ret = QFileSystemEngine::bundleName(fileEntry);
75 break;
76 case QAbstractFileEngine::AbsoluteName:
77 case QAbstractFileEngine::AbsolutePathName: {
78 QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry);
79 if (cache_enabled) { // be smart and store both
80 fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath();
81 fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path();
82 }
83 if (name == QAbstractFileEngine::AbsoluteName)
84 ret = entry.filePath();
85 else
86 ret = entry.path();
87 break;
88 }
89 default: break;
90 }
91 } else {
92 ret = fileEngine->fileName(name);
93 }
94 if (ret.isNull())
95 ret = QLatin1String("");
96 if (cache_enabled)
97 fileNames[(int)name] = ret;
98 return ret;
99}
100
101QString QFileInfoPrivate::getFileOwner(QAbstractFileEngine::FileOwner own) const
102{
103 if (cache_enabled && !fileOwners[(int)own].isNull())
104 return fileOwners[(int)own];
105 QString ret;
106 if (fileEngine == nullptr) {
107 switch (own) {
108 case QAbstractFileEngine::OwnerUser:
109 ret = QFileSystemEngine::resolveUserName(fileEntry, metaData);
110 break;
111 case QAbstractFileEngine::OwnerGroup:
112 ret = QFileSystemEngine::resolveGroupName(fileEntry, metaData);
113 break;
114 }
115 } else {
116 ret = fileEngine->owner(own);
117 }
118 if (ret.isNull())
119 ret = QLatin1String("");
120 if (cache_enabled)
121 fileOwners[(int)own] = ret;
122 return ret;
123}
124
125uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) const
126{
127 Q_ASSERT(fileEngine); // should never be called when using the native FS
128 // We split the testing into tests for for LinkType, BundleType, PermsMask
129 // and the rest.
130 // Tests for file permissions on Windows can be slow, expecially on network
131 // paths and NTFS drives.
132 // In order to determine if a file is a symlink or not, we have to lstat().
133 // If we're not interested in that information, we might as well avoid one
134 // extra syscall. Bundle detecton on Mac can be slow, expecially on network
135 // paths, so we separate out that as well.
136
137 QAbstractFileEngine::FileFlags req = nullptr;
138 uint cachedFlags = 0;
139
140 if (request & (QAbstractFileEngine::FlagsMask | QAbstractFileEngine::TypesMask)) {
141 if (!getCachedFlag(CachedFileFlags)) {
142 req |= QAbstractFileEngine::FlagsMask;
143 req |= QAbstractFileEngine::TypesMask;
144 req &= (~QAbstractFileEngine::LinkType);
145 req &= (~QAbstractFileEngine::BundleType);
146
147 cachedFlags |= CachedFileFlags;
148 }
149
150 if (request & QAbstractFileEngine::LinkType) {
151 if (!getCachedFlag(CachedLinkTypeFlag)) {
152 req |= QAbstractFileEngine::LinkType;
153 cachedFlags |= CachedLinkTypeFlag;
154 }
155 }
156
157 if (request & QAbstractFileEngine::BundleType) {
158 if (!getCachedFlag(CachedBundleTypeFlag)) {
159 req |= QAbstractFileEngine::BundleType;
160 cachedFlags |= CachedBundleTypeFlag;
161 }
162 }
163 }
164
165 if (request & QAbstractFileEngine::PermsMask) {
166 if (!getCachedFlag(CachedPerms)) {
167 req |= QAbstractFileEngine::PermsMask;
168 cachedFlags |= CachedPerms;
169 }
170 }
171
172 if (req) {
173 if (cache_enabled)
174 req &= (~QAbstractFileEngine::Refresh);
175 else
176 req |= QAbstractFileEngine::Refresh;
177
178 QAbstractFileEngine::FileFlags flags = fileEngine->fileFlags(req);
179 fileFlags |= uint(flags);
180 setCachedFlag(cachedFlags);
181 }
182
183 return fileFlags & request;
184}
185
186QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const
187{
188 Q_ASSERT(fileEngine); // should never be called when using the native FS
189 if (!cache_enabled)
190 clearFlags();
191
192 uint cf = 0;
193 switch (request) {
194 case QAbstractFileEngine::AccessTime:
195 cf = CachedATime;
196 break;
197 case QAbstractFileEngine::BirthTime:
198 cf = CachedBTime;
199 break;
200 case QAbstractFileEngine::MetadataChangeTime:
201 cf = CachedMCTime;
202 break;
203 case QAbstractFileEngine::ModificationTime:
204 cf = CachedMTime;
205 break;
206 }
207
208 if (!getCachedFlag(cf)) {
209 fileTimes[request] = fileEngine->fileTime(request);
210 setCachedFlag(cf);
211 }
212 return fileTimes[request];
213}
214
215//************* QFileInfo
216
217/*!
218 \class QFileInfo
219 \inmodule QtCore
220 \reentrant
221 \brief The QFileInfo class provides system-independent file information.
222
223 \ingroup io
224 \ingroup shared
225
226 QFileInfo provides information about a file's name and position
227 (path) in the file system, its access rights and whether it is a
228 directory or symbolic link, etc. The file's size and last
229 modified/read times are also available. QFileInfo can also be
230 used to obtain information about a Qt \l{resource
231 system}{resource}.
232
233 A QFileInfo can point to a file with either a relative or an
234 absolute file path. Absolute file paths begin with the directory
235 separator "/" (or with a drive specification on Windows). Relative
236 file names begin with a directory name or a file name and specify
237 a path relative to the current working directory. An example of an
238 absolute path is the string "/tmp/quartz". A relative path might
239 look like "src/fatlib". You can use the function isRelative() to
240 check whether a QFileInfo is using a relative or an absolute file
241 path. You can call the function makeAbsolute() to convert a
242 relative QFileInfo's path to an absolute path.
243
244 The file that the QFileInfo works on is set in the constructor or
245 later with setFile(). Use exists() to see if the file exists and
246 size() to get its size.
247
248 The file's type is obtained with isFile(), isDir() and
249 isSymLink(). The symLinkTarget() function provides the name of the file
250 the symlink points to.
251
252 On Unix (including \macos and iOS), the symlink has the same size() has
253 the file it points to, because Unix handles symlinks
254 transparently; similarly, opening a symlink using QFile
255 effectively opens the link's target. For example:
256
257 \snippet code/src_corelib_io_qfileinfo.cpp 0
258
259 On Windows, symlinks (shortcuts) are \c .lnk files. The reported
260 size() is that of the symlink (not the link's target), and
261 opening a symlink using QFile opens the \c .lnk file. For
262 example:
263
264 \snippet code/src_corelib_io_qfileinfo.cpp 1
265
266 Elements of the file's name can be extracted with path() and
267 fileName(). The fileName()'s parts can be extracted with
268 baseName(), suffix() or completeSuffix(). QFileInfo objects to
269 directories created by Qt classes will not have a trailing file
270 separator. If you wish to use trailing separators in your own file
271 info objects, just append one to the file name given to the constructors
272 or setFile().
273
274 The file's dates are returned by created(), lastModified(), lastRead() and
275 fileTime(). Information about the file's access permissions is
276 obtained with isReadable(), isWritable() and isExecutable(). The
277 file's ownership is available from owner(), ownerId(), group() and
278 groupId(). You can examine a file's permissions and ownership in a
279 single statement using the permission() function.
280
281 \target NTFS permissions
282 \note On NTFS file systems, ownership and permissions checking is
283 disabled by default for performance reasons. To enable it,
284 include the following line:
285
286 \snippet ntfsp.cpp 0
287
288 Permission checking is then turned on and off by incrementing and
289 decrementing \c qt_ntfs_permission_lookup by 1.
290
291 \snippet ntfsp.cpp 1
292
293 \section1 Performance Issues
294
295 Some of QFileInfo's functions query the file system, but for
296 performance reasons, some functions only operate on the
297 file name itself. For example: To return the absolute path of
298 a relative file name, absolutePath() has to query the file system.
299 The path() function, however, can work on the file name directly,
300 and so it is faster.
301
302 \note To speed up performance, QFileInfo caches information about
303 the file.
304
305 Because files can be changed by other users or programs, or
306 even by other parts of the same program, there is a function that
307 refreshes the file information: refresh(). If you want to switch
308 off a QFileInfo's caching and force it to access the file system
309 every time you request information from it call setCaching(false).
310
311 \sa QDir, QFile
312*/
313
314/*!
315 \fn QFileInfo &QFileInfo::operator=(QFileInfo &&other)
316
317 Move-assigns \a other to this QFileInfo instance.
318
319 \since 5.2
320*/
321
322/*!
323 \internal
324*/
325QFileInfo::QFileInfo(QFileInfoPrivate *p) : d_ptr(p)
326{
327}
328
329/*!
330 Constructs an empty QFileInfo object.
331
332 Note that an empty QFileInfo object contain no file reference.
333
334 \sa setFile()
335*/
336QFileInfo::QFileInfo() : d_ptr(new QFileInfoPrivate())
337{
338}
339
340/*!
341 Constructs a new QFileInfo that gives information about the given
342 file. The \a file can also include an absolute or relative path.
343
344 \sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
345*/
346QFileInfo::QFileInfo(const QString &file) : d_ptr(new QFileInfoPrivate(file))
347{
348}
349
350/*!
351 Constructs a new QFileInfo that gives information about file \a
352 file.
353
354 If the \a file has a relative path, the QFileInfo will also have a
355 relative path.
356
357 \sa isRelative()
358*/
359QFileInfo::QFileInfo(const QFile &file) : d_ptr(new QFileInfoPrivate(file.fileName()))
360{
361}
362
363/*!
364 Constructs a new QFileInfo that gives information about the given
365 \a file in the directory \a dir.
366
367 If \a dir has a relative path, the QFileInfo will also have a
368 relative path.
369
370 If \a file is an absolute path, then the directory specified
371 by \a dir will be disregarded.
372
373 \sa isRelative()
374*/
375QFileInfo::QFileInfo(const QDir &dir, const QString &file)
376 : d_ptr(new QFileInfoPrivate(dir.filePath(file)))
377{
378}
379
380/*!
381 Constructs a new QFileInfo that is a copy of the given \a fileinfo.
382*/
383QFileInfo::QFileInfo(const QFileInfo &fileinfo)
384 : d_ptr(fileinfo.d_ptr)
385{
386
387}
388
389/*!
390 Destroys the QFileInfo and frees its resources.
391*/
392
393QFileInfo::~QFileInfo()
394{
395}
396
397/*!
398 \fn bool QFileInfo::operator!=(const QFileInfo &fileinfo) const
399
400 Returns \c true if this QFileInfo object refers to a different file
401 than the one specified by \a fileinfo; otherwise returns \c false.
402
403 \sa operator==()
404*/
405
406/*!
407 Returns \c true if this QFileInfo object refers to a file in the same
408 location as \a fileinfo; otherwise returns \c false.
409
410 Note that the result of comparing two empty QFileInfo objects,
411 containing no file references (file paths that do not exist or
412 are empty), is undefined.
413
414 \warning This will not compare two different symbolic links
415 pointing to the same file.
416
417 \warning Long and short file names that refer to the same file on Windows
418 are treated as if they referred to different files.
419
420 \sa operator!=()
421*/
422bool QFileInfo::operator==(const QFileInfo &fileinfo) const
423{
424 Q_D(const QFileInfo);
425 // ### Qt 5: understand long and short file names on Windows
426 // ### (GetFullPathName()).
427 if (fileinfo.d_ptr == d_ptr)
428 return true;
429 if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed)
430 return false;
431
432 // Assume files are the same if path is the same
433 if (d->fileEntry.filePath() == fileinfo.d_ptr->fileEntry.filePath())
434 return true;
435
436 Qt::CaseSensitivity sensitive;
437 if (d->fileEngine == nullptr || fileinfo.d_ptr->fileEngine == nullptr) {
438 if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine
439 return false;
440
441 sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
442 } else {
443 if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive())
444 return false;
445 sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
446 }
447
448 // Fallback to expensive canonical path computation
449 return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0;
450}
451
452/*!
453 Makes a copy of the given \a fileinfo and assigns it to this QFileInfo.
454*/
455QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo)
456{
457 d_ptr = fileinfo.d_ptr;
458 return *this;
459}
460
461/*!
462 \fn void QFileInfo::swap(QFileInfo &other)
463 \since 5.0
464
465 Swaps this file info with \a other. This function is very fast and
466 never fails.
467*/
468
469/*!
470 Sets the file that the QFileInfo provides information about to \a
471 file.
472
473 The \a file can also include an absolute or relative file path.
474 Absolute paths begin with the directory separator (e.g. "/" under
475 Unix) or a drive specification (under Windows). Relative file
476 names begin with a directory name or a file name and specify a
477 path relative to the current directory.
478
479 Example:
480 \snippet code/src_corelib_io_qfileinfo.cpp 2
481
482 \sa isRelative(), QDir::setCurrent(), QDir::isRelativePath()
483*/
484void QFileInfo::setFile(const QString &file)
485{
486 bool caching = d_ptr.constData()->cache_enabled;
487 *this = QFileInfo(file);
488 d_ptr->cache_enabled = caching;
489}
490
491/*!
492 \overload
493
494 Sets the file that the QFileInfo provides information about to \a
495 file.
496
497 If \a file includes a relative path, the QFileInfo will also have
498 a relative path.
499
500 \sa isRelative()
501*/
502void QFileInfo::setFile(const QFile &file)
503{
504 setFile(file.fileName());
505}
506
507/*!
508 \overload
509
510 Sets the file that the QFileInfo provides information about to \a
511 file in directory \a dir.
512
513 If \a file includes a relative path, the QFileInfo will also
514 have a relative path.
515
516 \sa isRelative()
517*/
518void QFileInfo::setFile(const QDir &dir, const QString &file)
519{
520 setFile(dir.filePath(file));
521}
522
523/*!
524 Returns an absolute path including the file name.
525
526 The absolute path name consists of the full path and the file
527 name. On Unix this will always begin with the root, '/',
528 directory. On Windows this will always begin 'D:/' where D is a
529 drive letter, except for network shares that are not mapped to a
530 drive letter, in which case the path will begin '//sharename/'.
531 QFileInfo will uppercase drive letters. Note that QDir does not do
532 this. The code snippet below shows this.
533
534 \snippet code/src_corelib_io_qfileinfo.cpp newstuff
535
536 This function returns the same as filePath(), unless isRelative()
537 is true. In contrast to canonicalFilePath(), symbolic links or
538 redundant "." or ".." elements are not necessarily removed.
539
540 \warning If filePath() is empty the behavior of this function
541 is undefined.
542
543 \sa filePath(), canonicalFilePath(), isRelative()
544*/
545QString QFileInfo::absoluteFilePath() const
546{
547 Q_D(const QFileInfo);
548 if (d->isDefaultConstructed)
549 return QLatin1String("");
550 return d->getFileName(QAbstractFileEngine::AbsoluteName);
551}
552
553/*!
554 Returns the canonical path including the file name, i.e. an absolute
555 path without symbolic links or redundant "." or ".." elements.
556
557 If the file does not exist, canonicalFilePath() returns an empty
558 string.
559
560 \sa filePath(), absoluteFilePath(), dir()
561*/
562QString QFileInfo::canonicalFilePath() const
563{
564 Q_D(const QFileInfo);
565 if (d->isDefaultConstructed)
566 return QLatin1String("");
567 return d->getFileName(QAbstractFileEngine::CanonicalName);
568}
569
570
571/*!
572 Returns a file's path absolute path. This doesn't include the
573 file name.
574
575 On Unix the absolute path will always begin with the root, '/',
576 directory. On Windows this will always begin 'D:/' where D is a
577 drive letter, except for network shares that are not mapped to a
578 drive letter, in which case the path will begin '//sharename/'.
579
580 In contrast to canonicalPath() symbolic links or redundant "." or
581 ".." elements are not necessarily removed.
582
583 \warning If filePath() is empty the behavior of this function
584 is undefined.
585
586 \sa absoluteFilePath(), path(), canonicalPath(), fileName(), isRelative()
587*/
588QString QFileInfo::absolutePath() const
589{
590 Q_D(const QFileInfo);
591
592 if (d->isDefaultConstructed) {
593 return QLatin1String("");
594 }
595 return d->getFileName(QAbstractFileEngine::AbsolutePathName);
596}
597
598/*!
599 Returns the file's path canonical path (excluding the file name),
600 i.e. an absolute path without symbolic links or redundant "." or ".." elements.
601
602 If the file does not exist, canonicalPath() returns an empty string.
603
604 \sa path(), absolutePath()
605*/
606QString QFileInfo::canonicalPath() const
607{
608 Q_D(const QFileInfo);
609 if (d->isDefaultConstructed)
610 return QLatin1String("");
611 return d->getFileName(QAbstractFileEngine::CanonicalPathName);
612}
613
614/*!
615 Returns the file's path. This doesn't include the file name.
616
617 Note that, if this QFileInfo object is given a path ending in a
618 slash, the name of the file is considered empty and this function
619 will return the entire path.
620
621 \sa filePath(), absolutePath(), canonicalPath(), dir(), fileName(), isRelative()
622*/
623QString QFileInfo::path() const
624{
625 Q_D(const QFileInfo);
626 if (d->isDefaultConstructed)
627 return QLatin1String("");
628 return d->fileEntry.path();
629}
630
631/*!
632 \fn bool QFileInfo::isAbsolute() const
633
634 Returns \c true if the file path name is absolute, otherwise returns
635 false if the path is relative.
636
637 \sa isRelative()
638*/
639
640/*!
641 Returns \c true if the file path name is relative, otherwise returns
642 false if the path is absolute (e.g. under Unix a path is absolute
643 if it begins with a "/").
644
645 \sa isAbsolute()
646*/
647bool QFileInfo::isRelative() const
648{
649 Q_D(const QFileInfo);
650 if (d->isDefaultConstructed)
651 return true;
652 if (d->fileEngine == nullptr)
653 return d->fileEntry.isRelative();
654 return d->fileEngine->isRelativePath();
655}
656
657/*!
658 Converts the file's path to an absolute path if it is not already in that form.
659 Returns \c true to indicate that the path was converted; otherwise returns \c false
660 to indicate that the path was already absolute.
661
662 \sa filePath(), isRelative()
663*/
664bool QFileInfo::makeAbsolute()
665{
666 if (d_ptr.constData()->isDefaultConstructed
667 || !d_ptr.constData()->fileEntry.isRelative())
668 return false;
669
670 setFile(absoluteFilePath());
671 return true;
672}
673
674/*!
675 Returns \c true if the file exists; otherwise returns \c false.
676
677 \note If the file is a symlink that points to a non-existing
678 file, false is returned.
679*/
680bool QFileInfo::exists() const
681{
682 Q_D(const QFileInfo);
683 if (d->isDefaultConstructed)
684 return false;
685 if (d->fileEngine == nullptr) {
686 if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute))
687 QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute);
688 return d->metaData.exists();
689 }
690 return d->getFileFlags(QAbstractFileEngine::ExistsFlag);
691}
692
693/*!
694 \since 5.2
695
696 Returns \c true if the \a file exists; otherwise returns \c false.
697
698 \note If \a file is a symlink that points to a non-existing
699 file, false is returned.
700
701 \note Using this function is faster than using
702 \c QFileInfo(file).exists() for file system access.
703*/
704bool QFileInfo::exists(const QString &file)
705{
706 if (file.isEmpty())
707 return false;
708 QFileSystemEntry entry(file);
709 QFileSystemMetaData data;
710 std::unique_ptr<QAbstractFileEngine> engine
711 {QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, data)};
712 // Expensive fallback to non-QFileSystemEngine implementation
713 if (engine)
714 return QFileInfo(new QFileInfoPrivate(entry, data, std::move(engine))).exists();
715
716 QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
717 return data.exists();
718}
719
720/*!
721 Refreshes the information about the file, i.e. reads in information
722 from the file system the next time a cached property is fetched.
723*/
724void QFileInfo::refresh()
725{
726 Q_D(QFileInfo);
727 d->clear();
728}
729
730/*!
731 Returns the file name, including the path (which may be absolute
732 or relative).
733
734 \sa absoluteFilePath(), canonicalFilePath(), isRelative()
735*/
736QString QFileInfo::filePath() const
737{
738 Q_D(const QFileInfo);
739 if (d->isDefaultConstructed)
740 return QLatin1String("");
741 return d->fileEntry.filePath();
742}
743
744/*!
745 Returns the name of the file, excluding the path.
746
747 Example:
748 \snippet code/src_corelib_io_qfileinfo.cpp 3
749
750 Note that, if this QFileInfo object is given a path ending in a
751 slash, the name of the file is considered empty.
752
753 \sa isRelative(), filePath(), baseName(), suffix()
754*/
755QString QFileInfo::fileName() const
756{
757 Q_D(const QFileInfo);
758 if (d->isDefaultConstructed)
759 return QLatin1String("");
760 return d->fileEntry.fileName();
761}
762
763/*!
764 \since 4.3
765 Returns the name of the bundle.
766
767 On \macos and iOS this returns the proper localized name for a bundle if the
768 path isBundle(). On all other platforms an empty QString is returned.
769
770 Example:
771 \snippet code/src_corelib_io_qfileinfo.cpp 4
772
773 \sa isBundle(), filePath(), baseName(), suffix()
774*/
775QString QFileInfo::bundleName() const
776{
777 Q_D(const QFileInfo);
778 if (d->isDefaultConstructed)
779 return QLatin1String("");
780 return d->getFileName(QAbstractFileEngine::BundleName);
781}
782
783/*!
784 Returns the base name of the file without the path.
785
786 The base name consists of all characters in the file up to (but
787 not including) the \e first '.' character.
788
789 Example:
790 \snippet code/src_corelib_io_qfileinfo.cpp 5
791
792
793 The base name of a file is computed equally on all platforms, independent
794 of file naming conventions (e.g., ".bashrc" on Unix has an empty base
795 name, and the suffix is "bashrc").
796
797 \sa fileName(), suffix(), completeSuffix(), completeBaseName()
798*/
799QString QFileInfo::baseName() const
800{
801 Q_D(const QFileInfo);
802 if (d->isDefaultConstructed)
803 return QLatin1String("");
804 return d->fileEntry.baseName();
805}
806
807/*!
808 Returns the complete base name of the file without the path.
809
810 The complete base name consists of all characters in the file up
811 to (but not including) the \e last '.' character.
812
813 Example:
814 \snippet code/src_corelib_io_qfileinfo.cpp 6
815
816 \sa fileName(), suffix(), completeSuffix(), baseName()
817*/
818QString QFileInfo::completeBaseName() const
819{
820 Q_D(const QFileInfo);
821 if (d->isDefaultConstructed)
822 return QLatin1String("");
823 return d->fileEntry.completeBaseName();
824}
825
826/*!
827 Returns the complete suffix (extension) of the file.
828
829 The complete suffix consists of all characters in the file after
830 (but not including) the first '.'.
831
832 Example:
833 \snippet code/src_corelib_io_qfileinfo.cpp 7
834
835 \sa fileName(), suffix(), baseName(), completeBaseName()
836*/
837QString QFileInfo::completeSuffix() const
838{
839 Q_D(const QFileInfo);
840 if (d->isDefaultConstructed)
841 return QLatin1String("");
842 return d->fileEntry.completeSuffix();
843}
844
845/*!
846 Returns the suffix (extension) of the file.
847
848 The suffix consists of all characters in the file after (but not
849 including) the last '.'.
850
851 Example:
852 \snippet code/src_corelib_io_qfileinfo.cpp 8
853
854 The suffix of a file is computed equally on all platforms, independent of
855 file naming conventions (e.g., ".bashrc" on Unix has an empty base name,
856 and the suffix is "bashrc").
857
858 \sa fileName(), completeSuffix(), baseName(), completeBaseName()
859*/
860QString QFileInfo::suffix() const
861{
862 Q_D(const QFileInfo);
863 if (d->isDefaultConstructed)
864 return QLatin1String("");
865 return d->fileEntry.suffix();
866}
867
868
869/*!
870 Returns the path of the object's parent directory as a QDir object.
871
872 \b{Note:} The QDir returned always corresponds to the object's
873 parent directory, even if the QFileInfo represents a directory.
874
875 For each of the following, dir() returns the QDir
876 \c{"~/examples/191697"}.
877
878 \snippet fileinfo/main.cpp 0
879
880 For each of the following, dir() returns the QDir
881 \c{"."}.
882
883 \snippet fileinfo/main.cpp 1
884
885 \sa absolutePath(), filePath(), fileName(), isRelative(), absoluteDir()
886*/
887QDir QFileInfo::dir() const
888{
889 Q_D(const QFileInfo);
890 // ### Qt 6: Maybe rename this to parentDirectory(), considering what it actually does?
891 return QDir(d->fileEntry.path());
892}
893
894/*!
895 Returns the file's absolute path as a QDir object.
896
897 \sa dir(), filePath(), fileName(), isRelative()
898*/
899QDir QFileInfo::absoluteDir() const
900{
901 return QDir(absolutePath());
902}
903
904/*!
905 Returns \c true if the user can read the file; otherwise returns \c false.
906
907 \note If the \l{NTFS permissions} check has not been enabled, the result
908 on Windows will merely reflect whether the file exists.
909
910 \sa isWritable(), isExecutable(), permission()
911*/
912bool QFileInfo::isReadable() const
913{
914 Q_D(const QFileInfo);
915 return d->checkAttribute<bool>(
916 QFileSystemMetaData::UserReadPermission,
917 [d]() { return (d->metaData.permissions() & QFile::ReadUser) != 0; },
918 [d]() { return d->getFileFlags(QAbstractFileEngine::ReadUserPerm); });
919}
920
921/*!
922 Returns \c true if the user can write to the file; otherwise returns \c false.
923
924 \note If the \l{NTFS permissions} check has not been enabled, the result on
925 Windows will merely reflect whether the file is marked as Read Only.
926
927 \sa isReadable(), isExecutable(), permission()
928*/
929bool QFileInfo::isWritable() const
930{
931 Q_D(const QFileInfo);
932 return d->checkAttribute<bool>(
933 QFileSystemMetaData::UserWritePermission,
934 [d]() { return (d->metaData.permissions() & QFile::WriteUser) != 0; },
935 [d]() { return d->getFileFlags(QAbstractFileEngine::WriteUserPerm); });
936}
937
938/*!
939 Returns \c true if the file is executable; otherwise returns \c false.
940
941 \sa isReadable(), isWritable(), permission()
942*/
943bool QFileInfo::isExecutable() const
944{
945 Q_D(const QFileInfo);
946 return d->checkAttribute<bool>(
947 QFileSystemMetaData::UserExecutePermission,
948 [d]() { return (d->metaData.permissions() & QFile::ExeUser) != 0; },
949 [d]() { return d->getFileFlags(QAbstractFileEngine::ExeUserPerm); });
950}
951
952/*!
953 Returns \c true if this is a `hidden' file; otherwise returns \c false.
954
955 \b{Note:} This function returns \c true for the special entries
956 "." and ".." on Unix, even though QDir::entryList threats them as shown.
957*/
958bool QFileInfo::isHidden() const
959{
960 Q_D(const QFileInfo);
961 return d->checkAttribute<bool>(
962 QFileSystemMetaData::HiddenAttribute,
963 [d]() { return d->metaData.isHidden(); },
964 [d]() { return d->getFileFlags(QAbstractFileEngine::HiddenFlag); });
965}
966
967/*!
968 \since 5.0
969 Returns \c true if the file path can be used directly with native APIs.
970 Returns \c false if the file is otherwise supported by a virtual file system
971 inside Qt, such as \l{the Qt Resource System}.
972
973 \b{Note:} Native paths may still require conversion of path separators
974 and character encoding, depending on platform and input requirements of the
975 native API.
976
977 \sa QDir::toNativeSeparators(), QFile::encodeName(), filePath(),
978 absoluteFilePath(), canonicalFilePath()
979*/
980bool QFileInfo::isNativePath() const
981{
982 Q_D(const QFileInfo);
983 if (d->isDefaultConstructed)
984 return false;
985 if (d->fileEngine == nullptr)
986 return true;
987 return d->getFileFlags(QAbstractFileEngine::LocalDiskFlag);
988}
989
990/*!
991 Returns \c true if this object points to a file or to a symbolic
992 link to a file. Returns \c false if the
993 object points to something which isn't a file, such as a directory.
994
995 \sa isDir(), isSymLink(), isBundle()
996*/
997bool QFileInfo::isFile() const
998{
999 Q_D(const QFileInfo);
1000 return d->checkAttribute<bool>(
1001 QFileSystemMetaData::FileType,
1002 [d]() { return d->metaData.isFile(); },
1003 [d]() { return d->getFileFlags(QAbstractFileEngine::FileType); });
1004}
1005
1006/*!
1007 Returns \c true if this object points to a directory or to a symbolic
1008 link to a directory; otherwise returns \c false.
1009
1010 \sa isFile(), isSymLink(), isBundle()
1011*/
1012bool QFileInfo::isDir() const
1013{
1014 Q_D(const QFileInfo);
1015 return d->checkAttribute<bool>(
1016 QFileSystemMetaData::DirectoryType,
1017 [d]() { return d->metaData.isDirectory(); },
1018 [d]() { return d->getFileFlags(QAbstractFileEngine::DirectoryType); });
1019}
1020
1021
1022/*!
1023 \since 4.3
1024 Returns \c true if this object points to a bundle or to a symbolic
1025 link to a bundle on \macos and iOS; otherwise returns \c false.
1026
1027 \sa isDir(), isSymLink(), isFile()
1028*/
1029bool QFileInfo::isBundle() const
1030{
1031 Q_D(const QFileInfo);
1032 return d->checkAttribute<bool>(
1033 QFileSystemMetaData::BundleType,
1034 [d]() { return d->metaData.isBundle(); },
1035 [d]() { return d->getFileFlags(QAbstractFileEngine::BundleType); });
1036}
1037
1038/*!
1039 Returns \c true if this object points to a symbolic link;
1040 otherwise returns \c false.
1041
1042 Symbolic links exist on Unix (including \macos and iOS) and Windows
1043 and are typically created by the \c{ln -s} or \c{mklink} commands,
1044 respectively. Opening a symbolic link effectively opens
1045 the \l{symLinkTarget()}{link's target}.
1046
1047 In addition, true will be returned for shortcuts (\c *.lnk files) on
1048 Windows. Opening those will open the \c .lnk file itself.
1049
1050 Example:
1051
1052 \snippet code/src_corelib_io_qfileinfo.cpp 9
1053
1054 \note If the symlink points to a non existing file, exists() returns
1055 false.
1056
1057 \sa isFile(), isDir(), symLinkTarget()
1058*/
1059bool QFileInfo::isSymLink() const
1060{
1061 Q_D(const QFileInfo);
1062 return d->checkAttribute<bool>(
1063 QFileSystemMetaData::LegacyLinkType,
1064 [d]() { return d->metaData.isLegacyLink(); },
1065 [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
1066}
1067
1068/*!
1069 Returns \c true if the object points to a directory or to a symbolic
1070 link to a directory, and that directory is the root directory; otherwise
1071 returns \c false.
1072*/
1073bool QFileInfo::isRoot() const
1074{
1075 Q_D(const QFileInfo);
1076 if (d->isDefaultConstructed)
1077 return false;
1078 if (d->fileEngine == nullptr) {
1079 if (d->fileEntry.isRoot()) {
1080#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
1081 //the path is a drive root, but the drive may not exist
1082 //for backward compatibility, return true only if the drive exists
1083 if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute))
1084 QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute);
1085 return d->metaData.exists();
1086#else
1087 return true;
1088#endif
1089 }
1090 return false;
1091 }
1092 return d->getFileFlags(QAbstractFileEngine::RootFlag);
1093}
1094
1095/*!
1096 \fn QString QFileInfo::symLinkTarget() const
1097 \since 4.2
1098
1099 Returns the absolute path to the file or directory a symbolic link
1100 points to, or an empty string if the object isn't a symbolic
1101 link.
1102
1103 This name may not represent an existing file; it is only a string.
1104 QFileInfo::exists() returns \c true if the symlink points to an
1105 existing file.
1106
1107 \sa exists(), isSymLink(), isDir(), isFile()
1108*/
1109
1110#if QT_DEPRECATED_SINCE(5, 13)
1111/*!
1112 \obsolete
1113
1114 Use symLinkTarget() instead.
1115*/
1116QString QFileInfo::readLink() const
1117{
1118 return symLinkTarget();
1119}
1120#endif
1121
1122QString QFileInfo::symLinkTarget() const
1123{
1124 Q_D(const QFileInfo);
1125 if (d->isDefaultConstructed)
1126 return QLatin1String("");
1127 return d->getFileName(QAbstractFileEngine::LinkName);
1128}
1129
1130/*!
1131 Returns the owner of the file. On systems where files
1132 do not have owners, or if an error occurs, an empty string is
1133 returned.
1134
1135 This function can be time consuming under Unix (in the order of
1136 milliseconds). On Windows, it will return an empty string unless
1137 the \l{NTFS permissions} check has been enabled.
1138
1139 \sa ownerId(), group(), groupId()
1140*/
1141QString QFileInfo::owner() const
1142{
1143 Q_D(const QFileInfo);
1144 if (d->isDefaultConstructed)
1145 return QLatin1String("");
1146 return d->getFileOwner(QAbstractFileEngine::OwnerUser);
1147}
1148
1149/*!
1150 Returns the id of the owner of the file.
1151
1152 On Windows and on systems where files do not have owners this
1153 function returns ((uint) -2).
1154
1155 \sa owner(), group(), groupId()
1156*/
1157uint QFileInfo::ownerId() const
1158{
1159 Q_D(const QFileInfo);
1160 return d->checkAttribute(uint(-2),
1161 QFileSystemMetaData::UserId,
1162 [d]() { return d->metaData.userId(); },
1163 [d]() { return d->fileEngine->ownerId(QAbstractFileEngine::OwnerUser); });
1164}
1165
1166/*!
1167 Returns the group of the file. On Windows, on systems where files
1168 do not have groups, or if an error occurs, an empty string is
1169 returned.
1170
1171 This function can be time consuming under Unix (in the order of
1172 milliseconds).
1173
1174 \sa groupId(), owner(), ownerId()
1175*/
1176QString QFileInfo::group() const
1177{
1178 Q_D(const QFileInfo);
1179 if (d->isDefaultConstructed)
1180 return QLatin1String("");
1181 return d->getFileOwner(QAbstractFileEngine::OwnerGroup);
1182}
1183
1184/*!
1185 Returns the id of the group the file belongs to.
1186
1187 On Windows and on systems where files do not have groups this
1188 function always returns (uint) -2.
1189
1190 \sa group(), owner(), ownerId()
1191*/
1192uint QFileInfo::groupId() const
1193{
1194 Q_D(const QFileInfo);
1195 return d->checkAttribute(uint(-2),
1196 QFileSystemMetaData::GroupId,
1197 [d]() { return d->metaData.groupId(); },
1198 [d]() { return d->fileEngine->ownerId(QAbstractFileEngine::OwnerGroup); });
1199}
1200
1201/*!
1202 Tests for file permissions. The \a permissions argument can be
1203 several flags of type QFile::Permissions OR-ed together to check
1204 for permission combinations.
1205
1206 On systems where files do not have permissions this function
1207 always returns \c true.
1208
1209 \note The result might be inaccurate on Windows if the
1210 \l{NTFS permissions} check has not been enabled.
1211
1212 Example:
1213 \snippet code/src_corelib_io_qfileinfo.cpp 10
1214
1215 \sa isReadable(), isWritable(), isExecutable()
1216*/
1217bool QFileInfo::permission(QFile::Permissions permissions) const
1218{
1219 Q_D(const QFileInfo);
1220 // the QFileSystemMetaData::MetaDataFlag and QFile::Permissions overlap, so just cast.
1221 auto fseFlags = QFileSystemMetaData::MetaDataFlag(int(permissions));
1222 auto feFlags = QAbstractFileEngine::FileFlags(int(permissions));
1223 return d->checkAttribute<bool>(
1224 fseFlags,
1225 [=]() { return (d->metaData.permissions() & permissions) == permissions; },
1226 [=]() {
1227 return d->getFileFlags(feFlags) == uint(permissions);
1228 });
1229}
1230
1231/*!
1232 Returns the complete OR-ed together combination of
1233 QFile::Permissions for the file.
1234
1235 \note The result might be inaccurate on Windows if the
1236 \l{NTFS permissions} check has not been enabled.
1237*/
1238QFile::Permissions QFileInfo::permissions() const
1239{
1240 Q_D(const QFileInfo);
1241 return d->checkAttribute<QFile::Permissions>(
1242 QFileSystemMetaData::Permissions,
1243 [d]() { return d->metaData.permissions(); },
1244 [d]() {
1245 return QFile::Permissions(d->getFileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask);
1246 });
1247}
1248
1249
1250/*!
1251 Returns the file size in bytes. If the file does not exist or cannot be
1252 fetched, 0 is returned.
1253
1254 \sa exists()
1255*/
1256qint64 QFileInfo::size() const
1257{
1258 Q_D(const QFileInfo);
1259 return d->checkAttribute<qint64>(
1260 QFileSystemMetaData::SizeAttribute,
1261 [d]() { return d->metaData.size(); },
1262 [d]() {
1263 if (!d->getCachedFlag(QFileInfoPrivate::CachedSize)) {
1264 d->setCachedFlag(QFileInfoPrivate::CachedSize);
1265 d->fileSize = d->fileEngine->size();
1266 }
1267 return d->fileSize;
1268 });
1269}
1270
1271#if QT_DEPRECATED_SINCE(5, 10)
1272/*!
1273 \deprecated
1274
1275 Returns the date and time when the file was created, the time its metadata
1276 was last changed or the time of last modification, whichever one of the
1277 three is available (in that order).
1278
1279 This function is deprecated. Instead, use the birthTime() function to get
1280 the time the file was created, metadataChangeTime() to get the time its
1281 metadata was last changed, or lastModified() to get the time it was last modified.
1282
1283 \sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
1284*/
1285QDateTime QFileInfo::created() const
1286{
1287 QDateTime d = fileTime(QFile::FileBirthTime);
1288 if (d.isValid())
1289 return d;
1290 return fileTime(QFile::FileMetadataChangeTime);
1291}
1292#endif
1293
1294/*!
1295 \since 5.10
1296 Returns the date and time when the file was created / born.
1297
1298 If the file birth time is not available, this function returns an invalid
1299 QDateTime.
1300
1301 \sa lastModified(), lastRead(), metadataChangeTime()
1302*/
1303QDateTime QFileInfo::birthTime() const
1304{
1305 return fileTime(QFile::FileBirthTime);
1306}
1307
1308/*!
1309 \since 5.10
1310 Returns the date and time when the file metadata was changed. A metadata
1311 change occurs when the file is created, but it also occurs whenever the
1312 user writes or sets inode information (for example, changing the file
1313 permissions).
1314
1315 \sa lastModified(), lastRead()
1316*/
1317QDateTime QFileInfo::metadataChangeTime() const
1318{
1319 return fileTime(QFile::FileMetadataChangeTime);
1320}
1321
1322/*!
1323 Returns the date and local time when the file was last modified.
1324
1325 \sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
1326*/
1327QDateTime QFileInfo::lastModified() const
1328{
1329 return fileTime(QFile::FileModificationTime);
1330}
1331
1332/*!
1333 Returns the date and local time when the file was last read (accessed).
1334
1335 On platforms where this information is not available, returns the
1336 same as lastModified().
1337
1338 \sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
1339*/
1340QDateTime QFileInfo::lastRead() const
1341{
1342 return fileTime(QFile::FileAccessTime);
1343}
1344
1345/*!
1346 \since 5.10
1347
1348 Returns the file time specified by \a time. If the time cannot be
1349 determined, an invalid date time is returned.
1350
1351 \sa QFile::FileTime, QDateTime::isValid()
1352*/
1353QDateTime QFileInfo::fileTime(QFile::FileTime time) const
1354{
1355 Q_STATIC_ASSERT(int(QFile::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
1356 Q_STATIC_ASSERT(int(QFile::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
1357 Q_STATIC_ASSERT(int(QFile::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
1358 Q_STATIC_ASSERT(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
1359
1360 Q_D(const QFileInfo);
1361 auto fetime = QAbstractFileEngine::FileTime(time);
1362 QFileSystemMetaData::MetaDataFlags flag;
1363 switch (time) {
1364 case QFile::FileAccessTime:
1365 flag = QFileSystemMetaData::AccessTime;
1366 break;
1367 case QFile::FileBirthTime:
1368 flag = QFileSystemMetaData::BirthTime;
1369 break;
1370 case QFile::FileMetadataChangeTime:
1371 flag = QFileSystemMetaData::MetadataChangeTime;
1372 break;
1373 case QFile::FileModificationTime:
1374 flag = QFileSystemMetaData::ModificationTime;
1375 break;
1376 }
1377
1378 return d->checkAttribute<QDateTime>(
1379 flag,
1380 [=]() { return d->metaData.fileTime(fetime).toLocalTime(); },
1381 [=]() { return d->getFileTime(fetime).toLocalTime(); });
1382}
1383
1384/*!
1385 \internal
1386*/
1387QFileInfoPrivate* QFileInfo::d_func()
1388{
1389 return d_ptr.data();
1390}
1391
1392/*!
1393 Returns \c true if caching is enabled; otherwise returns \c false.
1394
1395 \sa setCaching(), refresh()
1396*/
1397bool QFileInfo::caching() const
1398{
1399 Q_D(const QFileInfo);
1400 return d->cache_enabled;
1401}
1402
1403/*!
1404 If \a enable is true, enables caching of file information. If \a
1405 enable is false caching is disabled.
1406
1407 When caching is enabled, QFileInfo reads the file information from
1408 the file system the first time it's needed, but generally not
1409 later.
1410
1411 Caching is enabled by default.
1412
1413 \sa refresh(), caching()
1414*/
1415void QFileInfo::setCaching(bool enable)
1416{
1417 Q_D(QFileInfo);
1418 d->cache_enabled = enable;
1419}
1420
1421/*!
1422 \typedef QFileInfoList
1423 \relates QFileInfo
1424
1425 Synonym for QList<QFileInfo>.
1426*/
1427
1428#ifndef QT_NO_DEBUG_STREAM
1429QDebug operator<<(QDebug dbg, const QFileInfo &fi)
1430{
1431 QDebugStateSaver saver(dbg);
1432 dbg.nospace();
1433 dbg.noquote();
1434 dbg << "QFileInfo(" << QDir::toNativeSeparators(fi.filePath()) << ')';
1435 return dbg;
1436}
1437#endif
1438
1439QT_END_NAMESPACE
1440