Revision control

Copy as Markdown

// 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
// Qt-Security score:significant reason:default
#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 <QtCore/qglobal.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qtimezone.h>
#include <QtCore/private/qabstractfileengine_p.h>
// Platform-specific includes
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
# 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,
CaseSensitive = 0x80000000,
OwnerIds = UserId | GroupId,
PosixStatFlags = OtherPermissions
| GroupPermissions
| OwnerPermissions
| FileType
| DirectoryType
| SequentialType
| SizeAttribute
| WasDeletedAttribute
| Times
| OwnerIds,
#if defined(Q_OS_WIN)
WinStatFlags = FileType
| DirectoryType
| HiddenAttribute
| ExistsAttribute
| SizeAttribute
| 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_; }
inline QFile::Permissions permissions() const;
// Has to be defined after the
// Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) call below.
inline void setPermissions(QFile::Permissions permissions);
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()); }
void QFileSystemMetaData::setPermissions(QFile::Permissions permissions)
{
entryFlags &= ~Permissions;
entryFlags |= MetaDataFlag(uint(permissions.toInt()));
knownFlagsMask |= Permissions;
}
#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;
// this function is never called for a .lnk file
knownFlagsMask |= WinLnkType;
}
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