// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QFILESYSTEMMETADATA_P_H #define QFILESYSTEMMETADATA_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qplatformdefs.h" #include #include #include #include // Platform-specific includes #ifdef Q_OS_WIN # include # ifndef IO_REPARSE_TAG_SYMLINK # define IO_REPARSE_TAG_SYMLINK (0xA000000CL) # endif #endif #ifdef Q_OS_UNIX struct statx; #endif QT_BEGIN_NAMESPACE class QFileSystemEngine; class Q_AUTOTEST_EXPORT QFileSystemMetaData { public: QFileSystemMetaData() : size_(-1) { } enum MetaDataFlag { // Permissions, overlaps with QFile::Permissions OtherReadPermission = 0x00000004, OtherWritePermission = 0x00000002, OtherExecutePermission = 0x00000001, GroupReadPermission = 0x00000040, GroupWritePermission = 0x00000020, GroupExecutePermission = 0x00000010, UserReadPermission = 0x00000400, UserWritePermission = 0x00000200, UserExecutePermission = 0x00000100, OwnerReadPermission = 0x00004000, OwnerWritePermission = 0x00002000, OwnerExecutePermission = 0x00001000, OtherPermissions = OtherReadPermission | OtherWritePermission | OtherExecutePermission, GroupPermissions = GroupReadPermission | GroupWritePermission | GroupExecutePermission, UserPermissions = UserReadPermission | UserWritePermission | UserExecutePermission, OwnerPermissions = OwnerReadPermission | OwnerWritePermission | OwnerExecutePermission, ReadPermissions = OtherReadPermission | GroupReadPermission | UserReadPermission | OwnerReadPermission, WritePermissions = OtherWritePermission | GroupWritePermission | UserWritePermission | OwnerWritePermission, ExecutePermissions = OtherExecutePermission | GroupExecutePermission | UserExecutePermission | OwnerExecutePermission, Permissions = OtherPermissions | GroupPermissions | UserPermissions | OwnerPermissions, // Type LinkType = 0x00010000, FileType = 0x00020000, DirectoryType = 0x00040000, #if defined(Q_OS_DARWIN) BundleType = 0x00080000, AliasType = 0x08000000, #else BundleType = 0x0, AliasType = 0x0, #endif #if defined(Q_OS_WIN) JunctionType = 0x04000000, WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac #else JunctionType = 0x0, WinLnkType = 0x0, #endif SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag LegacyLinkType = LinkType | AliasType | WinLnkType, Type = LinkType | FileType | DirectoryType | BundleType | SequentialType | AliasType, // Attributes HiddenAttribute = 0x00100000, SizeAttribute = 0x00200000, // Note: overlaps with QAbstractFileEngine::LocalDiskFlag ExistsAttribute = 0x00400000, // For historical reasons, indicates existence of data, not the file #if defined(Q_OS_WIN) WasDeletedAttribute = 0x0, #else WasDeletedAttribute = 0x40000000, // Indicates the file was deleted #endif Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute | WasDeletedAttribute, // Times - if we know one of them, we know them all AccessTime = 0x02000000, BirthTime = 0x02000000, MetadataChangeTime = 0x02000000, ModificationTime = 0x02000000, Times = AccessTime | BirthTime | MetadataChangeTime | ModificationTime, // Owner IDs UserId = 0x10000000, GroupId = 0x20000000, OwnerIds = UserId | GroupId, PosixStatFlags = QFileSystemMetaData::OtherPermissions | QFileSystemMetaData::GroupPermissions | QFileSystemMetaData::OwnerPermissions | QFileSystemMetaData::FileType | QFileSystemMetaData::DirectoryType | QFileSystemMetaData::SequentialType | QFileSystemMetaData::SizeAttribute | QFileSystemMetaData::WasDeletedAttribute | QFileSystemMetaData::Times | QFileSystemMetaData::OwnerIds, #if defined(Q_OS_WIN) WinStatFlags = QFileSystemMetaData::FileType | QFileSystemMetaData::DirectoryType | QFileSystemMetaData::HiddenAttribute | QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::SizeAttribute | QFileSystemMetaData::Times, #endif AllMetaDataFlags = 0xFFFFFFFF }; Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag) bool hasFlags(MetaDataFlags flags) const { return ((knownFlagsMask & flags) == flags); } MetaDataFlags missingFlags(MetaDataFlags flags) { return flags & ~knownFlagsMask; } void clear() { knownFlagsMask = {}; } void clearFlags(MetaDataFlags flags = AllMetaDataFlags) { knownFlagsMask &= ~flags; } bool exists() const { return entryFlags.testAnyFlag(ExistsAttribute); } bool isLink() const { return entryFlags.testAnyFlag(LinkType); } bool isFile() const { return entryFlags.testAnyFlag(FileType); } bool isDirectory() const { return entryFlags.testAnyFlag(DirectoryType); } bool isBundle() const; bool isAlias() const; bool isLegacyLink() const { return entryFlags.testAnyFlag(LegacyLinkType); } bool isSequential() const { return entryFlags.testAnyFlag(SequentialType); } bool isHidden() const { return entryFlags.testAnyFlag(HiddenAttribute); } bool wasDeleted() const { return entryFlags.testAnyFlag(WasDeletedAttribute); } #if defined(Q_OS_WIN) bool isLnkFile() const { return entryFlags.testAnyFlag(WinLnkType); } bool isJunction() const { return entryFlags.testAnyFlag(JunctionType); } #else bool isLnkFile() const { return false; } bool isJunction() const { return false; } #endif qint64 size() const { return size_; } QFile::Permissions permissions() const; QDateTime accessTime() const; QDateTime birthTime() const; QDateTime metadataChangeTime() const; QDateTime modificationTime() const; QDateTime fileTime(QFile::FileTime time) const; uint userId() const; uint groupId() const; uint ownerId(QAbstractFileEngine::FileOwner owner) const; bool isReadable() const { return permissions().testAnyFlags(QFile::ReadUser); } bool isWritable() const { return permissions().testAnyFlags(QFile::WriteUser); } bool isExecutable() const { return permissions().testAnyFlags(QFile::ExeUser); } #ifdef Q_OS_UNIX void fillFromStatxBuf(const struct statx &statBuffer); void fillFromStatBuf(const QT_STATBUF &statBuffer); void fillFromDirEnt(const QT_DIRENT &statBuffer); #endif #if defined(Q_OS_WIN) inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false); inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false); inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo); #endif private: friend class QFileSystemEngine; MetaDataFlags knownFlagsMask; MetaDataFlags entryFlags; qint64 size_ = 0; // Platform-specific data goes here: #if defined(Q_OS_WIN) DWORD fileAttribute_; FILETIME birthTime_; FILETIME changeTime_; FILETIME lastAccessTime_; FILETIME lastWriteTime_; #else // msec precision qint64 accessTime_ = 0; qint64 birthTime_ = 0; qint64 metadataChangeTime_ = 0; qint64 modificationTime_ = 0; uint userId_ = (uint) -2; uint groupId_ = (uint) -2; #endif }; Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) inline QFile::Permissions QFileSystemMetaData::permissions() const { return QFile::Permissions::fromInt((Permissions & entryFlags).toInt()); } #if defined(Q_OS_DARWIN) inline bool QFileSystemMetaData::isBundle() const { return entryFlags.testAnyFlag(BundleType); } inline bool QFileSystemMetaData::isAlias() const { return entryFlags.testAnyFlag(AliasType); } #else inline bool QFileSystemMetaData::isBundle() const { return false; } inline bool QFileSystemMetaData::isAlias() const { return false; } #endif #if defined(Q_OS_UNIX) || defined (Q_OS_WIN) inline QDateTime QFileSystemMetaData::fileTime(QFile::FileTime time) const { switch (time) { case QFile::FileModificationTime: return modificationTime(); case QFile::FileAccessTime: return accessTime(); case QFile::FileBirthTime: return birthTime(); case QFile::FileMetadataChangeTime: return metadataChangeTime(); } return QDateTime(); } #endif #if defined(Q_OS_UNIX) inline QDateTime QFileSystemMetaData::birthTime() const { return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_, QTimeZone::UTC) : QDateTime(); } inline QDateTime QFileSystemMetaData::metadataChangeTime() const { return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_, QTimeZone::UTC) : QDateTime(); } inline QDateTime QFileSystemMetaData::modificationTime() const { return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(modificationTime_, QTimeZone::UTC) : QDateTime(); } inline QDateTime QFileSystemMetaData::accessTime() const { return accessTime_ ? QDateTime::fromMSecsSinceEpoch(accessTime_, QTimeZone::UTC) : QDateTime(); } inline uint QFileSystemMetaData::userId() const { return userId_; } inline uint QFileSystemMetaData::groupId() const { return groupId_; } inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const { if (owner == QAbstractFileEngine::OwnerUser) return userId(); else return groupId(); } #endif #if defined(Q_OS_WIN) inline uint QFileSystemMetaData::userId() const { return (uint) -2; } inline uint QFileSystemMetaData::groupId() const { return (uint) -2; } inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const { if (owner == QAbstractFileEngine::OwnerUser) return userId(); else return groupId(); } inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot) { fileAttribute_ = fileAttribute; // Ignore the hidden attribute for drives. if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN)) entryFlags |= HiddenAttribute; entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType); entryFlags |= ExistsAttribute; knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute; } inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot) { fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot); birthTime_ = findData.ftCreationTime; lastAccessTime_ = findData.ftLastAccessTime; changeTime_ = lastWriteTime_ = findData.ftLastWriteTime; if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { size_ = 0; } else { size_ = findData.nFileSizeHigh; size_ <<= 32; size_ += findData.nFileSizeLow; } knownFlagsMask |= Times | SizeAttribute; if (setLinkType) { knownFlagsMask |= LinkType; entryFlags &= ~LinkType; if (fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) { if (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { entryFlags |= LinkType; #if defined(IO_REPARSE_TAG_MOUNT_POINT) } else if ((fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { entryFlags |= JunctionType; #endif } } } } inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo) { fillFromFileAttribute(fileInfo.dwFileAttributes); birthTime_ = fileInfo.ftCreationTime; lastAccessTime_ = fileInfo.ftLastAccessTime; changeTime_ = lastWriteTime_ = fileInfo.ftLastWriteTime; if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { size_ = 0; } else { size_ = fileInfo.nFileSizeHigh; size_ <<= 32; size_ += fileInfo.nFileSizeLow; } knownFlagsMask |= Times | SizeAttribute; } #endif // Q_OS_WIN QT_END_NAMESPACE #endif // include guard