~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/corelib/io/qfilesystemengine.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 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
 
 
51
QT_BEGIN_NAMESPACE
 
52
 
 
53
/*!
 
54
    \internal
 
55
 
 
56
    Returns the canonicalized form of \a path (i.e., with all symlinks
 
57
    resolved, and all redundant path elements removed.
 
58
*/
 
59
QString QFileSystemEngine::slowCanonicalized(const QString &path)
 
60
{
 
61
    if (path.isEmpty())
 
62
        return path;
 
63
 
 
64
    QFileInfo fi;
 
65
    const QChar slash(QLatin1Char('/'));
 
66
    QString tmpPath = path;
 
67
    int separatorPos = 0;
 
68
    QSet<QString> nonSymlinks;
 
69
    QSet<QString> known;
 
70
 
 
71
    known.insert(path);
 
72
    do {
 
73
#ifdef Q_OS_WIN
 
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
 
80
                separatorPos = 2;
 
81
            }
 
82
        }
 
83
        if (separatorPos != -1)
 
84
#endif
 
85
        separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
 
86
        QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
 
87
        if (!nonSymlinks.contains(prefix)) {
 
88
            fi.setFile(prefix);
 
89
            if (fi.isSymLink()) {
 
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))
 
95
                        target.append(slash);
 
96
                    target.append(tmpPath.mid(separatorPos));
 
97
                }
 
98
                tmpPath = QDir::cleanPath(target);
 
99
                separatorPos = 0;
 
100
 
 
101
                if (known.contains(tmpPath))
 
102
                    return QString();
 
103
                known.insert(tmpPath);
 
104
            } else {
 
105
                nonSymlinks.insert(prefix);
 
106
            }
 
107
        }
 
108
    } while (separatorPos != -1);
 
109
 
 
110
    return QDir::cleanPath(tmpPath);
 
111
}
 
112
 
 
113
static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
 
114
{
 
115
    if (resolvingEntry) {
 
116
        if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
 
117
                || !data.exists()) {
 
118
            data.clear();
 
119
            return false;
 
120
        }
 
121
    }
 
122
 
 
123
    return true;
 
124
}
 
125
 
 
126
static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
 
127
{
 
128
    if (resolvingEntry) {
 
129
        if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
 
130
            delete engine;
 
131
            engine = 0;
 
132
            return false;
 
133
        }
 
134
    }
 
135
 
 
136
    return true;
 
137
}
 
138
 
 
139
static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
 
140
        QAbstractFileEngine *&engine, bool resolvingEntry = false)
 
141
{
 
142
    QString const &filePath = entry.filePath();
 
143
    if ((engine = qt_custom_file_engine_handler_create(filePath)))
 
144
        return _q_checkEntry(engine, resolvingEntry);
 
145
 
 
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('/'))
 
150
            break;
 
151
 
 
152
        if (ch == QLatin1Char(':')) {
 
153
            if (prefixSeparator == 0) {
 
154
                engine = new QResourceFileEngine(filePath);
 
155
                return _q_checkEntry(engine, resolvingEntry);
 
156
            }
 
157
 
 
158
            if (prefixSeparator == 1)
 
159
                break;
 
160
 
 
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)));
 
164
                // Recurse!
 
165
                if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
 
166
                    return true;
 
167
            }
 
168
 
 
169
            // entry may have been clobbered at this point.
 
170
            return false;
 
171
        }
 
172
 
 
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.
 
176
        //
 
177
        //  if (!ch.isLetterOrNumber())
 
178
        //      break;
 
179
    }
 
180
#endif // defined(QT_BUILD_CORE_LIB)
 
181
 
 
182
    return _q_checkEntry(entry, data, resolvingEntry);
 
183
}
 
184
 
 
185
/*!
 
186
    \internal
 
187
 
 
188
    Resolves the \a entry (see QDir::searchPaths) and returns an engine for
 
189
    it, but never a QFSFileEngine.
 
190
 
 
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
 
193
    system object.
 
194
*/
 
195
QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
 
196
        QFileSystemEntry &entry, QFileSystemMetaData &data) {
 
197
    QFileSystemEntry copy = entry;
 
198
    QAbstractFileEngine *engine = 0;
 
199
 
 
200
    if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
 
201
        // Reset entry to resolved copy.
 
202
        entry = copy;
 
203
    else
 
204
        data.clear();
 
205
 
 
206
    return engine;
 
207
}
 
208
 
 
209
//these unix functions are in this file, because they are shared by symbian port
 
210
//for open C file handles.
 
211
#ifdef Q_OS_UNIX
 
212
//static
 
213
bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
 
