1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtCore module of the Qt Toolkit.
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 Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qfilesystemengine_p.h"
43
#include <QtCore/qdir.h>
44
#include <QtCore/qset.h>
45
#include <QtCore/qstringbuilder.h>
46
#include <QtCore/private/qabstractfileengine_p.h>
47
#ifdef QT_BUILD_CORE_LIB
48
#include <QtCore/private/qresource_p.h>
56
Returns the canonicalized form of \a path (i.e., with all symlinks
57
resolved, and all redundant path elements removed.
59
QString QFileSystemEngine::slowCanonicalized(const QString &path)
65
const QChar slash(QLatin1Char('/'));
66
QString tmpPath = path;
68
QSet<QString> nonSymlinks;
74
if (separatorPos == 0) {
75
if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
76
// UNC, skip past the first two elements
77
separatorPos = tmpPath.indexOf(slash, 2);
78
} else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
79
// volume root, skip since it can not be a symlink
83
if (separatorPos != -1)
85
separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
86
QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
87
if (!nonSymlinks.contains(prefix)) {
90
QString target = fi.symLinkTarget();
91
if(QFileInfo(target).isRelative())
92
target = fi.absolutePath() + slash + target;
93
if (separatorPos != -1) {
94
if (fi.isDir() && !target.endsWith(slash))
96
target.append(tmpPath.mid(separatorPos));
98
tmpPath = QDir::cleanPath(target);
101
if (known.contains(tmpPath))
103
known.insert(tmpPath);
105
nonSymlinks.insert(prefix);
108
} while (separatorPos != -1);
110
return QDir::cleanPath(tmpPath);
113
static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
115
if (resolvingEntry) {
116
if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
126
static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
128
if (resolvingEntry) {
129
if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
139
static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
140
QAbstractFileEngine *&engine, bool resolvingEntry = false)
142
QString const &filePath = entry.filePath();
143
if ((engine = qt_custom_file_engine_handler_create(filePath)))
144
return _q_checkEntry(engine, resolvingEntry);
146
#if defined(QT_BUILD_CORE_LIB)
147
for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
148
QChar const ch = filePath[prefixSeparator];
149
if (ch == QLatin1Char('/'))
152
if (ch == QLatin1Char(':')) {
153
if (prefixSeparator == 0) {
154
engine = new QResourceFileEngine(filePath);
155
return _q_checkEntry(engine, resolvingEntry);
158
if (prefixSeparator == 1)
161
const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
162
for (int i = 0; i < paths.count(); i++) {
163
entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)));
165
if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
169
// entry may have been clobbered at this point.
173
// There's no need to fully validate the prefix here. Consulting the
174
// unicode tables could be expensive and validation is already
175
// performed in QDir::setSearchPaths.
177
// if (!ch.isLetterOrNumber())
180
#endif // defined(QT_BUILD_CORE_LIB)
182
return _q_checkEntry(entry, data, resolvingEntry);
188
Resolves the \a entry (see QDir::searchPaths) and returns an engine for
189
it, but never a QFSFileEngine.
191
Returns a file engine that can be used to access the entry. Returns 0 if
192
QFileSystemEngine API should be used to query and interact with the file
195
QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
196
QFileSystemEntry &entry, QFileSystemMetaData &data) {
197
QFileSystemEntry copy = entry;
198
QAbstractFileEngine *engine = 0;
200
if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
201
// Reset entry to resolved copy.
209
//these unix functions are in this file, because they are shared by symbian port
210
//for open C file handles.
213
bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
215
data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
216
data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
218
QT_STATBUF statBuffer;
219
if (QT_FSTAT(fd, &statBuffer) == 0) {
220
data.fillFromStatBuf(statBuffer);
227
#if defined(Q_OS_QNX)
228
static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
230
statBuf64->st_mode = statBuf32.st_mode;
231
statBuf64->st_size = statBuf32.st_size;
232
statBuf64->st_ctime = statBuf32.st_ctime;
233
statBuf64->st_mtime = statBuf32.st_mtime;
234
statBuf64->st_atime = statBuf32.st_atime;
235
statBuf64->st_uid = statBuf32.st_uid;
236
statBuf64->st_gid = statBuf32.st_gid;
240
void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
243
if (statBuffer.st_mode & S_IRUSR)
244
entryFlags |= QFileSystemMetaData::OwnerReadPermission;
245
if (statBuffer.st_mode & S_IWUSR)
246
entryFlags |= QFileSystemMetaData::OwnerWritePermission;
247
if (statBuffer.st_mode & S_IXUSR)
248
entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
250
if (statBuffer.st_mode & S_IRGRP)
251
entryFlags |= QFileSystemMetaData::GroupReadPermission;
252
if (statBuffer.st_mode & S_IWGRP)
253
entryFlags |= QFileSystemMetaData::GroupWritePermission;
254
if (statBuffer.st_mode & S_IXGRP)
255
entryFlags |= QFileSystemMetaData::GroupExecutePermission;
257
if (statBuffer.st_mode & S_IROTH)
258
entryFlags |= QFileSystemMetaData::OtherReadPermission;
259
if (statBuffer.st_mode & S_IWOTH)
260
entryFlags |= QFileSystemMetaData::OtherWritePermission;
261
if (statBuffer.st_mode & S_IXOTH)
262
entryFlags |= QFileSystemMetaData::OtherExecutePermission;
265
if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
266
entryFlags |= QFileSystemMetaData::FileType;
267
else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
268
entryFlags |= QFileSystemMetaData::DirectoryType;
270
entryFlags |= QFileSystemMetaData::SequentialType;
273
entryFlags |= QFileSystemMetaData::ExistsAttribute;
274
size_ = statBuffer.st_size;
275
#if defined (Q_OS_MAC) && !defined(Q_OS_IOS) \
276
&& MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
277
if (statBuffer.st_flags & UF_HIDDEN) {
278
entryFlags |= QFileSystemMetaData::HiddenAttribute;
279
knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
284
creationTime_ = statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime;
285
modificationTime_ = statBuffer.st_mtime;
286
accessTime_ = statBuffer.st_atime;
287
userId_ = statBuffer.st_uid;
288
groupId_ = statBuffer.st_gid;
291
void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
293
#if defined(Q_OS_QNX)
296
for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
297
extra = _DEXTRA_NEXT(extra)) {
298
if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
300
const struct dirent_extra_stat * const extra_stat =
301
reinterpret_cast<struct dirent_extra_stat *>(extra);
303
// Remember whether this was a link or not, this saves an lstat() call later.
304
if (extra->d_type == _DTYPE_LSTAT) {
305
knownFlagsMask |= QFileSystemMetaData::LinkType;
306
if (S_ISLNK(extra_stat->d_stat.st_mode))
307
entryFlags |= QFileSystemMetaData::LinkType;
310
// For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data,
311
// as we need the stat() information there, not the lstat() information.
312
// In this case, don't use the extra information.
313
// Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for
314
// symlinks, we always incur the cost of an extra stat() call later.
315
if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
318
#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
319
// Even with large file support, d_stat is always of type struct stat, not struct stat64,
320
// so it needs to be converted
321
struct stat64 statBuf;
322
fillStat64fromStat32(&statBuf, extra_stat->d_stat);
323
fillFromStatBuf(statBuf);
325
fillFromStatBuf(extra_stat->d_stat);
327
knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
328
if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
329
knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
330
entryFlags |= QFileSystemMetaData::ExistsAttribute;
334
#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
335
// BSD4 includes Mac OS X
337
// ### This will clear all entry flags and knownFlagsMask
338
switch (entry.d_type)
341
knownFlagsMask = QFileSystemMetaData::LinkType
342
| QFileSystemMetaData::FileType
343
| QFileSystemMetaData::DirectoryType
344
| QFileSystemMetaData::SequentialType
345
| QFileSystemMetaData::ExistsAttribute;
347
entryFlags = QFileSystemMetaData::DirectoryType
348
| QFileSystemMetaData::ExistsAttribute;
356
// ### System attribute
357
knownFlagsMask = QFileSystemMetaData::LinkType
358
| QFileSystemMetaData::FileType
359
| QFileSystemMetaData::DirectoryType
360
| QFileSystemMetaData::BundleType
361
| QFileSystemMetaData::AliasType
362
| QFileSystemMetaData::SequentialType
363
| QFileSystemMetaData::ExistsAttribute;
365
entryFlags = QFileSystemMetaData::SequentialType
366
| QFileSystemMetaData::ExistsAttribute;
371
knownFlagsMask = QFileSystemMetaData::LinkType;
372
entryFlags = QFileSystemMetaData::LinkType;
376
knownFlagsMask = QFileSystemMetaData::LinkType
377
| QFileSystemMetaData::FileType
378
| QFileSystemMetaData::DirectoryType
379
| QFileSystemMetaData::BundleType
380
| QFileSystemMetaData::SequentialType
381
| QFileSystemMetaData::ExistsAttribute;
383
entryFlags = QFileSystemMetaData::FileType
384
| QFileSystemMetaData::ExistsAttribute;
400
QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
402
#if defined(Q_OS_WIN)
404
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
406
if (!metaData.hasFlags(QFileSystemMetaData::UserId))
407
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
408
return resolveUserName(metaData.userId());
413
QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
415
#if defined(Q_OS_WIN)
417
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
419
if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
420
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
421
return resolveGroupName(metaData.groupId());