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

« back to all changes in this revision

Viewing changes to src/corelib/io/qfsfileengine_unix.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 "qplatformdefs.h"
 
43
#include "private/qabstractfileengine_p.h"
 
44
#include "private/qfsfileengine_p.h"
 
45
#include "private/qcore_unix_p.h"
 
46
#include "qfilesystementry_p.h"
 
47
#include "qfilesystemengine_p.h"
 
48
 
 
49
#ifndef QT_NO_FSFILEENGINE
 
50
 
 
51
#include "qfile.h"
 
52
#include "qdir.h"
 
53
#include "qdatetime.h"
 
54
#include "qvarlengtharray.h"
 
55
 
 
56
#include <sys/mman.h>
 
57
#include <stdlib.h>
 
58
#include <limits.h>
 
59
#include <errno.h>
 
60
#if !defined(QWS) && defined(Q_OS_MAC)
 
61
# include <private/qcore_mac_p.h>
 
62
#endif
 
63
 
 
64
QT_BEGIN_NAMESPACE
 
65
 
 
66
/*!
 
67
    \internal
 
68
 
 
69
    Returns the stdlib open string corresponding to a QIODevice::OpenMode.
 
70
*/
 
71
static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry,
 
72
        QFileSystemMetaData &metaData)
 
73
{
 
74
    QByteArray mode;
 
75
    if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
 
76
        mode = "rb";
 
77
        if (flags & QIODevice::WriteOnly) {
 
78
            metaData.clearFlags(QFileSystemMetaData::FileType);
 
79
            if (!fileEntry.isEmpty()
 
80
                    && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType)
 
81
                    && metaData.isFile()) {
 
82
                mode += '+';
 
83
            } else {
 
84
                mode = "wb+";
 
85
            }
 
86
        }
 
87
    } else if (flags & QIODevice::WriteOnly) {
 
88
        mode = "wb";
 
89
        if (flags & QIODevice::ReadOnly)
 
90
            mode += '+';
 
91
    }
 
92
    if (flags & QIODevice::Append) {
 
93
        mode = "ab";
 
94
        if (flags & QIODevice::ReadOnly)
 
95
            mode += '+';
 
96
    }
 
97
 
 
98
#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
 
99
    // must be glibc >= 2.7
 
100
    mode += 'e';
 
101
#endif
 
102
 
 
103
    return mode;
 
104
}
 
105
 
 
106
/*!
 
107
    \internal
 
108
 
 
109
    Returns the stdio open flags corresponding to a QIODevice::OpenMode.
 
110
*/
 
111
static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
 
112
{
 
113
    int oflags = QT_OPEN_RDONLY;
 
114
#ifdef QT_LARGEFILE_SUPPORT
 
115
    oflags |= QT_OPEN_LARGEFILE;
 
116
#endif
 
117
 
 
118
    if ((mode & QFile::ReadWrite) == QFile::ReadWrite) {
 
119
        oflags = QT_OPEN_RDWR | QT_OPEN_CREAT;
 
120
    } else if (mode & QFile::WriteOnly) {
 
121
        oflags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
 
122
    }
 
123
 
 
124
    if (mode & QFile::Append) {
 
125
        oflags |= QT_OPEN_APPEND;
 
126
    } else if (mode & QFile::WriteOnly) {
 
127
        if ((mode & QFile::Truncate) || !(mode & QFile::ReadOnly))
 
128
            oflags |= QT_OPEN_TRUNC;
 
129
    }
 
130
 
 
131
    return oflags;
 
132
}
 
133
 
 
134
/*!
 
135
    \internal
 
136
 
 
137
    Sets the file descriptor to close on exec. That is, the file
 
138
    descriptor is not inherited by child processes.
 
139
*/
 
140
static inline bool setCloseOnExec(int fd)
 
141
{
 
142
    return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
 
143
}
 
144
 
 
145
/*!
 
146
    \internal
 
147
*/
 
148
bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
 