214
{
 
215
    data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
 
216
    data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
 
217
 
 
218
    QT_STATBUF statBuffer;
 
219
    if (QT_FSTAT(fd, &statBuffer) == 0) {
 
220
        data.fillFromStatBuf(statBuffer);
 
221
        return true;
 
222
    }
 
223
 
 
224
    return false;
 
225
}
 
226
 
 
227
#if defined(Q_OS_QNX)
 
228
static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
 
229
{
 
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;
 
237
}
 
238
#endif
 
239
 
 
240
void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
 
241
{
 
242
    // Permissions
 
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;
 
249
 
 
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;
 
256
 
 
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;
 
263
 
 
264
    // Type
 
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;
 
269
    else
 
270
        entryFlags |= QFileSystemMetaData::SequentialType;
 
271
 
 
272
    // Attributes
 
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;
 
280
    }
 
281
#endif
 
282
 
 
283
    // Times
 
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;
 
289
}
 
290
 
 
291
void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
 
292
{
 
293
#if defined(Q_OS_QNX)
 
294
    knownFlagsMask = 0;
 
295
    entryFlags = 0;
 
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) {
 
299
 
 
300
            const struct dirent_extra_stat * const extra_stat =
 
301
                    reinterpret_cast<struct dirent_extra_stat *>(extra);
 
302
 
 
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;
 
308
            }
 
309
 
 
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)
 
316
                continue;
 
317
 
 
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);
 
324
#else
 
325
            fillFromStatBuf(extra_stat->d_stat);
 
326
#endif
 
327
            knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
 
328
            if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
 
329
                knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
 
330
                entryFlags |= QFileSystemMetaData::ExistsAttribute;
 
331
            }
 
332
        }
 
333
    }
 
334
#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
 
335
    // BSD4 includes Mac OS X
 
336
 
 
337
    // ### This will clear all entry flags and knownFlagsMask
 
338
    switch (entry.d_type)
 
339
    {
 
340
    case DT_DIR:
 
341
        knownFlagsMask = QFileSystemMetaData::LinkType
 
342
            | QFileSystemMetaData::FileType
 
343
            | QFileSystemMetaData::DirectoryType
 
344
            | QFileSystemMetaData::SequentialType
 
345
            | QFileSystemMetaData::ExistsAttribute;
 
346
 
 
347
        entryFlags = QFileSystemMetaData::DirectoryType
 
348
            | QFileSystemMetaData::ExistsAttribute;
 
349
 
 
350
        break;
 
351
 
 
352
    case DT_BLK:
 
353
    case DT_CHR:
 
354
    case DT_FIFO:
 
355
    case DT_SOCK:
 
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;
 
364
 
 
365
        entryFlags = QFileSystemMetaData::SequentialType
 
366
            | QFileSystemMetaData::ExistsAttribute;
 
367
 
 
368
        break;
 
369
 
 
370
    case DT_LNK:
 
371
        knownFlagsMask = QFileSystemMetaData::LinkType;
 
372
        entryFlags = QFileSystemMetaData::LinkType;
 
373
        break;
 
374
 
 
375
    case DT_REG:
 
376
        knownFlagsMask = QFileSystemMetaData::LinkType
 
377
            | QFileSystemMetaData::FileType
 
378
            | QFileSystemMetaData::DirectoryType
 
379
            | QFileSystemMetaData::BundleType
 
380
            | QFileSystemMetaData::SequentialType
 
381
            | QFileSystemMetaData::ExistsAttribute;
 
382
 
 
383
        entryFlags = QFileSystemMetaData::FileType
 
384
            | QFileSystemMetaData::ExistsAttribute;
 
385
 
 
386
        break;
 
387
 
 
388
    case DT_UNKNOWN:
 
389
    default:
 
390
        clear();
 
391
    }
 
392
#else
 
393
    Q_UNUSED(entry)
 
394
#endif
 
395
}
 
396
 
 
397
#endif
 
398
 
 
399
//static
 
400
QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
 
401
{
 
402
#if defined(Q_OS_WIN)
 
403
    Q_UNUSED(metaData);
 
404
    return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
 
405
#else //(Q_OS_UNIX)
 
406
    if (!metaData.hasFlags(QFileSystemMetaData::UserId))
 
407
        QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
 
408
    return resolveUserName(metaData.userId());
 
409
#endif
 
410
}
 
411
 
 
412
//static
 
413
QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
 
414
{
 
415
#if defined(Q_OS_WIN)
 
416
    Q_UNUSED(metaData);
 
417
    return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
 
418
#else //(Q_OS_UNIX)
 
419
    if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
 
420
        QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
 
421
    return resolveGroupName(metaData.groupId());
 
422
#endif
 
423
}
 
424
 
 
425
QT_END_NAMESPACE