1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QFILESYSTEMMETADATA_P_H
41 #define QFILESYSTEMMETADATA_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include "qplatformdefs.h"
55 #include <QtCore/qglobal.h>
56 #include <QtCore/qdatetime.h>
57 #include <QtCore/private/qabstractfileengine_p.h>
58 
59 // Platform-specific includes
60 #ifdef Q_OS_WIN
61 #  include <QtCore/qt_windows.h>
62 #  ifndef IO_REPARSE_TAG_SYMLINK
63 #     define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
64 #  endif
65 #endif
66 
67 #ifdef Q_OS_UNIX
68 struct statx;
69 #endif
70 
71 QT_BEGIN_NAMESPACE
72 
73 class QFileSystemEngine;
74 
75 class Q_AUTOTEST_EXPORT QFileSystemMetaData
76 {
77 public:
QFileSystemMetaData()78     QFileSystemMetaData()
79         : size_(-1)
80     {
81     }
82 
83     enum MetaDataFlag {
84         // Permissions, overlaps with QFile::Permissions
85         OtherReadPermission = 0x00000004,   OtherWritePermission = 0x00000002,  OtherExecutePermission = 0x00000001,
86         GroupReadPermission = 0x00000040,   GroupWritePermission = 0x00000020,  GroupExecutePermission = 0x00000010,
87         UserReadPermission  = 0x00000400,   UserWritePermission  = 0x00000200,  UserExecutePermission  = 0x00000100,
88         OwnerReadPermission = 0x00004000,   OwnerWritePermission = 0x00002000,  OwnerExecutePermission = 0x00001000,
89 
90         OtherPermissions    = OtherReadPermission | OtherWritePermission | OtherExecutePermission,
91         GroupPermissions    = GroupReadPermission | GroupWritePermission | GroupExecutePermission,
92         UserPermissions     = UserReadPermission  | UserWritePermission  | UserExecutePermission,
93         OwnerPermissions    = OwnerReadPermission | OwnerWritePermission | OwnerExecutePermission,
94 
95         ReadPermissions     = OtherReadPermission | GroupReadPermission | UserReadPermission | OwnerReadPermission,
96         WritePermissions    = OtherWritePermission | GroupWritePermission | UserWritePermission | OwnerWritePermission,
97         ExecutePermissions  = OtherExecutePermission | GroupExecutePermission | UserExecutePermission | OwnerExecutePermission,
98 
99         Permissions         = OtherPermissions | GroupPermissions | UserPermissions | OwnerPermissions,
100 
101         // Type
102         LinkType            = 0x00010000,
103         FileType            = 0x00020000,
104         DirectoryType       = 0x00040000,
105 #if defined(Q_OS_DARWIN)
106         BundleType          = 0x00080000,
107         AliasType           = 0x08000000,
108 #else
109         BundleType          =        0x0,
110         AliasType           =        0x0,
111 #endif
112 #if defined(Q_OS_WIN)
113         JunctionType        = 0x04000000,
114         WinLnkType          = 0x08000000,   // Note: Uses the same position for AliasType on Mac
115 #else
116         JunctionType        =        0x0,
117         WinLnkType          =        0x0,
118 #endif
119         SequentialType      = 0x00800000,   // Note: overlaps with QAbstractFileEngine::RootFlag
120 
121         LegacyLinkType      = LinkType | AliasType | WinLnkType,
122 
123         Type                = LinkType | FileType | DirectoryType | BundleType | SequentialType | AliasType,
124 
125         // Attributes
126         HiddenAttribute     = 0x00100000,
127         SizeAttribute       = 0x00200000,   // Note: overlaps with QAbstractFileEngine::LocalDiskFlag
128         ExistsAttribute     = 0x00400000,   // For historical reasons, indicates existence of data, not the file
129 #if defined(Q_OS_WIN)
130         WasDeletedAttribute =        0x0,
131 #else
132         WasDeletedAttribute = 0x40000000,   // Indicates the file was deleted
133 #endif
134 
135         Attributes          = HiddenAttribute | SizeAttribute | ExistsAttribute | WasDeletedAttribute,
136 
137         // Times - if we know one of them, we know them all
138         AccessTime          = 0x02000000,
139         BirthTime           = 0x02000000,
140         MetadataChangeTime  = 0x02000000,
141         ModificationTime    = 0x02000000,
142 
143         Times               = AccessTime | BirthTime | MetadataChangeTime | ModificationTime,
144 
145         // Owner IDs
146         UserId              = 0x10000000,
147         GroupId             = 0x20000000,
148 
149         OwnerIds            = UserId | GroupId,
150 
151         PosixStatFlags      = QFileSystemMetaData::OtherPermissions
152                             | QFileSystemMetaData::GroupPermissions
153                             | QFileSystemMetaData::OwnerPermissions
154                             | QFileSystemMetaData::FileType
155                             | QFileSystemMetaData::DirectoryType
156                             | QFileSystemMetaData::SequentialType
157                             | QFileSystemMetaData::SizeAttribute
158                             | QFileSystemMetaData::WasDeletedAttribute
159                             | QFileSystemMetaData::Times
160                             | QFileSystemMetaData::OwnerIds,
161 
162 #if defined(Q_OS_WIN)
163         WinStatFlags        = QFileSystemMetaData::FileType
164                             | QFileSystemMetaData::DirectoryType
165                             | QFileSystemMetaData::HiddenAttribute
166                             | QFileSystemMetaData::ExistsAttribute
167                             | QFileSystemMetaData::SizeAttribute
168                             | QFileSystemMetaData::Times,
169 #endif
170 
171         AllMetaDataFlags    = 0xFFFFFFFF
172 
173     };
Q_DECLARE_FLAGS(MetaDataFlags,MetaDataFlag)174     Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag)
175 
176     bool hasFlags(MetaDataFlags flags) const
177     {
178         return ((knownFlagsMask & flags) == flags);
179     }
180 
missingFlags(MetaDataFlags flags)181     MetaDataFlags missingFlags(MetaDataFlags flags)
182     {
183         return flags & ~knownFlagsMask;
184     }
185 
clear()186     void clear()
187     {
188         knownFlagsMask = {};
189     }
190 
191     void clearFlags(MetaDataFlags flags = AllMetaDataFlags)
192     {
193         knownFlagsMask &= ~flags;
194     }
195 
exists()196     bool exists() const                     { return (entryFlags & ExistsAttribute); }
197 
isLink()198     bool isLink() const                     { return  (entryFlags & LinkType); }
isFile()199     bool isFile() const                     { return (entryFlags & FileType); }
isDirectory()200     bool isDirectory() const                { return (entryFlags & DirectoryType); }
201     bool isBundle() const;
202     bool isAlias() const;
isLegacyLink()203     bool isLegacyLink() const               { return (entryFlags & LegacyLinkType); }
isSequential()204     bool isSequential() const               { return (entryFlags & SequentialType); }
isHidden()205     bool isHidden() const                   { return (entryFlags & HiddenAttribute); }
wasDeleted()206     bool wasDeleted() const                 { return (entryFlags & WasDeletedAttribute); }
207 #if defined(Q_OS_WIN)
isLnkFile()208     bool isLnkFile() const                  { return (entryFlags & WinLnkType); }
isJunction()209     bool isJunction() const                 { return (entryFlags & JunctionType); }
210 #else
isLnkFile()211     bool isLnkFile() const                  { return false; }
isJunction()212     bool isJunction() const                 { return false; }
213 #endif
214 
size()215     qint64 size() const                     { return size_; }
216 
permissions()217     QFile::Permissions permissions() const  { return QFile::Permissions(Permissions & entryFlags); }
218 
219     QDateTime accessTime() const;
220     QDateTime birthTime() const;
221     QDateTime metadataChangeTime() const;
222     QDateTime modificationTime() const;
223 
224     QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
225     uint userId() const;
226     uint groupId() const;
227     uint ownerId(QAbstractFileEngine::FileOwner owner) const;
228 
229 #ifdef Q_OS_UNIX
230     void fillFromStatxBuf(const struct statx &statBuffer);
231     void fillFromStatBuf(const QT_STATBUF &statBuffer);
232     void fillFromDirEnt(const QT_DIRENT &statBuffer);
233 #endif
234 
235 #if defined(Q_OS_WIN)
236     inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false);
237     inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false);
238 #  ifndef Q_OS_WINRT
239     inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo);
240 #  endif
241 #endif
242 private:
243     friend class QFileSystemEngine;
244 
245     MetaDataFlags knownFlagsMask;
246     MetaDataFlags entryFlags;
247 
248     qint64 size_;
249 
250     // Platform-specific data goes here:
251 #if defined(Q_OS_WIN)
252     DWORD fileAttribute_;
253     FILETIME birthTime_;
254     FILETIME changeTime_;
255     FILETIME lastAccessTime_;
256     FILETIME lastWriteTime_;
257 #else
258     // msec precision
259     qint64 accessTime_;
260     qint64 birthTime_;
261     qint64 metadataChangeTime_;
262     qint64 modificationTime_;
263 
264     uint userId_;
265     uint groupId_;
266 #endif
267 
268 };
269 
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags)270 Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags)
271 
272 #if defined(Q_OS_DARWIN)
273 inline bool QFileSystemMetaData::isBundle() const                   { return (entryFlags & BundleType); }
isAlias()274 inline bool QFileSystemMetaData::isAlias() const                    { return (entryFlags & AliasType); }
275 #else
276 inline bool QFileSystemMetaData::isBundle() const                   { return false; }
277 inline bool QFileSystemMetaData::isAlias() const                    { return false; }
278 #endif
279 
280 #if defined(Q_OS_UNIX) || defined (Q_OS_WIN)
fileTime(QAbstractFileEngine::FileTime time)281 inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
282 {
283     switch (time) {
284     case QAbstractFileEngine::ModificationTime:
285         return modificationTime();
286 
287     case QAbstractFileEngine::AccessTime:
288         return accessTime();
289 
290     case QAbstractFileEngine::BirthTime:
291         return birthTime();
292 
293     case QAbstractFileEngine::MetadataChangeTime:
294         return metadataChangeTime();
295     }
296 
297     return QDateTime();
298 }
299 #endif
300 
301 #if defined(Q_OS_UNIX)
birthTime()302 inline QDateTime QFileSystemMetaData::birthTime() const
303 { return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_) : QDateTime(); }
metadataChangeTime()304 inline QDateTime QFileSystemMetaData::metadataChangeTime() const
305 { return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_) : QDateTime(); }
modificationTime()306 inline QDateTime QFileSystemMetaData::modificationTime() const
307 { return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(modificationTime_) : QDateTime(); }
accessTime()308 inline QDateTime QFileSystemMetaData::accessTime() const
309 { return accessTime_ ? QDateTime::fromMSecsSinceEpoch(accessTime_) : QDateTime(); }
310 
userId()311 inline uint QFileSystemMetaData::userId() const                     { return userId_; }
groupId()312 inline uint QFileSystemMetaData::groupId() const                    { return groupId_; }
313 
ownerId(QAbstractFileEngine::FileOwner owner)314 inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
315 {
316     if (owner == QAbstractFileEngine::OwnerUser)
317         return userId();
318     else
319         return groupId();
320 }
321 #endif
322 
323 #if defined(Q_OS_WIN)
userId()324 inline uint QFileSystemMetaData::userId() const                     { return (uint) -2; }
groupId()325 inline uint QFileSystemMetaData::groupId() const                    { return (uint) -2; }
ownerId(QAbstractFileEngine::FileOwner owner)326 inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
327 {
328     if (owner == QAbstractFileEngine::OwnerUser)
329         return userId();
330     else
331         return groupId();
332 }
333 
fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot)334 inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot)
335 {
336     fileAttribute_ = fileAttribute;
337     // Ignore the hidden attribute for drives.
338     if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN))
339         entryFlags |= HiddenAttribute;
340     entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType);
341     entryFlags |= ExistsAttribute;
342     knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute;
343 }
344 
fillFromFindData(WIN32_FIND_DATA & findData,bool setLinkType,bool isDriveRoot)345 inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot)
346 {
347     fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot);
348     birthTime_ = findData.ftCreationTime;
349     lastAccessTime_ = findData.ftLastAccessTime;
350     changeTime_ = lastWriteTime_ = findData.ftLastWriteTime;
351     if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
352         size_ = 0;
353     } else {
354         size_ = findData.nFileSizeHigh;
355         size_ <<= 32;
356         size_ += findData.nFileSizeLow;
357     }
358     knownFlagsMask |=  Times | SizeAttribute;
359     if (setLinkType) {
360         knownFlagsMask |=  LinkType;
361         entryFlags &= ~LinkType;
362         if (fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
363             if (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
364                 entryFlags |= LinkType;
365 #if defined(IO_REPARSE_TAG_MOUNT_POINT)
366             } else if ((fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY)
367                     && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) {
368                 entryFlags |= JunctionType;
369 #endif
370             }
371         }
372     }
373 }
374 
375 #ifndef Q_OS_WINRT
fillFromFindInfo(BY_HANDLE_FILE_INFORMATION & fileInfo)376 inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
377 {
378     fillFromFileAttribute(fileInfo.dwFileAttributes);
379     birthTime_ = fileInfo.ftCreationTime;
380     lastAccessTime_ = fileInfo.ftLastAccessTime;
381     changeTime_ = lastWriteTime_ = fileInfo.ftLastWriteTime;
382     if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
383         size_ = 0;
384     } else {
385         size_ = fileInfo.nFileSizeHigh;
386         size_ <<= 32;
387         size_ += fileInfo.nFileSizeLow;
388     }
389     knownFlagsMask |=  Times | SizeAttribute;
390 }
391 #endif // !Q_OS_WINRT
392 #endif // Q_OS_WIN
393 
394 QT_END_NAMESPACE
395 
396 #endif // include guard
397