149
{
 
150
    Q_Q(QFSFileEngine);
 
151
 
 
152
    if (openMode & QIODevice::Unbuffered) {
 
153
        int flags = openModeToOpenFlags(openMode);
 
154
 
 
155
        // Try to open the file in unbuffered mode.
 
156
        do {
 
157
            fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666);
 
158
        } while (fd == -1 && errno == EINTR);
 
159
 
 
160
        // On failure, return and report the error.
 
161
        if (fd == -1) {
 
162
            q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
 
163
                        qt_error_string(errno));
 
164
            return false;
 
165
        }
 
166
 
 
167
        if (!(openMode & QIODevice::WriteOnly)) {
 
168
            // we don't need this check if we tried to open for writing because then
 
169
            // we had received EISDIR anyway.
 
170
            if (QFileSystemEngine::fillMetaData(fd, metaData)
 
171
                    && metaData.isDirectory()) {
 
172
                q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
 
173
                QT_CLOSE(fd);
 
174
                return false;
 
175
            }
 
176
        }
 
177
 
 
178
        // Seek to the end when in Append mode.
 
179
        if (flags & QFile::Append) {
 
180
            int ret;
 
181
            do {
 
182
                ret = QT_LSEEK(fd, 0, SEEK_END);
 
183
            } while (ret == -1 && errno == EINTR);
 
184
 
 
185
            if (ret == -1) {
 
186
                q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
 
187
                            qt_error_string(int(errno)));
 
188
                return false;
 
189
            }
 
190
        }
 
191
 
 
192
        fh = 0;
 
193
    } else {
 
194
        QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData);
 
195
 
 
196
        // Try to open the file in buffered mode.
 
197
        do {
 
198
            fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData());
 
199
        } while (!fh && errno == EINTR);
 
200
 
 
201
        // On failure, return and report the error.
 
202
        if (!fh) {
 
203
            q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
 
204
                        qt_error_string(int(errno)));
 
205
            return false;
 
206
        }
 
207
 
 
208
        if (!(openMode & QIODevice::WriteOnly)) {
 
209
            // we don't need this check if we tried to open for writing because then
 
210
            // we had received EISDIR anyway.
 
211
            if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData)
 
212
                    && metaData.isDirectory()) {
 
213
                q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
 
214
                fclose(fh);
 
215
                return false;
 
216
            }
 
217
        }
 
218
 
 
219
        setCloseOnExec(fileno(fh)); // ignore failure
 
220
 
 
221
        // Seek to the end when in Append mode.
 
222
        if (openMode & QIODevice::Append) {
 
223
            int ret;
 
224
            do {
 
225
                ret = QT_FSEEK(fh, 0, SEEK_END);
 
226
            } while (ret == -1 && errno == EINTR);
 
227
 
 
228
            if (ret == -1) {
 
229
                q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
 
230
                            qt_error_string(int(errno)));
 
231
                return false;
 
232
            }
 
233
        }
 
234
 
 
235
        fd = -1;
 
236
    }
 
237
 
 
238
    closeFileHandle = true;
 
239
    return true;
 
240
}
 
241
 
 
242
/*!
 
243
    \internal
 
244
*/
 
245
bool QFSFileEnginePrivate::nativeClose()
 
246
{
 
247
    return closeFdFh();
 
248
}
 
249
 
 
250
/*!
 
251
    \internal
 
252
 
 
253
*/
 
254
bool QFSFileEnginePrivate::nativeFlush()
 
255
{
 
256
    return fh ? flushFh() : fd != -1;
 
257
}
 
258
 
 
259
/*!
 
260
    \internal
 
261
*/
 
262
qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len)
 
