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: |
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 | }; |
174 | Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag) |
175 | |
176 | bool hasFlags(MetaDataFlags flags) const |
177 | { |
178 | return ((knownFlagsMask & flags) == flags); |
179 | } |
180 | |
181 | MetaDataFlags missingFlags(MetaDataFlags flags) |
182 | { |
183 | return flags & ~knownFlagsMask; |
184 | } |
185 | |
186 | void clear() |
187 | { |
188 | knownFlagsMask = {}; |
189 | } |
190 | |
191 | void clearFlags(MetaDataFlags flags = AllMetaDataFlags) |
192 | { |
193 | knownFlagsMask &= ~flags; |
194 | } |
195 | |
196 | bool exists() const { return (entryFlags & ExistsAttribute); } |
197 | |
198 | bool isLink() const { return (entryFlags & LinkType); } |
199 | bool isFile() const { return (entryFlags & FileType); } |
200 | bool isDirectory() const { return (entryFlags & DirectoryType); } |
201 | bool isBundle() const; |
202 | bool isAlias() const; |
203 | bool isLegacyLink() const { return (entryFlags & LegacyLinkType); } |
204 | bool isSequential() const { return (entryFlags & SequentialType); } |
205 | bool isHidden() const { return (entryFlags & HiddenAttribute); } |
206 | bool wasDeleted() const { return (entryFlags & WasDeletedAttribute); } |
207 | #if defined(Q_OS_WIN) |
208 | bool isLnkFile() const { return (entryFlags & WinLnkType); } |
209 | bool isJunction() const { return (entryFlags & JunctionType); } |
210 | #else |
211 | bool isLnkFile() const { return false; } |
212 | bool isJunction() const { return false; } |
213 | #endif |
214 | |
215 | qint64 size() const { return size_; } |
216 | |
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 | inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo); |
239 | #endif |
240 | private: |
241 | friend class QFileSystemEngine; |
242 | |
243 | MetaDataFlags knownFlagsMask; |
244 | MetaDataFlags entryFlags; |
245 | |
246 | qint64 size_; |
247 | |
248 | // Platform-specific data goes here: |
249 | #if defined(Q_OS_WIN) |
250 | DWORD fileAttribute_; |
251 | FILETIME birthTime_; |
252 | FILETIME changeTime_; |
253 | FILETIME lastAccessTime_; |
254 | FILETIME lastWriteTime_; |
255 | #else |
256 | // msec precision |
257 | qint64 accessTime_; |
258 | qint64 birthTime_; |
259 | qint64 metadataChangeTime_; |
260 | qint64 modificationTime_; |
261 | |
262 | uint userId_; |
263 | uint groupId_; |
264 | #endif |
265 | |
266 | }; |
267 | |
268 | Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) |
269 | |
270 | #if defined(Q_OS_DARWIN) |
271 | inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); } |
272 | inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); } |
273 | #else |
274 | inline bool QFileSystemMetaData::isBundle() const { return false; } |
275 | inline bool QFileSystemMetaData::isAlias() const { return false; } |
276 | #endif |
277 | |
278 | #if defined(Q_OS_UNIX) || defined (Q_OS_WIN) |
279 | inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const |
280 | { |
281 | switch (time) { |
282 | case QAbstractFileEngine::ModificationTime: |
283 | return modificationTime(); |
284 | |
285 | case QAbstractFileEngine::AccessTime: |
286 | return accessTime(); |
287 | |
288 | case QAbstractFileEngine::BirthTime: |
289 | return birthTime(); |
290 | |
291 | case QAbstractFileEngine::MetadataChangeTime: |
292 | return metadataChangeTime(); |
293 | } |
294 | |
295 | return QDateTime(); |
296 | } |
297 | #endif |
298 | |
299 | #if defined(Q_OS_UNIX) |
300 | inline QDateTime QFileSystemMetaData::birthTime() const |
301 | { return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_) : QDateTime(); } |
302 | inline QDateTime QFileSystemMetaData::metadataChangeTime() const |
303 | { return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_) : QDateTime(); } |
304 | inline QDateTime QFileSystemMetaData::modificationTime() const |
305 | { return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(modificationTime_) : QDateTime(); } |
306 | inline QDateTime QFileSystemMetaData::accessTime() const |
307 | { return accessTime_ ? QDateTime::fromMSecsSinceEpoch(accessTime_) : QDateTime(); } |
308 | |
309 | inline uint QFileSystemMetaData::userId() const { return userId_; } |
310 | inline uint QFileSystemMetaData::groupId() const { return groupId_; } |
311 | |
312 | inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const |
313 | { |
314 | if (owner == QAbstractFileEngine::OwnerUser) |
315 | return userId(); |
316 | else |
317 | return groupId(); |
318 | } |
319 | #endif |
320 | |
321 | #if defined(Q_OS_WIN) |
322 | inline uint QFileSystemMetaData::userId() const { return (uint) -2; } |
323 | inline uint QFileSystemMetaData::groupId() const { return (uint) -2; } |
324 | inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const |
325 | { |
326 | if (owner == QAbstractFileEngine::OwnerUser) |
327 | return userId(); |
328 | else |
329 | return groupId(); |
330 | } |
331 | |
332 | inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot) |
333 | { |
334 | fileAttribute_ = fileAttribute; |
335 | // Ignore the hidden attribute for drives. |
336 | if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN)) |
337 | entryFlags |= HiddenAttribute; |
338 | entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType); |
339 | entryFlags |= ExistsAttribute; |
340 | knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute; |
341 | } |
342 | |
343 | inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot) |
344 | { |
345 | fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot); |
346 | birthTime_ = findData.ftCreationTime; |
347 | lastAccessTime_ = findData.ftLastAccessTime; |
348 | changeTime_ = lastWriteTime_ = findData.ftLastWriteTime; |
349 | if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { |
350 | size_ = 0; |
351 | } else { |
352 | size_ = findData.nFileSizeHigh; |
353 | size_ <<= 32; |
354 | size_ += findData.nFileSizeLow; |
355 | } |
356 | knownFlagsMask |= Times | SizeAttribute; |
357 | if (setLinkType) { |
358 | knownFlagsMask |= LinkType; |
359 | entryFlags &= ~LinkType; |
360 | if (fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) { |
361 | if (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { |
362 | entryFlags |= LinkType; |
363 | #if defined(IO_REPARSE_TAG_MOUNT_POINT) |
364 | } else if ((fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) |
365 | && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { |
366 | entryFlags |= JunctionType; |
367 | #endif |
368 | } |
369 | } |
370 | } |
371 | } |
372 | |
373 | inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo) |
374 | { |
375 | fillFromFileAttribute(fileInfo.dwFileAttributes); |
376 | birthTime_ = fileInfo.ftCreationTime; |
377 | lastAccessTime_ = fileInfo.ftLastAccessTime; |
378 | changeTime_ = lastWriteTime_ = fileInfo.ftLastWriteTime; |
379 | if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) { |
380 | size_ = 0; |
381 | } else { |
382 | size_ = fileInfo.nFileSizeHigh; |
383 | size_ <<= 32; |
384 | size_ += fileInfo.nFileSizeLow; |
385 | } |
386 | knownFlagsMask |= Times | SizeAttribute; |
387 | } |
388 | #endif // Q_OS_WIN |
389 | |
390 | QT_END_NAMESPACE |
391 | |
392 | #endif // include guard |
393 | |