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;
1201 return TriStateResult::Failed;
1204#if defined(Q_OS_LINUX)
1207 const size_t SendfileSize = 0x7ffff000;
1209 ssize_t n = ::sendfile(dstfd, srcfd,
nullptr, SendfileSize);
1214 return TriStateResult::Failed;
1218 return TriStateResult::NotSupported;
1222 n = ::sendfile(dstfd, srcfd,
nullptr, SendfileSize);
1225 n = ftruncate(dstfd, 0);
1226 n = lseek(srcfd, 0, SEEK_SET);
1227 n = lseek(dstfd, 0, SEEK_SET);
1228 return TriStateResult::Failed;
1232 return TriStateResult::Success;
1235 return TriStateResult::NotSupported;
1246 auto tryMkDir = [&path, mode]() -> QSystemError {
1247 if (QT_MKDIR(path, mode) == 0) {
1249 forceRequestedPermissionsOnVxWorks(path, mode);
1254 if (errno == EISDIR)
1256 if (errno == EEXIST || errno == EROFS) {
1260 if (QT_STAT(path.constData(), &st) != 0)
1261 return QSystemError::stdError(errno);
1262 const bool isDir = (st.st_mode & S_IFMT) == S_IFDIR;
1263 return isDir ? QSystemError{} : QSystemError::stdError(EEXIST);
1265 return QSystemError::stdError(errno);
1268 QSystemError result = tryMkDir();
1273 if (result.errorCode != ENOENT)
1276 qsizetype slash = path.lastIndexOf(
'/');
1277 while (slash > 0 && path[slash - 1] ==
'/')
1284 QByteArray parentPath = path.first(slash);
1285 if (result = createDirectoryWithParents(parentPath, mode); !result.ok())
1292bool QFileSystemEngine::mkpath(
const QFileSystemEntry &entry,
1293 std::optional<QFile::Permissions> permissions)
1295 QByteArray path = entry.nativeFilePath();
1298 mode_t mode = permissions ? QtPrivate::toMode_t(*permissions) : 0777;
1299 return createDirectoryWithParents(removeTrailingSlashes(path), mode).ok();
1302bool QFileSystemEngine::mkdir(
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 auto result = QT_MKDIR(removeTrailingSlashes(path), mode) == 0;
1310#if defined(Q_OS_VXWORKS)
1312 forceRequestedPermissionsOnVxWorks(path, mode);
1317bool QFileSystemEngine::rmdir(
const QFileSystemEntry &entry)
1319 const QByteArray path = entry.nativeFilePath();
1321 return ::rmdir(path.constData()) == 0;
1324bool QFileSystemEngine::rmpath(
const QFileSystemEntry &entry)
1326 QByteArray path = QFile::encodeName(QDir::cleanPath(entry.filePath()));
1329 if (::rmdir(path.constData()) != 0)
1332 const char sep = QDir::separator().toLatin1();
1333 qsizetype slash = path.lastIndexOf(sep);
1335 for (; slash > 0; slash = path.lastIndexOf(sep)) {
1336 path.truncate(slash);
1337 if (::rmdir(path.constData()) != 0)
1345bool QFileSystemEngine::createLink(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1350 if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
1352 error = QSystemError(errno, QSystemError::StandardLibraryError);
1356#if defined(QT_BOOTSTRAPPED) || !defined(AT_FDCWD) || defined(Q_OS_ANDROID) || !QT_CONFIG(datestring) || defined(Q_OS_VXWORKS)
1359bool QFileSystemEngine::supportsMoveFileToTrash()
1365bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &, QFileSystemEntry &,
1366 QSystemError &error)
1368 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1371#elif defined(Q_OS_DARWIN)
1375
1376
1378bool QFileSystemEngine::supportsMoveFileToTrash()
1384struct FreeDesktopTrashOperation
1387
1388
1390 int filesDirFd = -1;
1392 qsizetype volumePrefixLength = 0;
1395 QByteArray tempTrashFileName;
1396 QByteArray infoFilePath;
1398 int infoFileFd = -1;
1399 ~FreeDesktopTrashOperation()
1404 constexpr bool isTrashDirOpen()
const {
return filesDirFd != -1 && infoDirFd != -1; }
1408 int savedErrno = errno;
1409 if (infoFileFd != -1) {
1410 Q_ASSERT(infoDirFd != -1);
1411 Q_ASSERT(!infoFilePath.isEmpty());
1412 Q_ASSERT(!trashPath.isEmpty());
1414 QT_CLOSE(infoFileFd);
1415 unlinkat(infoDirFd, infoFilePath, 0);
1418 if (!tempTrashFileName.isEmpty()) {
1419 Q_ASSERT(filesDirFd != -1);
1420 unlinkat(filesDirFd, tempTrashFileName, 0);
1422 if (filesDirFd >= 0)
1423 QT_CLOSE(filesDirFd);
1425 QT_CLOSE(infoDirFd);
1426 filesDirFd = infoDirFd = -1;
1430 bool tryCreateInfoFile(
const QString &filePath, QSystemError &error)
1432 QByteArray p = QFile::encodeName(filePath) +
".trashinfo";
1433 infoFileFd = qt_safe_openat(infoDirFd, p, QT_OPEN_RDWR | QT_OPEN_CREAT | QT_OPEN_EXCL, 0666);
1434 if (infoFileFd < 0) {
1435 error = QSystemError(errno, QSystemError::StandardLibraryError);
1438 infoFilePath = std::move(p);
1444 QT_CLOSE(infoFileFd);
1446 tempTrashFileName = {};
1450 static int openDirFd(
int dfd,
const char *path,
int mode)
1452 mode |= QT_OPEN_RDONLY | O_DIRECTORY;
1453 return qt_safe_openat(dfd, path, mode);
1457 static int openOrCreateDir(
int dfd,
const char *path,
int openmode = 0)
1460 int fd = openDirFd(dfd, path, openmode);
1461 if (fd >= 0 || errno != ENOENT)
1465 if (mkdirat(dfd, path, 0700) < 0)
1469 return openDirFd(dfd, path, openmode);
1473 QSystemError getTrashDir(
int parentfd, QString targetDir,
const QFileSystemEntry &source,
1476 if (parentfd == AT_FDCWD)
1477 trashPath = targetDir;
1478 QByteArray nativePath = QFile::encodeName(targetDir);
1481 int trashfd = openOrCreateDir(parentfd, nativePath, openmode);
1482 if (trashfd < 0 && errno != ENOENT)
1483 return QSystemError::stdError(errno);
1486 if (QT_STATBUF st; QT_FSTAT(trashfd, &st) < 0)
1487 return QSystemError::stdError(errno);
1488 else if (st.st_uid != getuid())
1489 return QSystemError::stdError(errno);
1491 filesDirFd = openOrCreateDir(trashfd,
"files");
1492 if (filesDirFd >= 0) {
1494 QTemporaryFileName tfn(
"XXXXXX"_L1);
1495 for (
int i = 0; i < 16; ++i) {
1496 QByteArray attempt = tfn.generateNext();
1497 if (linkat(AT_FDCWD, source.nativeFilePath(), filesDirFd, attempt, 0) == 0) {
1498 tempTrashFileName = std::move(attempt);
1501 if (errno != EEXIST)
1512 if (!tempTrashFileName.isEmpty() || errno == EPERM || errno == EMLINK)
1513 infoDirFd = openOrCreateDir(trashfd,
"info");
1516 if (infoDirFd < 0) {
1517 int saved_errno = errno;
1520 return QSystemError::stdError(saved_errno);
1527 QSystemError openMountPointTrashLocation(
const QFileSystemEntry &source,
1528 const QStorageInfo &sourceStorage)
1531
1532
1533
1534
1535
1536
1537
1538
1539
1542 const auto dotTrash =
"/.Trash"_L1;
1543 const QString userID = QString::number(::getuid());
1544 QFileSystemEntry dotTrashDir(sourceStorage.rootPath() + dotTrash);
1547 int genericTrashFd = openDirFd(AT_FDCWD, dotTrashDir.nativeFilePath(), O_NOFOLLOW);
1549 if (genericTrashFd < 0 && errno != ENOENT && errno != EACCES) {
1551 if (QT_LSTAT(dotTrashDir.nativeFilePath(), &st) == 0 && S_ISLNK(st.st_mode)) {
1553 qCritical(
"Warning: '%s' is a symlink to '%s'",
1554 dotTrashDir.nativeFilePath().constData(),
1555 qt_readlink(dotTrashDir.nativeFilePath()).constData());
1556 error = QSystemError(ELOOP, QSystemError::StandardLibraryError);
1558 }
else if (genericTrashFd >= 0) {
1559 QT_FSTAT(genericTrashFd, &st);
1560 if ((st.st_mode & S_ISVTX) == 0) {
1562 qCritical(
"Warning: '%s' doesn't have sticky bit set!",
1563 dotTrashDir.nativeFilePath().constData());
1564 error = QSystemError(EPERM, QSystemError::StandardLibraryError);
1567
1568
1569
1570
1571
1572
1573
1574
1575 if (error = getTrashDir(genericTrashFd, userID, source, O_NOFOLLOW); error.ok()) {
1577 trashPath = dotTrashDir.filePath() + u'/' + userID;
1580 QT_CLOSE(genericTrashFd);
1584
1585
1586
1587
1588
1589
1590 if (!isTrashDirOpen())
1591 error = getTrashDir(AT_FDCWD, sourceStorage.rootPath() + dotTrash + u'-' + userID, source,
1594 if (isTrashDirOpen()) {
1595 volumePrefixLength = sourceStorage.rootPath().size();
1596 if (volumePrefixLength == 1)
1597 volumePrefixLength = 0;
1599 ++volumePrefixLength;
1601 return isTrashDirOpen() ? QSystemError() : error;
1604 QSystemError openHomeTrashLocation(
const QFileSystemEntry &source)
1606 QString topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
1608 return getTrashDir(AT_FDCWD, topDir +
"/Trash"_L1, source, openmode);
1611 QSystemError findTrashFor(
const QFileSystemEntry &source)
1614
1615
1616
1617
1618
1619 if (QSystemError error = openHomeTrashLocation(source); error.ok())
1620 return QSystemError();
1621 else if (error.errorCode != EXDEV)
1625 const QStorageInfo sourceStorage(source.filePath());
1626 if (!sourceStorage.isValid())
1627 return QSystemError::stdError(ENODEV);
1628 return openMountPointTrashLocation(source, sourceStorage);
1634bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &source,
1635 QFileSystemEntry &newLocation, QSystemError &error)
1637 const QFileSystemEntry sourcePath = [&] {
1638 if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) {
1640 return absoluteName(QFileSystemEntry(path));
1642 return absoluteName(source);
1644 FreeDesktopTrashOperation op;
1645 if (error = op.findTrashFor(sourcePath); !error.ok())
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668 QString uniqueTrashedName = sourcePath.fileName();
1669 if (!op.tryCreateInfoFile(uniqueTrashedName, error) && error.errorCode == EEXIST) {
1673 if (QT_STATBUF st; Q_LIKELY(QT_STAT(source.nativeFilePath(), &st) == 0)) {
1674 counter = st.st_ino;
1676 error = QSystemError(errno, QSystemError::StandardLibraryError);
1680 QString uniqueTrashBase = std::move(uniqueTrashedName);
1682 uniqueTrashedName = QString::asprintf(
"%ls-%llu", qUtf16Printable(uniqueTrashBase),
1684 if (op.tryCreateInfoFile(uniqueTrashedName, error))
1686 if (error.errorCode != EEXIST)
1693 "Path=" + QUrl::toPercentEncoding(source.filePath().mid(op.volumePrefixLength),
"/") +
"\n"
1694 "DeletionDate=" + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8()
1696 if (QT_WRITE(op.infoFileFd, info.data(), info.size()) < 0) {
1697 error = QSystemError(errno, QSystemError::StandardLibraryError);
1702
1703
1704
1705
1707 if (op.tempTrashFileName.isEmpty()) {
1709
1710
1711
1712
1713
1714 renamed = renameat(AT_FDCWD, source.nativeFilePath(), op.filesDirFd,
1715 QFile::encodeName(uniqueTrashedName)) == 0;
1717 renamed = renameat(op.filesDirFd, op.tempTrashFileName, op.filesDirFd,
1718 QFile::encodeName(uniqueTrashedName)) == 0;
1720 removeFile(sourcePath, error);
1723 error = QSystemError(errno, QSystemError::StandardLibraryError);
1728 newLocation = QFileSystemEntry(op.trashPath +
"/files/"_L1 + uniqueTrashedName);
1734bool QFileSystemEngine::copyFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1738 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1743bool QFileSystemEngine::renameFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1745 QFileSystemEntry::NativePath srcPath = source.nativeFilePath();
1746 QFileSystemEntry::NativePath tgtPath = target.nativeFilePath();
1751#if defined(RENAME_NOREPLACE
) && QT_CONFIG(renameat2)
1752 if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0)
1756 if (errno != EINVAL) {
1757 error = QSystemError(errno, QSystemError::StandardLibraryError);
1761#if defined(Q_OS_DARWIN) && defined(RENAME_EXCL)
1762 if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0)
1764 if (errno != ENOTSUP) {
1765 error = QSystemError(errno, QSystemError::StandardLibraryError);
1770 if (SupportsHardlinking && ::link(srcPath, tgtPath) == 0) {
1771 if (::unlink(srcPath) == 0)
1777 int savedErrno = errno;
1782 error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
1784 }
else if (!SupportsHardlinking) {
1806 if (::rename(srcPath, tgtPath) == 0)
1810 error = QSystemError(errno, QSystemError::StandardLibraryError);
1815bool QFileSystemEngine::renameOverwriteFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target, QSystemError &error)
1820 if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
1822 error = QSystemError(errno, QSystemError::StandardLibraryError);
1827bool QFileSystemEngine::removeFile(
const QFileSystemEntry &entry, QSystemError &error)
1830 if (unlink(entry.nativeFilePath().constData()) == 0)
1832 error = QSystemError(errno, QSystemError::StandardLibraryError);
1838bool QFileSystemEngine::setPermissions(
const QFileSystemEntry &entry,
1839 QFile::Permissions permissions, QSystemError &error)
1843 mode_t mode = QtPrivate::toMode_t(permissions);
1844 bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
1846 error = QSystemError(errno, QSystemError::StandardLibraryError);
1851bool QFileSystemEngine::setPermissions(
int fd, QFile::Permissions permissions, QSystemError &error)
1853 mode_t mode = QtPrivate::toMode_t(permissions);
1854 bool success = ::fchmod(fd, mode) == 0;
1856 error = QSystemError(errno, QSystemError::StandardLibraryError);
1861bool QFileSystemEngine::setFileTime(
int fd,
const QDateTime &newDate, QFile::FileTime time, QSystemError &error)
1863 if (!newDate.isValid()
1864 || time == QFile::FileBirthTime || time == QFile::FileMetadataChangeTime) {
1865 error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
1869#if QT_CONFIG(futimens)
1871 struct timespec ts[2] = {{0, UTIME_OMIT}, {0, UTIME_OMIT}};
1873 if (time == QFile::FileAccessTime || time == QFile::FileModificationTime) {
1874 const int idx = time == QFile::FileAccessTime ? 0 : 1;
1875 const std::chrono::milliseconds msecs{newDate.toMSecsSinceEpoch()};
1876 ts[idx] = durationToTimespec(msecs);
1879 if (futimens(fd, ts) == -1) {
1880 error = QSystemError(errno, QSystemError::StandardLibraryError);
1887 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1892QString QFileSystemEngine::homePath()
1894 QString home = qEnvironmentVariable(
"HOME");
1897 return QDir::cleanPath(home);
1900QString QFileSystemEngine::rootPath()
1908 QLatin1StringView temp =
_PATH_TMP ""_L1;
1909 static_assert(
_PATH_TMP[0] ==
'/',
"_PATH_TMP needs to be absolute");
1910 static_assert(
_PATH_TMP[1] !=
'\0',
"Are you really sure _PATH_TMP should be the root dir??");
1911 if (temp.endsWith(u'/'))
1916QString QFileSystemEngine::tempPath()
1918#ifdef QT_UNIX_TEMP_PATH_OVERRIDE
1919 return QT_UNIX_TEMP_PATH_OVERRIDE
""_L1;
1921 QString temp = qEnvironmentVariable(
"TMPDIR");
1922# if defined(Q_OS_DARWIN) && !defined(QT_BOOTSTRAPPED)
1923 if (NSString *nsPath; temp.isEmpty() && (nsPath = NSTemporaryDirectory()))
1924 temp = QString::fromCFString((CFStringRef)nsPath);
1927 return nativeTempPath();
1930 if (temp.size() > 1 && temp.endsWith(u'/'))
1933 QFileSystemEntry e(temp, QFileSystemEntry::FromInternalPath{});
1934 return QFileSystemEngine::absoluteName(e).filePath();
1938bool QFileSystemEngine::setCurrentPath(
const QFileSystemEntry &path)
1941 r = QT_CHDIR(path.nativeFilePath().constData());
1945QFileSystemEntry QFileSystemEngine::currentPath()
1947 QFileSystemEntry result;
1948#if defined(__GLIBC__
) && !defined(PATH_MAX)
1949 char *currentName = ::get_current_dir_name();
1951 result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
1952 ::free(currentName);
1955 char currentName[PATH_MAX+1];
1956 if (::getcwd(currentName, PATH_MAX)) {
1957#if defined(Q_OS_VXWORKS) && defined(VXWORKS_VXSIM)
1958 QByteArray dir(currentName);
1959 if (dir.indexOf(
':') < dir.indexOf(
'/'))
1960 dir.remove(0, dir.indexOf(
':')+1);
1962 qstrncpy(currentName, dir.constData(), PATH_MAX);
1964 result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
1966# if defined(QT_DEBUG)
1967 if (result.isEmpty())
1968 qWarning(
"QFileSystemEngine::currentPath: getcwd() failed");
1974bool QFileSystemEngine::isCaseSensitive(
const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
1976#if defined(Q_OS_DARWIN)
1977 if (!metaData.hasFlags(QFileSystemMetaData::CaseSensitive))
1978 fillMetaData(entry, metaData, QFileSystemMetaData::CaseSensitive);
1979 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 *)