263
{
 
264
    Q_Q(QFSFileEngine);
 
265
 
 
266
    if (fh && nativeIsSequential()) {
 
267
        size_t readBytes = 0;
 
268
        int oldFlags = fcntl(QT_FILENO(fh), F_GETFL);
 
269
        for (int i = 0; i < 2; ++i) {
 
270
            // Unix: Make the underlying file descriptor non-blocking
 
271
            if ((oldFlags & O_NONBLOCK) == 0)
 
272
                fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK);
 
273
 
 
274
            // Cross platform stdlib read
 
275
            size_t read = 0;
 
276
            do {
 
277
                read = fread(data + readBytes, 1, size_t(len - readBytes), fh);
 
278
            } while (read == 0 && !feof(fh) && errno == EINTR);
 
279
            if (read > 0) {
 
280
                readBytes += read;
 
281
                break;
 
282
            } else {
 
283
                if (readBytes)
 
284
                    break;
 
285
                readBytes = read;
 
286
            }
 
287
 
 
288
            // Unix: Restore the blocking state of the underlying socket
 
289
            if ((oldFlags & O_NONBLOCK) == 0) {
 
290
                fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
 
291
                if (readBytes == 0) {
 
292
                    int readByte = 0;
 
293
                    do {
 
294
                        readByte = fgetc(fh);
 
295
                    } while (readByte == -1 && errno == EINTR);
 
296
                    if (readByte != -1) {
 
297
                        *data = uchar(readByte);
 
298
                        readBytes += 1;
 
299
                    } else {
 
300
                        break;
 
301
                    }
 
302
                }
 
303
            }
 
304
        }
 
305
        // Unix: Restore the blocking state of the underlying socket
 
306
        if ((oldFlags & O_NONBLOCK) == 0) {
 
307
            fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
 
308
        }
 
309
        if (readBytes == 0 && !feof(fh)) {
 
310
            // if we didn't read anything and we're not at EOF, it must be an error
 
311
            q->setError(QFile::ReadError, qt_error_string(int(errno)));
 
312
            return -1;
 
313
        }
 
314
        return readBytes;
 
315
    }
 
316
 
 
317
    return readFdFh(data, len);
 
318
}
 
319
 
 
320
/*!
 
321
    \internal
 
322
*/
 
323
qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen)
 
324
{
 
325
    return readLineFdFh(data, maxlen);
 
326
}
 
327
 
 
328
/*!
 
329
    \internal
 
330
*/
 
331
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
 
332
{
 
333
    return writeFdFh(data, len);
 
334
}
 
335
 
 
336
/*!
 
337
    \internal
 
338
*/
 
339
qint64 QFSFileEnginePrivate::nativePos() const
 
340
{
 
341
    return posFdFh();
 
342
}
 
343
 
 
344
/*!
 
345
    \internal
 
346
*/
 
347
bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
 
348
{
 
349
    return seekFdFh(pos);
 
350
}
 
351
 
 
352
/*!
 
353
    \internal
 
354
*/
 
355
int QFSFileEnginePrivate::nativeHandle() const
 
356
{
 
357
    return fh ? fileno(fh) : fd;
 
358
}
 
359
 
 
360
/*!
 
361
    \internal
 
362
*/
 
363
bool QFSFileEnginePrivate::nativeIsSequential() const
 
364
{
 
365
    return isSequentialFdFh();
 
366
}
 
367
 
 
368
bool QFSFileEngine::remove()
 
369
{
 
370
    Q_D(QFSFileEngine);
 
371
    QSystemError error;
 
372
    bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
 
373
    d->metaData.clear();
 
374
    if (!ret) {
 
375
        setError(QFile::RemoveError, error.toString());
 
376
    }
 
377
    return ret;
 
378
}
 
379
 
 
380
bool QFSFileEngine::copy(const QString &newName)
 
381
{
 
382
    Q_D(QFSFileEngine);
 
383
    QSystemError error;
 
384
    bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), error);
 
385
    if (!ret) {
 
386
        setError(QFile::CopyError, error.toString());
 
387
    }
 
388
    return ret;
 
389
}
 
390
 
 
391
bool QFSFileEngine::rename(const QString &newName)
 
392
{
 
393
    Q_D(QFSFileEngine);
 
394
    QSystemError error;
 
395
    bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
 
396
 
 
397
    if (!ret) {
 
398
        setError(QFile::RenameError, error.toString());
 
399
    }
 
400
 
 
401
    return ret;
 
402
}
 
403
 
 
404
bool QFSFileEngine::link(const QString &newName)
 
