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 | # 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 | |
270 | Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) |
271 | |
272 | #if defined(Q_OS_DARWIN) |
273 | inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); } |
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) |
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) |
302 | inline QDateTime QFileSystemMetaData::birthTime() const |
303 | { return birthTime_ ? QDateTime::fromMSecsSinceEpoch(msecs: birthTime_) : QDateTime(); } |
304 | inline QDateTime QFileSystemMetaData::metadataChangeTime() const |
305 | { return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(msecs: metadataChangeTime_) : QDateTime(); } |
306 | inline QDateTime QFileSystemMetaData::modificationTime() const |
307 | { return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(msecs: modificationTime_) : QDateTime(); } |
308 | inline QDateTime QFileSystemMetaData::accessTime() const |
309 | { return accessTime_ ? QDateTime::fromMSecsSinceEpoch(msecs: accessTime_) : QDateTime(); } |
310 | |
311 | inline uint QFileSystemMetaData::userId() const { return userId_; } |
312 | inline uint QFileSystemMetaData::groupId() const { return groupId_; } |
313 | |
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) |
324 | inline uint QFileSystemMetaData::userId() const { return (uint) -2; } |
325 | inline uint QFileSystemMetaData::groupId() const { return (uint) -2; } |
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 | |
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 | |
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 |
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 | |