Qt 4.8
qfilesystemengine.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
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>
49 #endif
50 
52 
63 {
64  if (path.isEmpty())
65  return path;
66 
67  QFileInfo fi;
68  const QChar slash(QLatin1Char('/'));
69  QString tmpPath = path;
70  int separatorPos = 0;
71  QSet<QString> nonSymlinks;
72  QSet<QString> known;
73 
74  known.insert(path);
75  do {
76 #ifdef Q_OS_WIN
77  if (separatorPos == 0) {
78  if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
79  // UNC, skip past the first two elements
80  separatorPos = tmpPath.indexOf(slash, 2);
81  } else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
82  // volume root, skip since it can not be a symlink
83  separatorPos = 2;
84  }
85  }
86  if (separatorPos != -1)
87 #endif
88  separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
89  QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
90  if (
91 #ifdef Q_OS_SYMBIAN
92  // Symbian doesn't support directory symlinks, so do not check for link unless we
93  // are handling the last path element. This not only slightly improves performance,
94  // but also saves us from lot of unnecessary platform security check failures
95  // when dealing with files under *:/private directories.
96  separatorPos == -1 &&
97 #endif
98  !nonSymlinks.contains(prefix)) {
99  fi.setFile(prefix);
100  if (fi.isSymLink()) {
101  QString target = fi.symLinkTarget();
102  if(QFileInfo(target).isRelative())
103  target = fi.absolutePath() + slash + target;
104  if (separatorPos != -1) {
105  if (fi.isDir() && !target.endsWith(slash))
106  target.append(slash);
107  target.append(tmpPath.mid(separatorPos));
108  }
109  tmpPath = QDir::cleanPath(target);
110  separatorPos = 0;
111 
112  if (known.contains(tmpPath))
113  return QString();
114  known.insert(tmpPath);
115  } else {
116  nonSymlinks.insert(prefix);
117  }
118  }
119  } while (separatorPos != -1);
120 
121  return QDir::cleanPath(tmpPath);
122 }
123 
124 static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
125 {
126  if (resolvingEntry) {
128  || !data.exists()) {
129  data.clear();
130  return false;
131  }
132  }
133 
134  return true;
135 }
136 
137 static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
138 {
139  if (resolvingEntry) {
141  delete engine;
142  engine = 0;
143  return false;
144  }
145  }
146 
147  return true;
148 }
149 
151  QAbstractFileEngine *&engine, bool resolvingEntry = false)
152 {
153  QString const &filePath = entry.filePath();
154  if ((engine = qt_custom_file_engine_handler_create(filePath)))
155  return _q_checkEntry(engine, resolvingEntry);
156 
157 #if defined(QT_BUILD_CORE_LIB)
158  for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
159  QChar const ch = filePath[prefixSeparator];
160  if (ch == QLatin1Char('/'))
161  break;
162 
163  if (ch == QLatin1Char(':')) {
164  if (prefixSeparator == 0) {
165  engine = new QResourceFileEngine(filePath);
166  return _q_checkEntry(engine, resolvingEntry);
167  }
168 
169  if (prefixSeparator == 1)
170  break;
171 
172  const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
173  for (int i = 0; i < paths.count(); i++) {
174  entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)));
175  // Recurse!
176  if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
177  return true;
178  }
179 
180  // entry may have been clobbered at this point.
181  return false;
182  }
183 
184  // There's no need to fully validate the prefix here. Consulting the
185  // unicode tables could be expensive and validation is already
186  // performed in QDir::setSearchPaths.
187  //
188  // if (!ch.isLetterOrNumber())
189  // break;
190  }
191 #endif // defined(QT_BUILD_CORE_LIB)
192 
193  return _q_checkEntry(entry, data, resolvingEntry);
194 }
195 
211  QFileSystemEntry copy = entry;
212  QAbstractFileEngine *engine = 0;
213 
214  if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
215  // Reset entry to resolved copy.
216  entry = copy;
217  else
218  data.clear();
219 
220  return engine;
221 }
222 
223 //these unix functions are in this file, because they are shared by symbian port
224 //for open C file handles.
225 #ifdef Q_OS_UNIX
226 //static
228 {
229  data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
231 
232  QT_STATBUF statBuffer;
233  if (QT_FSTAT(fd, &statBuffer) == 0) {
234  data.fillFromStatBuf(statBuffer);
235  return true;
236  }
237 
238  return false;
239 }
240 
241 #if defined(Q_OS_QNX)
242 static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
243 {
244  statBuf64->st_mode = statBuf32.st_mode;
245  statBuf64->st_size = statBuf32.st_size;
246  statBuf64->st_ctime = statBuf32.st_ctime;
247  statBuf64->st_mtime = statBuf32.st_mtime;
248  statBuf64->st_atime = statBuf32.st_atime;
249  statBuf64->st_uid = statBuf32.st_uid;
250  statBuf64->st_gid = statBuf32.st_gid;
251 }
252 #endif
253 
254 void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
255 {
256  // Permissions
257  if (statBuffer.st_mode & S_IRUSR)
259  if (statBuffer.st_mode & S_IWUSR)
261  if (statBuffer.st_mode & S_IXUSR)
263 
264  if (statBuffer.st_mode & S_IRGRP)
266  if (statBuffer.st_mode & S_IWGRP)
268  if (statBuffer.st_mode & S_IXGRP)
270 
271  if (statBuffer.st_mode & S_IROTH)
273  if (statBuffer.st_mode & S_IWOTH)
275  if (statBuffer.st_mode & S_IXOTH)
277 
278  // Type
279  if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
280  entryFlags |= QFileSystemMetaData::FileType;
281  else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
283  else
285 
286  // Attributes
288  size_ = statBuffer.st_size;
289 #if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) \
290  && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
291  if (statBuffer.st_flags & UF_HIDDEN) {
293  knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
294  }
295 #endif
296 
297  // Times
298 #ifdef Q_OS_SYMBIAN
299  modificationTime_ = qt_symbian_time_t_To_TTime(statBuffer.st_mtime);
300 #else
301  creationTime_ = statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime;
302  modificationTime_ = statBuffer.st_mtime;
303  accessTime_ = statBuffer.st_atime;
304  userId_ = statBuffer.st_uid;
305  groupId_ = statBuffer.st_gid;
306 #endif
307 }
308 
309 void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
310 {
311 #if defined(Q_OS_QNX)
312  entryFlags = 0;
313  knownFlagsMask = 0;
314  for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
315  extra = _DEXTRA_NEXT(extra)) {
316  if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
317 
318  const struct dirent_extra_stat * const extra_stat =
319  reinterpret_cast<struct dirent_extra_stat *>(extra);
320 
321  // Remember whether this was a link or not, this saves an lstat() call later.
322  if (extra->d_type == _DTYPE_LSTAT) {
323  knownFlagsMask |= QFileSystemMetaData::LinkType;
324  if (S_ISLNK(extra_stat->d_stat.st_mode))
325  entryFlags |= QFileSystemMetaData::LinkType;
326  }
327 
328  // For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data,
329  // as we need the stat() information there, not the lstat() information.
330  // In this case, don't use the extra information.
331  // Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for
332  // symlinks, we always incur the cost of an extra stat() call later.
333  if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
334  continue;
335 
336 #if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
337  // Even with large file support, d_stat is always of type struct stat, not struct stat64,
338  // so it needs to be converted
339  struct stat64 statBuf;
340  fillStat64fromStat32(&statBuf, extra_stat->d_stat);
341  fillFromStatBuf(statBuf);
342 #else
343  fillFromStatBuf(extra_stat->d_stat);
344 #endif
345  knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
346  if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
347  knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
349  }
350  }
351  }
352 #elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) || defined(Q_OS_SYMBIAN)
353  // BSD4 includes Mac OS X
354 
355  // ### This will clear all entry flags and knownFlagsMask
356  switch (entry.d_type)
357  {
358  case DT_DIR:
359  knownFlagsMask = QFileSystemMetaData::LinkType
364 
367 
368  break;
369 
370  case DT_BLK:
371  case DT_CHR:
372  case DT_FIFO:
373  case DT_SOCK:
374  // ### System attribute
375  knownFlagsMask = QFileSystemMetaData::LinkType
382 
385 
386  break;
387 
388  case DT_LNK:
389  knownFlagsMask = QFileSystemMetaData::LinkType;
390  entryFlags = QFileSystemMetaData::LinkType;
391  break;
392 
393  case DT_REG:
394  knownFlagsMask = QFileSystemMetaData::LinkType
400 
401  entryFlags = QFileSystemMetaData::FileType
403 
404  break;
405 
406  case DT_UNKNOWN:
407  default:
408  clear();
409  }
410 #else
411  Q_UNUSED(entry)
412 #endif
413 }
414 
415 #endif
416 
417 //static
419 {
420 #if defined (Q_OS_SYMBIAN)
421  Q_UNUSED(entry);
422  Q_UNUSED(metaData);
423  return QString();
424 #elif defined(Q_OS_WIN)
425  Q_UNUSED(metaData);
427 #else //(Q_OS_UNIX)
428  if (!metaData.hasFlags(QFileSystemMetaData::UserId))
430  return resolveUserName(metaData.userId());
431 #endif
432 }
433 
434 //static
436 {
437 #if defined (Q_OS_SYMBIAN)
438  Q_UNUSED(entry);
439  Q_UNUSED(metaData);
440  return QString();
441 #elif defined(Q_OS_WIN)
442  Q_UNUSED(metaData);
444 #else //(Q_OS_UNIX)
445  if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
447  return resolveGroupName(metaData.groupId());
448 #endif
449 }
450 
static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what)
#define S_IFREG
#define S_IWOTH
Definition: qzip.cpp:83
virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const
This function should return the set of OR&#39;d flags that are true for the file engine&#39;s file...
#define S_IRGRP
Definition: qzip.cpp:79
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
#define S_IXGRP
Definition: qzip.cpp:81
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
time_t st_ctime
static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
#define S_IRUSR
Definition: qzip.cpp:71
#define S_IXUSR
Definition: qzip.cpp:77
static void clear(QVariant::Private *d)
Definition: qvariant.cpp:197
static bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
QAbstractFileEngine * qt_custom_file_engine_handler_create(const QString &path)
#define S_IFMT
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory; otherwise ret...
Definition: qfileinfo.cpp:990
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
bool contains(const T &value) const
Definition: qset.h:91
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define S_IXOTH
Definition: qzip.cpp:84
static QString slowCanonicalized(const QString &path)
Returns the canonicalized form of path (i.
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
void setFile(const QString &file)
Sets the file that the QFileInfo provides information about to file.
Definition: qfileinfo.cpp:468
The QAbstractFileEngine class provides an abstraction for accessing the filesystem.
const_iterator insert(const T &value)
Definition: qset.h:179
#define S_IROTH
Definition: qzip.cpp:82
static const char * data(const QByteArray &arr)
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
bool hasFlags(MetaDataFlags flags) const
static QString cleanPath(const QString &path)
Removes all multiple directory separators "/" and resolves any "."s or ".."s found in the path...
Definition: qdir.cpp:2082
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
QString & append(QChar c)
Definition: qstring.cpp:1777
#define S_IFDIR
time_t st_atime
QString symLinkTarget() const
Returns the absolute path to the file or directory a symlink (or shortcut on Windows) points to...
Definition: qfileinfo.h:121
static QStringList searchPaths(const QString &prefix)
QString filePath() const
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
#define S_IWGRP
Definition: qzip.cpp:80
static QAbstractFileEngine * resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data)
Resolves the entry (see QDir::searchPaths) and returns an engine for it, but never a QFSFileEngine...
#define S_ISLNK(x)
Definition: qzip.cpp:69
bool isSymLink() const
Returns true if this object points to a symbolic link (or to a shortcut on Windows); otherwise return...
Definition: qfileinfo.cpp:1044
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
time_t st_mtime
QString absolutePath() const
Returns a file&#39;s path absolute path.
Definition: qfileinfo.cpp:577
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
void fillFromDirEnt(const QT_DIRENT &statBuffer)
static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data, QAbstractFileEngine *&engine, bool resolvingEntry=false)
#define S_IWUSR
Definition: qzip.cpp:74
void fillFromStatBuf(const QT_STATBUF &statBuffer)