405
{
 
406
    Q_D(QFSFileEngine);
 
407
    QSystemError error;
 
408
    bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), error);
 
409
    if (!ret) {
 
410
        setError(QFile::RenameError, error.toString());
 
411
    }
 
412
    return ret;
 
413
}
 
414
 
 
415
qint64 QFSFileEnginePrivate::nativeSize() const
 
416
{
 
417
    return sizeFdFh();
 
418
}
 
419
 
 
420
bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
 
421
{
 
422
    return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
 
423
}
 
424
 
 
425
bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
 
426
{
 
427
    return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
 
428
}
 
429
 
 
430
bool QFSFileEngine::caseSensitive() const
 
431
{
 
432
    return true;
 
433
}
 
434
 
 
435
bool QFSFileEngine::setCurrentPath(const QString &path)
 
436
{
 
437
    return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
 
438
}
 
439
 
 
440
QString QFSFileEngine::currentPath(const QString &)
 
441
{
 
442
    return QFileSystemEngine::currentPath().filePath();
 
443
}
 
444
 
 
445
QString QFSFileEngine::homePath()
 
446
{
 
447
    return QFileSystemEngine::homePath();
 
448
}
 
449
 
 
450
QString QFSFileEngine::rootPath()
 
451
{
 
452
    return QFileSystemEngine::rootPath();
 
453
}
 
454
 
 
455
QString QFSFileEngine::tempPath()
 
456
{
 
457
    return QFileSystemEngine::tempPath();
 
458
}
 
459
 
 
460
QFileInfoList QFSFileEngine::drives()
 
461
{
 
462
    QFileInfoList ret;
 
463
    ret.append(QFileInfo(rootPath()));
 
464
    return ret;
 
465
}
 
466
 
 
467
bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
 
468
{
 
469
    if (!tried_stat || !metaData.hasFlags(flags)) {
 
470
        tried_stat = 1;
 
471
 
 
472
        int localFd = fd;
 
473
        if (fh && fileEntry.isEmpty())
 
474
            localFd = QT_FILENO(fh);
 
475
        if (localFd != -1)
 
476
            QFileSystemEngine::fillMetaData(localFd, metaData);
 
477
 
 
478
        if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
 
479
            QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
 
480
    }
 
481
 
 
482
    return metaData.exists();
 
483
}
 
484
 
 
485
bool QFSFileEnginePrivate::isSymlink() const
 
486
{
 
487
    if (!metaData.hasFlags(QFileSystemMetaData::LinkType))
 
488
        QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::LinkType);
 
489
 
 
490
    return metaData.isLink();
 
491
}
 
492
 
 
493
/*!
 
494
    \reimp
 
495
*/
 
496
QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
 
497
{
 
498
    Q_D(const QFSFileEngine);
 
499
 
 
500
    if (type & Refresh)
 
501
        d->metaData.clear();
 
502
 
 
503
    QAbstractFileEngine::FileFlags ret = 0;
 
504
 
 
505
    if (type & FlagsMask)
 
506
        ret |= LocalDiskFlag;
 
507
 
 
508
    bool exists;
 
509
    {
 
510
        QFileSystemMetaData::MetaDataFlags queryFlags = 0;
 
511
 
 
512
        queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
 
513
                & QFileSystemMetaData::Permissions;
 
514
 
 
515
        if (type & TypesMask)
 
516
            queryFlags |= QFileSystemMetaData::AliasType
 
517
                    | QFileSystemMetaData::LinkType
 
518
                    | QFileSystemMetaData::FileType
 
519
                    | QFileSystemMetaData::DirectoryType
 
520
                    | QFileSystemMetaData::BundleType;
 
521
 
 
522
        if (type & FlagsMask)
 
523
            queryFlags |= QFileSystemMetaData::HiddenAttribute
 
524
                    | QFileSystemMetaData::ExistsAttribute;
 
525
 
 
526
        queryFlags |= QFileSystemMetaData::LinkType;
 
527
 
 
528
        exists = d->doStat(queryFlags);
 
529
    }
 
530
 
 
531
    if (!exists && !d->metaData.isLink())
 
532
        return ret;
 
533
 
 
534
    if (exists && (type & PermsMask))
 
535
        ret |= FileFlags(uint(d->metaData.permissions()));
 
536
 
 
537
    if (type & TypesMask) {
 
538
        if (d->metaData.isAlias()) {
 
539
            ret |= LinkType;
 
540
        } else {
 
541
            if ((type & LinkType) && d->metaData.isLink())
 
542
                ret |= LinkType;
 
543
            if (exists) {
 
544
                if (d->metaData.isFile()) {
 
545
                    ret |= FileType;
 
546
                } else if (d->metaData.isDirectory()) {
 
547
                    ret |= DirectoryType;
 
548
                    if ((type & BundleType) && d->metaData.isBundle())
 
549
                        ret |= BundleType;
 
550
                }
 
551
            }
 
552
        }
 
553
    }
 
554
 
 
555
    if (type & FlagsMask) {
 
556
        if (exists)
 
557
            ret |= ExistsFlag;
 
558
        if (d->fileEntry.isRoot())
 
559
            ret |= RootFlag;
 
560
        else if (d->metaData.isHidden())
 
561
            ret |= HiddenFlag;
 
562
    }
 
563
 
 
564
    return ret;
 
565
}
 
