7#include "qplatformdefs.h"
13#include <QtCore/qoperatingsystemversion.h>
14#include <QtCore/private/qcore_unix_p.h>
15#include <QtCore/private/qfiledevice_p.h>
16#include <QtCore/private/qfunctions_p.h>
17#include <QtCore/qvarlengtharray.h>
18#ifndef QT_BOOTSTRAPPED
19# include <QtCore/qstandardpaths.h>
20# include <QtCore/private/qtemporaryfile_p.h>
37# define _PATH_TMP "/tmp"
45#if defined(Q_OS_DARWIN)
46# include <QtCore/private/qcore_mac_p.h>
47# include <CoreFoundation/CFBundle.h>
48# include <UniformTypeIdentifiers/UTType.h>
49# include <UniformTypeIdentifiers/UTCoreTypes.h>
50# include <Foundation/Foundation.h>
55#include <CoreServices/CoreServices.h>
58#if defined(QT_PLATFORM_UIKIT)
59#include <MobileCoreServices/MobileCoreServices.h>
62#if defined(Q_OS_LINUX)
63# include <sys/ioctl.h>
64# include <sys/sendfile.h>
69# define FICLONE _IOW(0x94
, 9
, int)
73#if defined(Q_OS_VXWORKS)
74# include <sys/statfs.h>
75# if __has_include(<dosFsLib.h>)
80#if defined(Q_OS_ANDROID)
84# undef STATX_BASIC_STATS
93using namespace Qt::StringLiterals;
98 while (path.size() > 1 && path.endsWith(
'/'))
108 SupportsHardlinking =
false
114#if defined(Q_OS_DARWIN)
115static inline bool hasResourcePropertyFlag(
const QFileSystemMetaData &data,
116 const QFileSystemEntry &entry,
117 CFStringRef key, QCFType<CFURLRef> &url)
120 QCFString path = CFStringCreateWithFileSystemRepresentation(0,
121 entry.nativeFilePath().constData());
125 url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle,
126 data.hasFlags(QFileSystemMetaData::DirectoryType));
132 if (CFURLCopyResourcePropertyForKey(url, key, &value, NULL)) {
133 if (value == kCFBooleanTrue)
140static bool isPackage(
const QFileSystemMetaData &data,
const QFileSystemEntry &entry,
141 QCFType<CFURLRef> &cachedUrl)
143 if (!data.isDirectory())
146 QFileInfo info(entry.filePath());
147 QString suffix = info.suffix();
149 if (suffix.length() > 0) {
151 const auto *utType = [UTType typeWithFilenameExtension:suffix.toNSString()];
152 if ([utType conformsToType:UTTypeBundle])
156 QCFType<CFStringRef> path = entry.filePath().toCFString();
157 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle,
true);
159 UInt32 type, creator;
161 if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
166 QCFType<CFURLRef> application = LSCopyDefaultApplicationURLForURL(url,
167 kLSRolesEditor | kLSRolesViewer,
nullptr);
170 QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, application);
171 CFStringRef identifier = CFBundleGetIdentifier(bundle);
172 QString applicationId = QString::fromCFString(identifier);
173 if (applicationId !=
"com.apple.finder"_L1)
180 return hasResourcePropertyFlag(data, entry, kCFURLIsPackageKey, cachedUrl);
185static inline void forceRequestedPermissionsOnVxWorks(QByteArray dirName, mode_t mode)
195qint64 time_t_toMsecs(time_t t)
197 using namespace std::chrono;
198 return milliseconds{seconds{t}}.count();
202[[
maybe_unused]] qint64 atime(
const QT_STATBUF &statBuffer, ulong)
204 return time_t_toMsecs(statBuffer.st_atime);
206[[
maybe_unused]] qint64 birthtime(
const QT_STATBUF &, ulong)
210[[
maybe_unused]] qint64 ctime(
const QT_STATBUF &statBuffer, ulong)
212 return time_t_toMsecs(statBuffer.st_ctime);
214[[
maybe_unused]] qint64 mtime(
const QT_STATBUF &statBuffer, ulong)
216 return time_t_toMsecs(statBuffer.st_mtime);
222qint64 timespecToMSecs(
const T &spec)
224 using namespace std::chrono;
225 const nanoseconds nsecs = seconds{spec.tv_sec} + nanoseconds{spec.tv_nsec};
226 return duration_cast<milliseconds>(nsecs).count();
231[[maybe_unused]]
static typename std::enable_if<(&T::st_atim,
true), qint64>::type
232atime(
const T &statBuffer,
int)
233{
return timespecToMSecs(statBuffer.st_atim); }
236[[maybe_unused]]
static typename std::enable_if<(&T::st_birthtim,
true), qint64>::type
237birthtime(
const T &statBuffer,
int)
238{
return timespecToMSecs(statBuffer.st_birthtim); }
241[[maybe_unused]]
static typename std::enable_if<(&T::st_ctim,
true), qint64>::type
242ctime(
const T &statBuffer,
int)
243{
return timespecToMSecs(statBuffer.st_ctim); }
246[[maybe_unused]]
static typename std::enable_if<(&T::st_mtim,
true), qint64>::type
247mtime(
const T &statBuffer,
int)
248{
return timespecToMSecs(statBuffer.st_mtim); }
253[[maybe_unused]]
static typename std::enable_if<(&T::st_atimespec,
true), qint64>::type
254atime(
const T &statBuffer,
int)
255{
return timespecToMSecs(statBuffer.st_atimespec); }
258[[maybe_unused]]
static typename std::enable_if<(&T::st_birthtimespec,
true), qint64>::type
259birthtime(
const T &statBuffer,
int)
260{
return timespecToMSecs(statBuffer.st_birthtimespec); }
263[[maybe_unused]]
static typename std::enable_if<(&T::st_ctimespec,
true), qint64>::type
264ctime(
const T &statBuffer,
int)
265{
return timespecToMSecs(statBuffer.st_ctimespec); }
268[[maybe_unused]]
static typename std::enable_if<(&T::st_mtimespec,
true), qint64>::type
269mtime(
const T &statBuffer,
int)
270{
return timespecToMSecs(statBuffer.st_mtimespec); }
273#if !defined(st_mtimensec) && !defined(__alpha__)
276[[maybe_unused]]
static typename std::enable_if<(&T::st_atimensec,
true), qint64>::type
277atime(
const T &statBuffer,
int)
278{
return statBuffer.st_atime * Q_INT64_C(1000) + statBuffer.st_atimensec / 1000000; }
281[[maybe_unused]]
static typename std::enable_if<(&T::st_birthtimensec,
true), qint64>::type
282birthtime(
const T &statBuffer,
int)
283{
return statBuffer.st_birthtime * Q_INT64_C(1000) + statBuffer.st_birthtimensec / 1000000; }
286[[maybe_unused]]
static typename std::enable_if<(&T::st_ctimensec,
true), qint64>::type
287ctime(
const T &statBuffer,
int)
288{
return statBuffer.st_ctime * Q_INT64_C(1000) + statBuffer.st_ctimensec / 1000000; }
291[[maybe_unused]]
static typename std::enable_if<(&T::st_mtimensec,
true), qint64>::type
292mtime(
const T &statBuffer,
int)
293{
return statBuffer.st_mtime * Q_INT64_C(1000) + statBuffer.st_mtimensec / 1000000; }
304 QFileSystemMetaData::MetaDataFlags entryFlags = QFileSystemMetaData::ExistsAttribute;
307 entryFlags |= QFileSystemMetaData::OwnerReadPermission;
309 entryFlags |= QFileSystemMetaData::OwnerWritePermission;
311 entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
314 entryFlags |= QFileSystemMetaData::GroupReadPermission;
316 entryFlags |= QFileSystemMetaData::GroupWritePermission;
318 entryFlags |= QFileSystemMetaData::GroupExecutePermission;
321 entryFlags |= QFileSystemMetaData::OtherReadPermission;
323 entryFlags |= QFileSystemMetaData::OtherWritePermission;
325 entryFlags |= QFileSystemMetaData::OtherExecutePermission;
328 Q_ASSERT(!S_ISLNK(mode));
329 if ((mode & S_IFMT) == S_IFREG)
330 entryFlags |= QFileSystemMetaData::FileType;
331 else if ((mode & S_IFMT) == S_IFDIR)
332 entryFlags |= QFileSystemMetaData::DirectoryType;
333 else if ((mode & S_IFMT) != S_IFBLK)
334 entryFlags |= QFileSystemMetaData::SequentialType;
344 if (attributes & DOS_ATTR_RDONLY) {
347 entryFlags &= ~QFileSystemMetaData::OwnerWritePermission;
348 entryFlags &= ~QFileSystemMetaData::GroupWritePermission;
349 entryFlags &= ~QFileSystemMetaData::OtherWritePermission;
355#ifdef STATX_BASIC_STATS
356static int qt_real_statx(
int fd,
const char *pathname,
int flags,
struct statx *statxBuffer)
358 unsigned mask = STATX_BASIC_STATS | STATX_BTIME;
359 int ret = statx(fd, pathname, flags | AT_NO_AUTOMOUNT, mask, statxBuffer);
360 return ret == -1 ? -errno : 0;
363static int qt_statx(
const char *pathname,
struct statx *statxBuffer)
365 return qt_real_statx(AT_FDCWD, pathname, 0, statxBuffer);
368static int qt_lstatx(
const char *pathname,
struct statx *statxBuffer)
370 return qt_real_statx(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW, statxBuffer);
373static int qt_fstatx(
int fd,
struct statx *statxBuffer)
375 return qt_real_statx(fd,
"", AT_EMPTY_PATH, statxBuffer);
378inline void QFileSystemMetaData::fillFromStatxBuf(
const struct statx &statxBuffer)
381 MetaDataFlags flags = flagsFromStMode(statxBuffer.stx_mode, statxBuffer.stx_attributes);
383 knownFlagsMask |= flags | PosixStatFlags;
386 if (statxBuffer.stx_nlink == 0)
387 entryFlags |= QFileSystemMetaData::WasDeletedAttribute;
388 size_ = qint64(statxBuffer.stx_size);
391 using namespace GetFileTimes;
392 accessTime_ = timespecToMSecs(statxBuffer.stx_atime);
393 metadataChangeTime_ = timespecToMSecs(statxBuffer.stx_ctime);
394 modificationTime_ = timespecToMSecs(statxBuffer.stx_mtime);
395 const bool birthMask = statxBuffer.stx_mask & STATX_BTIME;
396 birthTime_ = birthMask ? timespecToMSecs(statxBuffer.stx_btime) : 0;
398 userId_ = statxBuffer.stx_uid;
399 groupId_ = statxBuffer.stx_gid;
411inline void QFileSystemMetaData::fillFromStatxBuf(
const struct statx &)
416bool QFileSystemEngine::fillMetaData(
int fd, QFileSystemMetaData &data)
418 auto getSizeForBlockDev = [&](mode_t st_mode) {
421 if (quint64 sz; (st_mode & S_IFMT) == S_IFBLK && ioctl(fd, BLKGETSIZE64, &sz) == 0)
423#elif defined(BLKGETSIZE)
425 if (ulong sz; (st_mode & S_IFMT) == S_IFBLK && ioctl(fd, BLKGETSIZE, &sz) == 0)
426 data.size_ = sz * 512;
427#elif defined(DKIOCGETBLOCKCOUNT)
430 if (quint64 count; (st_mode & S_IFMT) == S_IFBLK
431 && ioctl(fd, DKIOCGETBLOCKCOUNT, &count) == 0
432 && ioctl(fd, DKIOCGETBLOCKSIZE, &blksz) == 0)
433 data.size_ = count * blksz;
434#elif defined(DIOCGMEDIASIZE)
439 if (QT_OFF_T sz; (st_mode & S_IFMT) == S_IFCHR && ioctl(fd, DIOCGMEDIASIZE, &sz) == 0)
445 data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
446 data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
448 struct statx statxBuffer;
450 int ret = qt_fstatx(fd, &statxBuffer);
451 if (ret != -ENOSYS) {
453 data.fillFromStatxBuf(statxBuffer);
454 getSizeForBlockDev(statxBuffer.stx_mode);
460 QT_STATBUF statBuffer;
462 if (QT_FSTAT(fd, &statBuffer) == 0) {
463 data.fillFromStatBuf(statBuffer);
464 getSizeForBlockDev(statBuffer.st_mode);
471#if defined(_DEXTRA_FIRST)
472static void fillStat64fromStat32(
struct stat64 *statBuf64,
const struct stat &statBuf32)
474 statBuf64->st_mode = statBuf32.st_mode;
475 statBuf64->st_size = statBuf32.st_size;
476#if _POSIX_VERSION >= 200809L
477 statBuf64->st_ctim = statBuf32.st_ctim;
478 statBuf64->st_mtim = statBuf32.st_mtim;
479 statBuf64->st_atim = statBuf32.st_atim;
481 statBuf64->st_ctime = statBuf32.st_ctime;
482 statBuf64->st_mtime = statBuf32.st_mtime;
483 statBuf64->st_atime = statBuf32.st_atime;
485 statBuf64->st_uid = statBuf32.st_uid;
486 statBuf64->st_gid = statBuf32.st_gid;
490void QFileSystemMetaData::fillFromStatBuf(
const QT_STATBUF &statBuffer)
492 quint64 attributes = 0;
493#if defined(UF_SETTABLE)
494 attributes = statBuffer.st_flags;
496 attributes = statBuffer.st_attrib;
499 MetaDataFlags flags = flagsFromStMode(statBuffer.st_mode, attributes);
501 knownFlagsMask |= flags | PosixStatFlags;
504 if (statBuffer.st_nlink == 0)
505 entryFlags |= QFileSystemMetaData::WasDeletedAttribute;
506 size_ = statBuffer.st_size;
509 accessTime_ = GetFileTimes::atime(statBuffer, 0);
510 birthTime_ = GetFileTimes::birthtime(statBuffer, 0);
511 metadataChangeTime_ = GetFileTimes::ctime(statBuffer, 0);
512 modificationTime_ = GetFileTimes::mtime(statBuffer, 0);
514 userId_ = statBuffer.st_uid;
515 groupId_ = statBuffer.st_gid;
518void QFileSystemMetaData::fillFromDirEnt(
const QT_DIRENT &entry)
520#if defined(_DEXTRA_FIRST)
523 for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
524 extra = _DEXTRA_NEXT(extra)) {
525 if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
527 const struct dirent_extra_stat *
const extra_stat =
528 reinterpret_cast<
struct dirent_extra_stat *>(extra);
531 if (extra->d_type == _DTYPE_LSTAT) {
532 knownFlagsMask |= QFileSystemMetaData::LinkType;
533 if (S_ISLNK(extra_stat->d_stat.st_mode))
534 entryFlags |= QFileSystemMetaData::LinkType;
542 if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
545#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
548 struct stat64 statBuf;
549 fillStat64fromStat32(&statBuf, extra_stat->d_stat);
550 fillFromStatBuf(statBuf);
552 fillFromStatBuf(extra_stat->d_stat);
554 knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
555 if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
556 knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
557 entryFlags |= QFileSystemMetaData::ExistsAttribute;
561#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
565 switch (entry.d_type)
568 knownFlagsMask = QFileSystemMetaData::LinkType
569 | QFileSystemMetaData::FileType
570 | QFileSystemMetaData::DirectoryType
571 | QFileSystemMetaData::SequentialType
572 | QFileSystemMetaData::ExistsAttribute;
574 entryFlags = QFileSystemMetaData::DirectoryType
575 | QFileSystemMetaData::ExistsAttribute;
580 knownFlagsMask = QFileSystemMetaData::LinkType
581 | QFileSystemMetaData::FileType
582 | QFileSystemMetaData::DirectoryType
583 | QFileSystemMetaData::BundleType
584 | QFileSystemMetaData::AliasType
585 | QFileSystemMetaData::SequentialType
586 | QFileSystemMetaData::ExistsAttribute;
588 entryFlags = QFileSystemMetaData::ExistsAttribute;
596 knownFlagsMask = QFileSystemMetaData::LinkType
597 | QFileSystemMetaData::FileType
598 | QFileSystemMetaData::DirectoryType
599 | QFileSystemMetaData::BundleType
600 | QFileSystemMetaData::AliasType
601 | QFileSystemMetaData::SequentialType
602 | QFileSystemMetaData::ExistsAttribute;
604 entryFlags = QFileSystemMetaData::SequentialType
605 | QFileSystemMetaData::ExistsAttribute;
610 knownFlagsMask = QFileSystemMetaData::LinkType;
611 entryFlags = QFileSystemMetaData::LinkType;
615 knownFlagsMask = QFileSystemMetaData::LinkType
616 | QFileSystemMetaData::FileType
617 | QFileSystemMetaData::DirectoryType
618 | QFileSystemMetaData::BundleType
619 | QFileSystemMetaData::SequentialType
620 | QFileSystemMetaData::ExistsAttribute;
622 entryFlags = QFileSystemMetaData::FileType
623 | QFileSystemMetaData::ExistsAttribute;
637QFileSystemEntry QFileSystemEngine::getLinkTarget(
const QFileSystemEntry &link, QFileSystemMetaData &data)
641 QByteArray s = qt_readlink(link.nativeFilePath().constData());
644 if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
645 fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
646 if (data.isDirectory() && s[0] !=
'/') {
647 QDir parent(link.filePath());
650 if (!ret.isEmpty() && !ret.endsWith(u'/'))
653 ret += QFile::decodeName(s);
655 if (!ret.startsWith(u'/'))
656 ret.prepend(absoluteName(link).path() + u'/');
657 ret = QDir::cleanPath(ret);
658 if (ret.size() > 1 && ret.endsWith(u'/'))
660 return QFileSystemEntry(ret);
662#if defined(Q_OS_DARWIN)
664 QCFString path = CFStringCreateWithFileSystemRepresentation(0,
665 QFile::encodeName(QDir::cleanPath(link.filePath())).data());
667 return QFileSystemEntry();
669 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle,
670 data.hasFlags(QFileSystemMetaData::DirectoryType));
672 return QFileSystemEntry();
674 QCFType<CFDataRef> bookmarkData = CFURLCreateBookmarkDataFromFile(0, url, NULL);
676 return QFileSystemEntry();
678 QCFType<CFURLRef> resolvedUrl = CFURLCreateByResolvingBookmarkData(0,
680 (CFURLBookmarkResolutionOptions)(kCFBookmarkResolutionWithoutUIMask
681 | kCFBookmarkResolutionWithoutMountingMask), NULL, NULL, NULL, NULL);
683 return QFileSystemEntry();
685 QCFString cfstr(CFURLCopyFileSystemPath(resolvedUrl, kCFURLPOSIXPathStyle));
687 return QFileSystemEntry();
689 return QFileSystemEntry(QString::fromCFString(cfstr));
692 return QFileSystemEntry();
696QFileSystemEntry QFileSystemEngine::getRawLinkPath(
const QFileSystemEntry &link,
697 QFileSystemMetaData &data)
700 const QByteArray path = qt_readlink(link.nativeFilePath().constData());
701 const QString ret = QFile::decodeName(path);
702 return QFileSystemEntry(ret);
706QFileSystemEntry QFileSystemEngine::canonicalName(
const QFileSystemEntry &entry, QFileSystemMetaData &data)
709 char *resolved_name =
nullptr;
713 char stack_result[PATH_MAX + 1];
716 std::nullptr_t stack_result =
nullptr;
717 auto freer = qScopeGuard([&] { free(resolved_name); });
720# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
723 if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
724 fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
729 resolved_name = realpath(entry.nativeFilePath().constData(), stack_result);
731 resolved_name = realpath(entry.nativeFilePath().constData(), stack_result);
734 data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
735 data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
736 return QFileSystemEntry(resolved_name, QFileSystemEntry::FromNativePath{});
737 }
else if (errno == ENOENT || errno == ENOTDIR) {
738 data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
739 data.entryFlags &= ~(QFileSystemMetaData::ExistsAttribute);
740 return QFileSystemEntry();
746QFileSystemEntry QFileSystemEngine::absoluteName(
const QFileSystemEntry &entry)
750 if (entry.isAbsolute() && entry.isClean())
753 QByteArray orig = entry.nativeFilePath();
755 if (orig.isEmpty() || !orig.startsWith(
'/')) {
756 QFileSystemEntry cur(currentPath());
757 result = cur.nativeFilePath();
759 if (!orig.isEmpty() && !(orig.size() == 1 && orig[0] ==
'.')) {
760 if (!result.isEmpty() && !result.endsWith(
'/'))
765 if (result.size() == 1 && result[0] ==
'/')
766 return QFileSystemEntry(result, QFileSystemEntry::FromNativePath());
767 const bool isDir = result.endsWith(
'/');
770
771
772
773 QFileSystemEntry resultingEntry(result, QFileSystemEntry::FromNativePath());
774 QString stringVersion = QDir::cleanPath(resultingEntry.filePath());
776 stringVersion.append(u'/');
777 return QFileSystemEntry(stringVersion);
781QByteArray QFileSystemEngine::id(
const QFileSystemEntry &entry)
785 QT_STATBUF statResult;
786 if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) {
788 qErrnoWarning(
"stat() failed for '%s'", entry.nativeFilePath().constData());
791 QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
793 result += QByteArray::number(quint64(statResult.st_ino));
798QByteArray QFileSystemEngine::id(
int fd)
800 QT_STATBUF statResult;
801 if (QT_FSTAT(fd, &statResult)) {
802 qErrnoWarning(
"fstat() failed for fd %d", fd);
805 QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
807 result += QByteArray::number(quint64(statResult.st_ino));
812QString QFileSystemEngine::resolveUserName(uint userId)
814#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
815 long size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
818 QVarLengthArray<
char, 1024> buf(size_max);
821#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_WASM)
822 struct passwd *pw =
nullptr;
823#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS)
825 getpwuid_r(userId, &entry, buf.data(), buf.size(), &pw);
827 pw = getpwuid(userId);
830 return QFile::decodeName(QByteArray(pw->pw_name));
838QString QFileSystemEngine::resolveGroupName(uint groupId)
840#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
841 long size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
844 QVarLengthArray<
char, 1024> buf(size_max);
847#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_WASM)
848 struct group *gr =
nullptr;
849#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID) && (__ANDROID_API__ >= 24
))
850 size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
853 buf.resize(size_max);
857 for (
long size = size_max; size < 256000; size += size)
861 if (!getgrgid_r(groupId, &entry, buf.data(), buf.size(), &gr)
866 gr = getgrgid(groupId);
869 return QFile::decodeName(QByteArray(gr->gr_name));
876#if defined(Q_OS_DARWIN)
878QString QFileSystemEngine::bundleName(
const QFileSystemEntry &entry)
880 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(entry.filePath()),
881 kCFURLPOSIXPathStyle,
true);
882 if (QCFType<CFDictionaryRef> dict = CFBundleCopyInfoDictionaryForURL(url)) {
883 if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
884 if (CFGetTypeID(name) == CFStringGetTypeID())
885 return QString::fromCFString((CFStringRef)name);
893bool QFileSystemEngine::fillMetaData(
const QFileSystemEntry &entry, QFileSystemMetaData &data,
894 QFileSystemMetaData::MetaDataFlags what)
902 auto hadBeenDeleted = data.entryFlags & QFileSystemMetaData::WasDeletedAttribute;
904#if defined(Q_OS_DARWIN)
905 if (what & (QFileSystemMetaData::BundleType | QFileSystemMetaData::CaseSensitive)) {
906 if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
907 what |= QFileSystemMetaData::DirectoryType;
909 if (what & QFileSystemMetaData::AliasType)
910 what |= QFileSystemMetaData::LinkType;
913 bool needLstat = what.testAnyFlag(QFileSystemMetaData::LinkType);
916 if (what & QFileSystemMetaData::HiddenAttribute) {
926 if (what & QFileSystemMetaData::PosixStatFlags)
927 what |= QFileSystemMetaData::PosixStatFlags;
929 data.entryFlags &= ~what;
931 const QByteArray nativeFilePath = entry.nativeFilePath();
948 QT_STATBUF statBuffer;
949 struct statx statxBuffer;
954 statResult = qt_lstatx(nativeFilePath, &statxBuffer);
955 if (statResult == -ENOSYS) {
957 statResult = QT_LSTAT(nativeFilePath, &statBuffer);
959 mode = statBuffer.st_mode;
960 }
else if (statResult == 0) {
962 mode = statxBuffer.stx_mode;
965 if (statResult >= 0) {
968 Q_ASSERT(statResult == 0);
969 if (statBuffer.st_flags & UF_HIDDEN)
970 data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
971 data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
976 data.entryFlags |= QFileSystemMetaData::LinkType;
981 data.fillFromStatxBuf(statxBuffer);
983 data.fillFromStatBuf(statBuffer);
989 data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
992 data.knownFlagsMask |= QFileSystemMetaData::LinkType;
996 if (statResult == -1 && (what & QFileSystemMetaData::PosixStatFlags)) {
997 if (entryErrno == 0) {
998 data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
999 statResult = qt_statx(nativeFilePath, &statxBuffer);
1000 if (statResult == -ENOSYS) {
1002 statResult = QT_STAT(nativeFilePath, &statBuffer);
1003 if (statResult == 0)
1004 data.fillFromStatBuf(statBuffer);
1005 }
else if (statResult == 0) {
1006 data.fillFromStatxBuf(statxBuffer);
1010 if (statResult != 0) {
1012 data.birthTime_ = 0;
1013 data.metadataChangeTime_ = 0;
1014 data.modificationTime_ = 0;
1015 data.accessTime_ = 0;
1017 data.userId_ = (uint) -2;
1018 data.groupId_ = (uint) -2;
1021 data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
1022 | QFileSystemMetaData::ExistsAttribute;
1027 if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) {
1028#if defined(Q_OS_VXWORKS)
1029 struct statfs statBuf;
1030 if (statfs(nativeFilePath, &statBuf) == 0) {
1031 if (statBuf.f_type != NFSV2_MAGIC && statBuf.f_type != NFSV3_MAGIC &&
1032 statBuf.f_type != HRFS_MAGIC) {
1033#if __has_include(<dosFsLib.h>)
1034 if (data.entryFlags & QFileSystemMetaData::OwnerWritePermission) {
1035 data.entryFlags |= QFileSystemMetaData::UserWritePermission;
1037 if (data.entryFlags & QFileSystemMetaData::OwnerExecutePermission) {
1038 data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
1041 data.entryFlags |= QFileSystemMetaData::UserReadPermission |
1042 QFileSystemMetaData::ExistsAttribute;
1046#if defined(QT_DEBUG)
1050 statResult = QT_STAT(nativeFilePath, &statBuffer);
1051 if (statResult == 0) {
1052 data.entryFlags |= QFileSystemMetaData::UserReadPermission |
1053 QFileSystemMetaData::ExistsAttribute;
1054 data.entryFlags &= ~QFileSystemMetaData::WasDeletedAttribute;
1061 auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag,
int mode) {
1062 if (entryErrno != 0 || (what & flag) == 0)
1064 if (QT_ACCESS(nativeFilePath, mode) == 0) {
1066 data.entryFlags |= flag | QFileSystemMetaData::ExistsAttribute;
1067 }
else if (errno != EACCES && errno != EROFS) {
1071 checkAccess(QFileSystemMetaData::UserReadPermission, R_OK);
1072 checkAccess(QFileSystemMetaData::UserWritePermission, W_OK);
1073 checkAccess(QFileSystemMetaData::UserExecutePermission, X_OK);
1076 if (entryErrno == 0 && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) {
1077 if (QT_ACCESS(nativeFilePath, F_OK) == -1)
1080 data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
1083 data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions) |
1084 QFileSystemMetaData::ExistsAttribute;
1087#if defined(Q_OS_DARWIN)
1088 QCFType<CFURLRef> cachedUrl;
1089 if (what & QFileSystemMetaData::AliasType) {
1090 if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey, cachedUrl)) {
1092 if (!(data.entryFlags & QFileSystemMetaData::LinkType))
1093 data.entryFlags |= QFileSystemMetaData::AliasType;
1095 data.knownFlagsMask |= QFileSystemMetaData::AliasType;
1098 if (what & QFileSystemMetaData::BundleType) {
1099 if (entryErrno == 0 && isPackage(data, entry, cachedUrl))
1100 data.entryFlags |= QFileSystemMetaData::BundleType;
1102 data.knownFlagsMask |= QFileSystemMetaData::BundleType;
1105 if (what & QFileSystemMetaData::CaseSensitive) {
1106 if (entryErrno == 0 && hasResourcePropertyFlag(data, entry,
1107 kCFURLVolumeSupportsCaseSensitiveNamesKey, cachedUrl))
1108 data.entryFlags |= QFileSystemMetaData::CaseSensitive;
1109 data.knownFlagsMask |= QFileSystemMetaData::CaseSensitive;
1113 if (what & QFileSystemMetaData::HiddenAttribute
1114 && !data.isHidden()) {
1117 qsizetype lastSlash = nativeFilePath.size();
1119 while (lastSlash && nativeFilePath.at(lastSlash - 1) ==
'/')
1121 while (lastSlash && nativeFilePath.at(lastSlash - 1) !=
'/')
1125 if (nativeFilePath.at(lastSlash + 1) ==
'.')
1126 data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
1127 data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
1130 if (entryErrno != 0) {
1131 what &= ~QFileSystemMetaData::LinkType;
1132 data.clearFlags(what);
1135 data.entryFlags |= hadBeenDeleted;
1136 data.knownFlagsMask |= hadBeenDeleted;
1144auto QFileSystemEngine::cloneFile(
int srcfd,
int dstfd,
const QFileSystemMetaData &knownData) -> TriStateResult
1146 QT_STATBUF statBuffer;
1147 if (knownData.hasFlags(QFileSystemMetaData::PosixStatFlags) &&
1148 knownData.isFile()) {
1149 statBuffer.st_mode = S_IFREG;
1150 }
else if (knownData.hasFlags(QFileSystemMetaData::PosixStatFlags) &&
1151 knownData.isDirectory()) {
1153 return TriStateResult::Failed;
1154 }
else if (QT_FSTAT(srcfd, &statBuffer) == -1) {
1156 return TriStateResult::Failed;
1157 }
else if (!S_ISREG((statBuffer.st_mode))) {
1159 return TriStateResult::NotSupported;
1162 [[maybe_unused]]
auto destinationIsEmpty = [dstfd]() {
1163 QT_STATBUF statBuffer;
1164 return QT_FSTAT(dstfd, &statBuffer) == 0 && statBuffer.st_size == 0;
1166 Q_ASSERT(destinationIsEmpty());
1168#if defined(Q_OS_LINUX)
1170 if (::ioctl(dstfd, FICLONE, srcfd) == 0)
1171 return TriStateResult::Success;
1172#elif defined(Q_OS_DARWIN)
1174 if (fcopyfile(srcfd, dstfd,
nullptr, COPYFILE_DATA | COPYFILE_STAT) == 0)
1175 return TriStateResult::Success;
1179 return TriStateResult::NotSupported;
1181 return TriStateResult::Failed;
1184#if QT_CONFIG(copy_file_range)
1188 QT_OFF_T srcoffset = 0;
1191 copied = ::copy_file_range(srcfd, &srcoffset, dstfd,
nullptr, SSIZE_MAX, 0);
1192 }
while (copied > 0 || (copied < 0 && errno == EINTR));
1194 return TriStateResult::Success;
1197 copied = ftruncate(dstfd, 0);
1198 return TriStateResult::Failed;
1210 return TriStateResult::Failed;
1214#if defined(Q_OS_LINUX)
1217 const size_t SendfileSize = 0x7ffff000;
1219 ssize_t n = ::sendfile(dstfd, srcfd,
nullptr, SendfileSize);
1224 return TriStateResult::Failed;
1228 return TriStateResult::NotSupported;
1232 n = ::sendfile(dstfd, srcfd,
nullptr, SendfileSize);
1235 n = ftruncate(dstfd, 0);
1236 n = lseek(srcfd, 0, SEEK_SET);
1237 n = lseek(dstfd, 0, SEEK_SET);
1238 return TriStateResult::Failed;
1242 return TriStateResult::Success;
1245 return TriStateResult::NotSupported;
1256 auto tryMkDir = [&path, mode]() -> QSystemError {
1257 if (QT_MKDIR(path, mode) == 0) {
1259 forceRequestedPermissionsOnVxWorks(path, mode);
1264 if (errno == EISDIR)
1266 if (errno == EEXIST || errno == EROFS) {
1270 if (QT_STAT(path.constData(), &st) != 0)
1271 return QSystemError::stdError(errno);
1272 const bool isDir = (st.st_mode & S_IFMT) == S_IFDIR;
1273 return isDir ? QSystemError{} : QSystemError::stdError(EEXIST);
1275 return QSystemError::stdError(errno);
1278 QSystemError result = tryMkDir();
1283 if (result.errorCode != ENOENT)
1286 qsizetype slash = path.lastIndexOf(
'/');
1287 while (slash > 0 && path[slash - 1] ==
'/')
1294 QByteArray parentPath = path.first(slash);
1295 if (result = createDirectoryWithParents(parentPath, mode); !result.ok())
1302bool QFileSystemEngine::mkpath(
const QFileSystemEntry &entry,
1303 std::optional<QFile::Permissions> permissions)
1305 QByteArray path = entry.nativeFilePath();
1308 mode_t mode = permissions ? QtPrivate::toMode_t(*permissions) : 0777;
1309 return createDirectoryWithParents(removeTrailingSlashes(path), mode).ok();
1312bool QFileSystemEngine::mkdir(
const QFileSystemEntry &entry,
1313 std::optional<QFile::Permissions> permissions)
1315 QByteArray path = entry.nativeFilePath();
1318 mode_t mode = permissions ? QtPrivate::toMode_t(*permissions) : 0777;
1319 auto result = QT_MKDIR(removeTrailingSlashes(path), mode) == 0;
1320#if defined(Q_OS_VXWORKS)
1322 forceRequestedPermissionsOnVxWorks(path, mode);
1327bool QFileSystemEngine::rmdir(
const QFileSystemEntry &entry)
1329 const QByteArray path = entry.nativeFilePath();
1331 return ::rmdir(path.constData()) == 0;
1334bool QFileSystemEngine::rmpath(
const QFileSystemEntry &entry)
1336 QByteArray path = QFile::encodeName(QDir::cleanPath(entry.filePath()));
1339 if (::rmdir(path.constData()) != 0)
1342 const char sep = QDir::separator().toLatin1();
1343 qsizetype slash = path.lastIndexOf(sep);
1345 for (; slash > 0; slash = path.lastIndexOf(sep)) {
1346 path.truncate(slash);
1347 if (::rmdir(path.constData()) != 0)
1355bool QFileSystemEngine::createLink(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1360 if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
1362 error = QSystemError(errno, QSystemError::StandardLibraryError);
1366#if defined(QT_BOOTSTRAPPED) || !defined(AT_FDCWD) || defined(Q_OS_ANDROID) || !QT_CONFIG(datestring) || defined(Q_OS_VXWORKS)
1369bool QFileSystemEngine::supportsMoveFileToTrash()
1375bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &, QFileSystemEntry &,
1376 QSystemError &error)
1378 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1381#elif defined(Q_OS_DARWIN)
1385
1386
1388bool QFileSystemEngine::supportsMoveFileToTrash()
1394struct FreeDesktopTrashOperation
1397
1398
1400 int filesDirFd = -1;
1402 qsizetype volumePrefixLength = 0;
1405 QByteArray tempTrashFileName;
1406 QByteArray infoFilePath;
1408 int infoFileFd = -1;
1409 ~FreeDesktopTrashOperation()
1414 constexpr bool isTrashDirOpen()
const {
return filesDirFd != -1 && infoDirFd != -1; }
1418 int savedErrno = errno;
1419 if (infoFileFd != -1) {
1420 Q_ASSERT(infoDirFd != -1);
1421 Q_ASSERT(!infoFilePath.isEmpty());
1422 Q_ASSERT(!trashPath.isEmpty());
1424 QT_CLOSE(infoFileFd);
1425 unlinkat(infoDirFd, infoFilePath, 0);
1428 if (!tempTrashFileName.isEmpty()) {
1429 Q_ASSERT(filesDirFd != -1);
1430 unlinkat(filesDirFd, tempTrashFileName, 0);
1432 if (filesDirFd >= 0)
1433 QT_CLOSE(filesDirFd);
1435 QT_CLOSE(infoDirFd);
1436 filesDirFd = infoDirFd = -1;
1440 bool tryCreateInfoFile(
const QString &filePath, QSystemError &error)
1442 QByteArray p = QFile::encodeName(filePath) +
".trashinfo";
1443 infoFileFd = qt_safe_openat(infoDirFd, p, QT_OPEN_RDWR | QT_OPEN_CREAT | QT_OPEN_EXCL, 0666);
1444 if (infoFileFd < 0) {
1445 error = QSystemError(errno, QSystemError::StandardLibraryError);
1448 infoFilePath = std::move(p);
1454 QT_CLOSE(infoFileFd);
1456 tempTrashFileName = {};
1460 static int openDirFd(
int dfd,
const char *path,
int mode)
1462 mode |= QT_OPEN_RDONLY | O_DIRECTORY;
1463 return qt_safe_openat(dfd, path, mode);
1467 static int openOrCreateDir(
int dfd,
const char *path,
int openmode = 0)
1470 int fd = openDirFd(dfd, path, openmode);
1471 if (fd >= 0 || errno != ENOENT)
1475 if (mkdirat(dfd, path, 0700) < 0)
1479 return openDirFd(dfd, path, openmode);
1483 QSystemError getTrashDir(
int parentfd, QString targetDir,
const QFileSystemEntry &source,
1486 if (parentfd == AT_FDCWD)
1487 trashPath = targetDir;
1488 QByteArray nativePath = QFile::encodeName(targetDir);
1491 int trashfd = openOrCreateDir(parentfd, nativePath, openmode);
1492 if (trashfd < 0 && errno != ENOENT)
1493 return QSystemError::stdError(errno);
1496 if (QT_STATBUF st; QT_FSTAT(trashfd, &st) < 0)
1497 return QSystemError::stdError(errno);
1498 else if (st.st_uid != getuid())
1499 return QSystemError::stdError(errno);
1501 filesDirFd = openOrCreateDir(trashfd,
"files");
1502 if (filesDirFd >= 0) {
1504 QTemporaryFileName tfn(
"XXXXXX"_L1);
1505 for (
int i = 0; i < 16; ++i) {
1506 QByteArray attempt = tfn.generateNext();
1507 if (linkat(AT_FDCWD, source.nativeFilePath(), filesDirFd, attempt, 0) == 0) {
1508 tempTrashFileName = std::move(attempt);
1511 if (errno != EEXIST)
1522 if (!tempTrashFileName.isEmpty() || errno == EPERM || errno == EMLINK)
1523 infoDirFd = openOrCreateDir(trashfd,
"info");
1526 if (infoDirFd < 0) {
1527 int saved_errno = errno;
1530 return QSystemError::stdError(saved_errno);
1537 QSystemError openMountPointTrashLocation(
const QFileSystemEntry &source,
1538 const QStorageInfo &sourceStorage)
1541
1542
1543
1544
1545
1546
1547
1548
1549
1552 const auto dotTrash =
"/.Trash"_L1;
1553 const QString userID = QString::number(::getuid());
1554 QFileSystemEntry dotTrashDir(sourceStorage.rootPath() + dotTrash);
1557 int genericTrashFd = openDirFd(AT_FDCWD, dotTrashDir.nativeFilePath(), O_NOFOLLOW);
1559 if (genericTrashFd < 0 && errno != ENOENT && errno != EACCES) {
1561 if (QT_LSTAT(dotTrashDir.nativeFilePath(), &st) == 0 && S_ISLNK(st.st_mode)) {
1563 qCritical(
"Warning: '%s' is a symlink to '%s'",
1564 dotTrashDir.nativeFilePath().constData(),
1565 qt_readlink(dotTrashDir.nativeFilePath()).constData());
1566 error = QSystemError(ELOOP, QSystemError::StandardLibraryError);
1568 }
else if (genericTrashFd >= 0) {
1569 QT_FSTAT(genericTrashFd, &st);
1570 if ((st.st_mode & S_ISVTX) == 0) {
1572 qCritical(
"Warning: '%s' doesn't have sticky bit set!",
1573 dotTrashDir.nativeFilePath().constData());
1574 error = QSystemError(EPERM, QSystemError::StandardLibraryError);
1577
1578
1579
1580
1581
1582
1583
1584
1585 if (error = getTrashDir(genericTrashFd, userID, source, O_NOFOLLOW); error.ok()) {
1587 trashPath = dotTrashDir.filePath() + u'/' + userID;
1590 QT_CLOSE(genericTrashFd);
1594
1595
1596
1597
1598
1599
1600 if (!isTrashDirOpen())
1601 error = getTrashDir(AT_FDCWD, sourceStorage.rootPath() + dotTrash + u'-' + userID, source,
1604 if (isTrashDirOpen()) {
1605 volumePrefixLength = sourceStorage.rootPath().size();
1606 if (volumePrefixLength == 1)
1607 volumePrefixLength = 0;
1609 ++volumePrefixLength;
1611 return isTrashDirOpen() ? QSystemError() : error;
1614 QSystemError openHomeTrashLocation(
const QFileSystemEntry &source)
1616 QString topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
1618 return getTrashDir(AT_FDCWD, topDir +
"/Trash"_L1, source, openmode);
1621 QSystemError findTrashFor(
const QFileSystemEntry &source)
1624
1625
1626
1627
1628
1629 if (QSystemError error = openHomeTrashLocation(source); error.ok())
1630 return QSystemError();
1631 else if (error.errorCode != EXDEV)
1635 const QStorageInfo sourceStorage(source.filePath());
1636 if (!sourceStorage.isValid())
1637 return QSystemError::stdError(ENODEV);
1638 return openMountPointTrashLocation(source, sourceStorage);
1644bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &source,
1645 QFileSystemEntry &newLocation, QSystemError &error)
1647 const QFileSystemEntry sourcePath = [&] {
1648 if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) {
1650 return absoluteName(QFileSystemEntry(path));
1652 return absoluteName(source);
1654 FreeDesktopTrashOperation op;
1655 if (error = op.findTrashFor(sourcePath); !error.ok())
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678 QString uniqueTrashedName = sourcePath.fileName();
1679 if (!op.tryCreateInfoFile(uniqueTrashedName, error) && error.errorCode == EEXIST) {
1683 if (QT_STATBUF st; Q_LIKELY(QT_STAT(source.nativeFilePath(), &st) == 0)) {
1684 counter = st.st_ino;
1686 error = QSystemError(errno, QSystemError::StandardLibraryError);
1690 QString uniqueTrashBase = std::move(uniqueTrashedName);
1692 uniqueTrashedName = QString::asprintf(
"%ls-%llu", qUtf16Printable(uniqueTrashBase),
1694 if (op.tryCreateInfoFile(uniqueTrashedName, error))
1696 if (error.errorCode != EEXIST)
1703 "Path=" + QUrl::toPercentEncoding(source.filePath().mid(op.volumePrefixLength),
"/") +
"\n"
1704 "DeletionDate=" + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8()
1706 if (QT_WRITE(op.infoFileFd, info.data(), info.size()) < 0) {
1707 error = QSystemError(errno, QSystemError::StandardLibraryError);
1712
1713
1714
1715
1717 if (op.tempTrashFileName.isEmpty()) {
1719
1720
1721
1722
1723
1724 renamed = renameat(AT_FDCWD, source.nativeFilePath(), op.filesDirFd,
1725 QFile::encodeName(uniqueTrashedName)) == 0;
1727 renamed = renameat(op.filesDirFd, op.tempTrashFileName, op.filesDirFd,
1728 QFile::encodeName(uniqueTrashedName)) == 0;
1730 removeFile(sourcePath, error);
1733 error = QSystemError(errno, QSystemError::StandardLibraryError);
1738 newLocation = QFileSystemEntry(op.trashPath +
"/files/"_L1 + uniqueTrashedName);
1744bool QFileSystemEngine::copyFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1748 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1753bool QFileSystemEngine::renameFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1755 QFileSystemEntry::NativePath srcPath = source.nativeFilePath();
1756 QFileSystemEntry::NativePath tgtPath = target.nativeFilePath();
1761#if defined(RENAME_NOREPLACE
) && QT_CONFIG(renameat2)
1762 if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0)
1766 if (errno != EINVAL) {
1767 error = QSystemError(errno, QSystemError::StandardLibraryError);
1771#if defined(Q_OS_DARWIN) && defined(RENAME_EXCL)
1772 if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0)
1774 if (errno != ENOTSUP) {
1775 error = QSystemError(errno, QSystemError::StandardLibraryError);
1780 if (SupportsHardlinking && ::link(srcPath, tgtPath) == 0) {
1781 if (::unlink(srcPath) == 0)
1787 int savedErrno = errno;
1792 error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
1794 }
else if (!SupportsHardlinking) {
1816 if (::rename(srcPath, tgtPath) == 0)
1820 error = QSystemError(errno, QSystemError::StandardLibraryError);
1825bool QFileSystemEngine::renameOverwriteFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1830 if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
1832 error = QSystemError(errno, QSystemError::StandardLibraryError);
1837bool QFileSystemEngine::removeFile(
const QFileSystemEntry &entry, QSystemError &error)
1840 if (unlink(entry.nativeFilePath().constData()) == 0)
1842 error = QSystemError(errno, QSystemError::StandardLibraryError);
1848bool QFileSystemEngine::setPermissions(
const QFileSystemEntry &entry,
1849 QFile::Permissions permissions, QSystemError &error)
1853 mode_t mode = QtPrivate::toMode_t(permissions);
1854 bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
1856 error = QSystemError(errno, QSystemError::StandardLibraryError);
1861bool QFileSystemEngine::setPermissions(
int fd, QFile::Permissions permissions, QSystemError &error)
1863 mode_t mode = QtPrivate::toMode_t(permissions);
1864 bool success = ::fchmod(fd, mode) == 0;
1866 error = QSystemError(errno, QSystemError::StandardLibraryError);
1871bool QFileSystemEngine::setFileTime(
int fd,
const QDateTime &newDate, QFile::FileTime time, QSystemError &error)
1873 if (!newDate.isValid()
1874 || time == QFile::FileBirthTime || time == QFile::FileMetadataChangeTime) {
1875 error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
1879#if QT_CONFIG(futimens)
1881 struct timespec ts[2] = {{0, UTIME_OMIT}, {0, UTIME_OMIT}};
1883 if (time == QFile::FileAccessTime || time == QFile::FileModificationTime) {
1884 const int idx = time == QFile::FileAccessTime ? 0 : 1;
1885 const std::chrono::milliseconds msecs{newDate.toMSecsSinceEpoch()};
1886 ts[idx] = durationToTimespec(msecs);
1889 if (futimens(fd, ts) == -1) {
1890 error = QSystemError(errno, QSystemError::StandardLibraryError);
1897 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1902QString QFileSystemEngine::homePath()
1904 QString home = qEnvironmentVariable(
"HOME");
1907 return QDir::cleanPath(home);
1910QString QFileSystemEngine::rootPath()
1918 QLatin1StringView temp =
_PATH_TMP ""_L1;
1919 static_assert(
_PATH_TMP[0] ==
'/',
"_PATH_TMP needs to be absolute");
1920 static_assert(
_PATH_TMP[1] !=
'\0',
"Are you really sure _PATH_TMP should be the root dir??");
1921 if (temp.endsWith(u'/'))
1926QString QFileSystemEngine::tempPath()
1928#ifdef QT_UNIX_TEMP_PATH_OVERRIDE
1929 return QT_UNIX_TEMP_PATH_OVERRIDE
""_L1;
1931 QString temp = qEnvironmentVariable(
"TMPDIR");
1932# if defined(Q_OS_DARWIN) && !defined(QT_BOOTSTRAPPED)
1933 if (NSString *nsPath; temp.isEmpty() && (nsPath = NSTemporaryDirectory()))
1934 temp = QString::fromCFString((CFStringRef)nsPath);
1937 return nativeTempPath();
1940 if (temp.size() > 1 && temp.endsWith(u'/'))
1943 QFileSystemEntry e(temp, QFileSystemEntry::FromInternalPath{});
1944 return QFileSystemEngine::absoluteName(e).filePath();
1948bool QFileSystemEngine::setCurrentPath(
const QFileSystemEntry &path)
1951 r = QT_CHDIR(path.nativeFilePath().constData());
1955QFileSystemEntry QFileSystemEngine::currentPath()
1957 QFileSystemEntry result;
1958#if defined(__GLIBC__
) && !defined(PATH_MAX)
1959 char *currentName = ::get_current_dir_name();
1961 result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
1962 ::free(currentName);
1965 char currentName[PATH_MAX+1];
1966 if (::getcwd(currentName, PATH_MAX)) {
1967#if defined(Q_OS_VXWORKS) && defined(VXWORKS_VXSIM)
1968 QByteArray dir(currentName);
1969 if (dir.indexOf(
':') < dir.indexOf(
'/'))
1970 dir.remove(0, dir.indexOf(
':')+1);
1972 qstrncpy(currentName, dir.constData(), PATH_MAX);
1974 result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
1976# if defined(QT_DEBUG)
1977 if (result.isEmpty())
1978 qWarning(
"QFileSystemEngine::currentPath: getcwd() failed");
1984bool QFileSystemEngine::isCaseSensitive(
const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
1986#if defined(Q_OS_DARWIN)
1987 if (!metaData.hasFlags(QFileSystemMetaData::CaseSensitive))
1988 fillMetaData(entry, metaData, QFileSystemMetaData::CaseSensitive);
1989 return metaData.entryFlags.testFlag(QFileSystemMetaData::CaseSensitive);
#define Q_CHECK_FILE_NAME(name, result)
static int qt_lstatx(const char *, struct statx *)
static int qt_fstatx(int, struct statx *)
static QFileSystemMetaData::MetaDataFlags flagsFromStMode(mode_t mode, quint64 attributes)
static QByteArray & removeTrailingSlashes(QByteArray &path)
static QSystemError createDirectoryWithParents(const QByteArray &path, mode_t mode)
static constexpr QLatin1StringView nativeTempPath() noexcept
static int qt_statx(const char *, struct statx *)