566
 
 
567
QString QFSFileEngine::fileName(FileName file) const
 
568
{
 
569
    Q_D(const QFSFileEngine);
 
570
    if (file == BundleName) {
 
571
        return QFileSystemEngine::bundleName(d->fileEntry);
 
572
    } else if (file == BaseName) {
 
573
        return d->fileEntry.fileName();
 
574
    } else if (file == PathName) {
 
575
        return d->fileEntry.path();
 
576
    } else if (file == AbsoluteName || file == AbsolutePathName) {
 
577
        QFileSystemEntry entry(QFileSystemEngine::absoluteName(d->fileEntry));
 
578
        if (file == AbsolutePathName) {
 
579
            return entry.path();
 
580
        }
 
581
        return entry.filePath();
 
582
    } else if (file == CanonicalName || file == CanonicalPathName) {
 
583
        QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData));
 
584
        if (file == CanonicalPathName)
 
585
            return entry.path();
 
586
        return entry.filePath();
 
587
    } else if (file == LinkName) {
 
588
        if (d->isSymlink()) {
 
589
            QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
 
590
            return entry.filePath();
 
591
        }
 
592
        return QString();
 
593
    }
 
594
    return d->fileEntry.filePath();
 
595
}
 
596
 
 
597
bool QFSFileEngine::isRelativePath() const
 
598
{
 
599
    Q_D(const QFSFileEngine);
 
600
    return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
 
601
}
 
602
 
 
603
uint QFSFileEngine::ownerId(FileOwner own) const
 
604
{
 
605
    Q_D(const QFSFileEngine);
 
606
    static const uint nobodyID = (uint) -2;
 
607
 
 
608
    if (d->doStat(QFileSystemMetaData::OwnerIds))
 
609
        return d->metaData.ownerId(own);
 
610
 
 
611
    return nobodyID;
 
612
}
 
613
 
 
614
QString QFSFileEngine::owner(FileOwner own) const
 
615
{
 
616
    if (own == OwnerUser)
 
617
        return QFileSystemEngine::resolveUserName(ownerId(own));
 
618
    return QFileSystemEngine::resolveGroupName(ownerId(own));
 
619
}
 
620
 
 
621
bool QFSFileEngine::setPermissions(uint perms)
 
622
{
 
623
    Q_D(QFSFileEngine);
 
624
    QSystemError error;
 
625
    if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0)) {
 
626
        setError(QFile::PermissionsError, error.toString());
 
627
        return false;
 
628
    }
 
629
    return true;
 
630
}
 
631
 
 
632
bool QFSFileEngine::setSize(qint64 size)
 
633
{
 
634
    Q_D(QFSFileEngine);
 
635
    bool ret = false;
 
636
    if (d->fd != -1)
 
637
        ret = QT_FTRUNCATE(d->fd, size) == 0;
 
638
    else if (d->fh)
 
639
        ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
 
640
    else
 
641
        ret = QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size) == 0;
 
642
    if (!ret)
 
643
        setError(QFile::ResizeError, qt_error_string(errno));
 
644
    return ret;
 
645
}
 
646
 
 
647
QDateTime QFSFileEngine::fileTime(FileTime time) const
 
648
{
 
649
    Q_D(const QFSFileEngine);
 
650
 
 
651
    if (d->doStat(QFileSystemMetaData::Times))
 
652
        return d->metaData.fileTime(time);
 
653
 
 
654
    return QDateTime();
 
655
}
 
656
 
 
657
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
 
658
{
 
659
    Q_Q(QFSFileEngine);
 
660
    Q_UNUSED(flags);
 
661
    if (openMode == QIODevice::NotOpen) {
 
662
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
 
663
        return 0;
 
664
    }
 
665
 
 
666
    if (offset < 0 || offset != qint64(QT_OFF_T(offset))
 
667
            || size < 0 || quint64(size) > quint64(size_t(-1))) {
 
668
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
 
669
        return 0;
 
670
    }
 
671
 
 
672
    // If we know the mapping will extend beyond EOF, fail early to avoid
 
673
    // undefined behavior. Otherwise, let mmap have its say.
 
674
    if (doStat(QFileSystemMetaData::SizeAttribute)
 
675
            && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
 
676
        qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable");
 
677
 
 
678
    int access = 0;
 
679
    if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
 
680
    if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
 
681
 
 
682
#if defined(Q_OS_INTEGRITY)
 
683
    int pageSize = sysconf(_SC_PAGESIZE);
 
684
#else
 
685
    int pageSize = getpagesize();
 
686
#endif
 
687
    int extra = offset % pageSize;
 
688
 
 
689
    if (quint64(size + extra) > quint64((size_t)-1)) {
 
690
        q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
 
691
        return 0;
 
692
    }
 
693
 
 
694
    size_t realSize = (size_t)size + extra;
 
695
    QT_OFF_T realOffset = QT_OFF_T(offset);
 
696
    realOffset &= ~(QT_OFF_T(pageSize - 1));
 
697
 
 
698
    void *mapAddress = QT_MMAP((void*)0, realSize,
 
699
                   access, MAP_SHARED, nativeHandle(), realOffset);
 
700
    if (MAP_FAILED != mapAddress) {
 
701
        uchar *address = extra + static_cast<uchar*>(mapAddress);
 
702
        maps[address] = QPair<int,size_t>(extra, realSize);
 
703
        return address;
 
704
    }
 
705
 
 
706
    switch(errno) {
 
707
    case EBADF:
 
708
        q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
 
709
        break;
 
710
    case ENFILE:
 
711
    case ENOMEM:
 
712
        q->setError(QFile::ResourceError, qt_error_string(int(errno)));
 
713
        break;
 
714
    case EINVAL:
 
715
        // size are out of bounds
 
716
    default:
 
717
        q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
 
718
        break;
 
719
    }
 
720
    return 0;
 
721
}
 
722
 
 
723
bool QFSFileEnginePrivate::unmap(uchar *ptr)
 
724
{
 
725
#if !defined(Q_OS_INTEGRITY)
 
726
    Q_Q(QFSFileEngine);
 
727
    if (!maps.contains(ptr)) {
 
728
        q->setError(QFile::PermissionsError, qt_error_string(EACCES));
 
729
        return false;
 
730
    }
 
731
 
 
732
    uchar *start = ptr - maps[ptr].first;
 
733
    size_t len = maps[ptr].second;
 
734
    if (-1 == munmap(start, len)) {
 
735
        q->setError(QFile::UnspecifiedError, qt_error_string(errno));
 
736
        return false;
 
737
    }
 
738
    maps.remove(ptr);
 
739
    return true;
 
740
#else
 
741
    return false;
 
742
#endif
 
743
}
 
744
 
 
745
QT_END_NAMESPACE
 
746
 
 
747
#endif // QT_NO_FSFILEENGINE