source: trunk/src/corelib/io/qfsfileengine.cpp @ 929

Last change on this file since 929 was 929, checked in by Dmitry A. Kuminov, 9 years ago

OS/2: QProcess: Reverted r923 (superseded by r928).

File size: 27.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file.  Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights.  These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file.  Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfsfileengine_p.h"
43#include "qfsfileengine_iterator_p.h"
44#include "qdatetime.h"
45#include "qdiriterator.h"
46#include "qset.h"
47#include <QtCore/qdebug.h>
48
49#ifndef QT_NO_FSFILEENGINE
50
51#if !defined(Q_OS_WINCE)
52#include <errno.h>
53#endif
54#if defined(Q_OS_UNIX)
55#include "private/qcore_unix_p.h"
56#endif
57#include <stdio.h>
58#include <stdlib.h>
59#if defined(Q_OS_MAC)
60# include <private/qcore_mac_p.h>
61#endif
62
63QT_BEGIN_NAMESPACE
64
65#ifdef Q_OS_WIN
66#  ifndef S_ISREG
67#    define S_ISREG(x)   (((x) & S_IFMT) == S_IFREG)
68#  endif
69#  ifndef S_ISCHR
70#    define S_ISCHR(x)   (((x) & S_IFMT) == S_IFCHR)
71#  endif
72#  ifndef S_ISFIFO
73#    define S_ISFIFO(x) false
74#  endif
75#  ifndef S_ISSOCK
76#    define S_ISSOCK(x) false
77#  endif
78#  ifndef INVALID_FILE_ATTRIBUTES
79#    define INVALID_FILE_ATTRIBUTES (DWORD (-1))
80#  endif
81#endif
82
83/*! \class QFSFileEngine
84    \brief The QFSFileEngine class implements Qt's default file engine.
85    \since 4.1
86
87    This class is part of the file engine framework in Qt. If you only want to
88    access files or directories, use QFile, QFileInfo or QDir instead.
89
90    QFSFileEngine is the default file engine for accessing regular files. It
91    is provided for convenience; by subclassing this class, you can alter its
92    behavior slightly, without having to write a complete QAbstractFileEngine
93    subclass. To install your custom file engine, you must also subclass
94    QAbstractFileEngineHandler and create an instance of your handler.
95
96    It can also be useful to create a QFSFileEngine object directly if you
97    need to use the local file system inside QAbstractFileEngine::create(), in
98    order to avoid recursion (as higher-level classes tend to call
99    QAbstractFileEngine::create()).
100*/
101
102//**************** QFSFileEnginePrivate
103QFSFileEnginePrivate::QFSFileEnginePrivate() : QAbstractFileEnginePrivate()
104{
105    init();
106}
107
108/*!
109    \internal
110*/
111void QFSFileEnginePrivate::init()
112{
113    is_sequential = 0;
114    tried_stat = 0;
115#if !defined(Q_OS_WINCE)
116    need_lstat = 1;
117    is_link = 0;
118#endif
119    openMode = QIODevice::NotOpen;
120    fd = -1;
121    fh = 0;
122    lastIOCommand = IOFlushCommand;
123    lastFlushFailed = false;
124    closeFileHandle = false;
125#ifdef Q_OS_WIN
126    fileAttrib = INVALID_FILE_ATTRIBUTES;
127    fileHandle = INVALID_HANDLE_VALUE;
128    mapHandle = INVALID_HANDLE_VALUE;
129#ifndef Q_OS_WINCE
130    cachedFd = -1;
131#endif
132#endif
133}
134
135/*!
136    \internal
137
138    Returns the canonicalized form of \a path (i.e., with all symlinks
139    resolved, and all redundant path elements removed.
140*/
141QString QFSFileEnginePrivate::canonicalized(const QString &path)
142{
143    if (path.isEmpty())
144        return path;
145
146    // FIXME let's see if this stuff works, then we might be able to remove some of the other code.
147#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
148    if (path.size() == 1 && path.at(0) == QLatin1Char('/'))
149        return path;
150#endif
151#if defined(Q_OS_LINUX) || defined(Q_OS_SYMBIAN) || defined(Q_OS_MAC)
152    // ... but Linux with uClibc does not have it
153#if !defined(__UCLIBC__)
154    char *ret = 0;
155#if defined(Q_OS_MAC)
156    // Mac OS X 10.5.x doesn't support the realpath(X,0) extension we use here.
157    if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) {
158        ret = realpath(path.toLocal8Bit().constData(), (char*)0);
159    } else {
160        // on 10.5 we can use FSRef to resolve the file path.
161        FSRef fsref;
162        if (FSPathMakeRef((const UInt8 *)QDir::cleanPath(path).toUtf8().data(), &fsref, 0) == noErr) {
163            CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref);
164            CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle);
165            QString ret = QCFString::toQString(canonicalPath);
166            CFRelease(canonicalPath);
167            CFRelease(urlref);
168            return ret;
169        }
170    }
171#else
172    ret = realpath(path.toLocal8Bit().constData(), (char*)0);
173#endif
174    if (ret) {
175        QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret));
176        free(ret);
177        return canonicalPath;
178    }
179#endif
180#endif
181
182    QFileInfo fi;
183    const QChar slash(QLatin1Char('/'));
184    QString tmpPath = path;
185    int separatorPos = 0;
186    QSet<QString> nonSymlinks;
187    QSet<QString> known;
188
189    known.insert(path);
190    do {
191#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
192        // UNC, skip past the first two elements
193        if (separatorPos == 0 && tmpPath.startsWith(QLatin1String("//")))
194            separatorPos = tmpPath.indexOf(slash, 2);
195        if (separatorPos != -1)
196#endif
197        separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
198        QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
199        if (
200#ifdef Q_OS_SYMBIAN
201            // Symbian doesn't support directory symlinks, so do not check for link unless we
202            // are handling the last path element. This not only slightly improves performance,
203            // but also saves us from lot of unnecessary platform security check failures
204            // when dealing with files under *:/private directories.
205            separatorPos == -1 &&
206#endif
207            !nonSymlinks.contains(prefix)) {
208            fi.setFile(prefix);
209            if (fi.isSymLink()) {
210                QString target = fi.symLinkTarget();
211                if (separatorPos != -1) {
212                    if (fi.isDir() && !target.endsWith(slash))
213                        target.append(slash);
214                    target.append(tmpPath.mid(separatorPos));
215                }
216                tmpPath = QDir::cleanPath(target);
217                separatorPos = 0;
218
219                if (known.contains(tmpPath))
220                    return QString();
221                known.insert(tmpPath);
222            } else {
223                nonSymlinks.insert(prefix);
224            }
225        }
226    } while (separatorPos != -1);
227
228    return QDir::cleanPath(tmpPath);
229}
230
231/*!
232    Constructs a QFSFileEngine for the file name \a file.
233*/
234QFSFileEngine::QFSFileEngine(const QString &file) : QAbstractFileEngine(*new QFSFileEnginePrivate)
235{
236    Q_D(QFSFileEngine);
237    d->filePath = QDir::fromNativeSeparators(file);
238    d->nativeInitFileName();
239}
240
241/*!
242    Constructs a QFSFileEngine.
243*/
244QFSFileEngine::QFSFileEngine() : QAbstractFileEngine(*new QFSFileEnginePrivate)
245{
246}
247
248/*!
249    \internal
250*/
251QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
252    : QAbstractFileEngine(dd)
253{
254}
255
256/*!
257    Destructs the QFSFileEngine.
258*/
259QFSFileEngine::~QFSFileEngine()
260{
261    Q_D(QFSFileEngine);
262    if (d->closeFileHandle) {
263        if (d->fh) {
264            int ret;
265            do {
266                ret = fclose(d->fh);
267            } while (ret == EOF && errno == EINTR);
268        } else if (d->fd != -1) {
269            int ret;
270            do {
271                ret = QT_CLOSE(d->fd);
272            } while (ret == -1 && errno == EINTR);
273        }
274    }
275    QList<uchar*> keys = d->maps.keys();
276    for (int i = 0; i < keys.count(); ++i)
277        unmap(keys.at(i));
278}
279
280/*!
281    \reimp
282*/
283void QFSFileEngine::setFileName(const QString &file)
284{
285    Q_D(QFSFileEngine);
286    d->init();
287    d->filePath = QDir::fromNativeSeparators(file);
288    d->nativeInitFileName();
289}
290
291/*!
292    \reimp
293*/
294bool QFSFileEngine::open(QIODevice::OpenMode openMode)
295{
296    Q_D(QFSFileEngine);
297    if (d->filePath.isEmpty()) {
298        qWarning("QFSFileEngine::open: No file name specified");
299        setError(QFile::OpenError, QLatin1String("No file name specified"));
300        return false;
301    }
302
303    // Append implies WriteOnly.
304    if (openMode & QFile::Append)
305        openMode |= QFile::WriteOnly;
306
307    // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
308    if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
309        openMode |= QFile::Truncate;
310
311    d->openMode = openMode;
312    d->lastFlushFailed = false;
313    d->tried_stat = 0;
314    d->fh = 0;
315    d->fd = -1;
316
317    return d->nativeOpen(openMode);
318}
319
320/*!
321    Opens the file handle \a fh in \a openMode mode. Returns true on
322    success; otherwise returns false.
323*/
324bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
325{
326    Q_D(QFSFileEngine);
327
328    // Append implies WriteOnly.
329    if (openMode & QFile::Append)
330        openMode |= QFile::WriteOnly;
331
332    // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
333    if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
334        openMode |= QFile::Truncate;
335
336    d->openMode = openMode;
337    d->lastFlushFailed = false;
338    d->closeFileHandle = false;
339    d->nativeFilePath.clear();
340    d->filePath.clear();
341    d->tried_stat = 0;
342    d->fd = -1;
343
344    return d->openFh(openMode, fh);
345}
346
347/*!
348    Opens the file handle \a fh using the open mode \a flags.
349*/
350bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
351{
352    Q_Q(QFSFileEngine);
353    this->fh = fh;
354    fd = -1;
355
356    // Seek to the end when in Append mode.
357    if (openMode & QIODevice::Append) {
358        int ret;
359        do {
360            ret = QT_FSEEK(fh, 0, SEEK_END);
361        } while (ret != 0 && errno == EINTR);
362
363        if (ret != 0) {
364            q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
365                        qt_error_string(int(errno)));
366
367            this->openMode = QIODevice::NotOpen;
368            this->fh = 0;
369
370            return false;
371        }
372    }
373
374    return true;
375}
376
377/*!
378    Opens the file descriptor \a fd in \a openMode mode. Returns true
379    on success; otherwise returns false.
380*/
381bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd)
382{
383    Q_D(QFSFileEngine);
384
385    // Append implies WriteOnly.
386    if (openMode & QFile::Append)
387        openMode |= QFile::WriteOnly;
388
389    // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
390    if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
391        openMode |= QFile::Truncate;
392
393    d->openMode = openMode;
394    d->lastFlushFailed = false;
395    d->closeFileHandle = false;
396    d->nativeFilePath.clear();
397    d->filePath.clear();
398    d->fh = 0;
399    d->fd = -1;
400    d->tried_stat = 0;
401
402    return d->openFd(openMode, fd);
403}
404
405
406/*!
407    Opens the file descriptor \a fd to the file engine, using the open mode \a
408    flags.
409*/
410bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
411{
412    Q_Q(QFSFileEngine);
413    this->fd = fd;
414    fh = 0;
415
416    // Seek to the end when in Append mode.
417    if (openMode & QFile::Append) {
418        int ret;
419        do {
420            ret = QT_LSEEK(fd, 0, SEEK_END);
421        } while (ret == -1 && errno == EINTR);
422
423        if (ret == -1) {
424            q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
425                        qt_error_string(int(errno)));
426
427            this->openMode = QIODevice::NotOpen;
428            this->fd = -1;
429
430            return false;
431        }
432    }
433
434    return true;
435}
436
437/*!
438    \reimp
439*/
440bool QFSFileEngine::close()
441{
442    Q_D(QFSFileEngine);
443    d->openMode = QIODevice::NotOpen;
444    return d->nativeClose();
445}
446
447/*!
448    \internal
449*/
450bool QFSFileEnginePrivate::closeFdFh()
451{
452    Q_Q(QFSFileEngine);
453    if (fd == -1 && !fh)
454        return false;
455
456    // Flush the file if it's buffered, and if the last flush didn't fail.
457    bool flushed = !fh || (!lastFlushFailed && q->flush());
458    bool closed = true;
459    tried_stat = 0;
460
461    // Close the file if we created the handle.
462    if (closeFileHandle) {
463        int ret;
464        do {
465            if (fh) {
466                // Close buffered file.
467                ret = fclose(fh) != 0 ? -1 : 0;
468            } else {
469                // Close unbuffered file.
470                ret = QT_CLOSE(fd);
471            }
472        } while (ret == -1 && errno == EINTR);
473
474        // We must reset these guys regardless; calling close again after a
475        // failed close causes crashes on some systems.
476        fh = 0;
477        fd = -1;
478        closed = (ret == 0);
479    }
480
481    // Report errors.
482    if (!flushed || !closed) {
483        if (flushed) {
484            // If not flushed, we want the flush error to fall through.
485            q->setError(QFile::UnspecifiedError, qt_error_string(errno));
486        }
487        return false;
488    }
489
490    return true;
491}
492
493/*!
494    \reimp
495*/
496bool QFSFileEngine::flush()
497{
498    Q_D(QFSFileEngine);
499    if ((d->openMode & QIODevice::WriteOnly) == 0) {
500        // Nothing in the write buffers, so flush succeeds in doing
501        // nothing.
502        return true;
503    }
504    return d->nativeFlush();
505}
506
507/*!
508    \internal
509*/
510bool QFSFileEnginePrivate::flushFh()
511{
512    Q_Q(QFSFileEngine);
513
514    // Never try to flush again if the last flush failed. Otherwise you can
515    // get crashes on some systems (AIX).
516    if (lastFlushFailed)
517        return false;
518
519    int ret = fflush(fh);
520
521    lastFlushFailed = (ret != 0);
522    lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
523
524    if (ret != 0) {
525        q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
526                    qt_error_string(errno));
527        return false;
528    }
529    return true;
530}
531
532/*!
533    \reimp
534*/
535qint64 QFSFileEngine::size() const
536{
537    Q_D(const QFSFileEngine);
538    return d->nativeSize();
539}
540
541/*!
542    \internal
543*/
544qint64 QFSFileEnginePrivate::sizeFdFh() const
545{
546    Q_Q(const QFSFileEngine);
547    // ### Fix this function, it should not stat unless the file is closed.
548    QT_STATBUF st;
549    int ret = 0;
550    const_cast<QFSFileEngine *>(q)->flush();
551    if (fh && nativeFilePath.isEmpty()) {
552        // Buffered stdlib mode.
553        // ### This should really be an ftell
554        ret = QT_FSTAT(QT_FILENO(fh), &st);
555    } else if (fd == -1) {
556        // Stateless stat.
557        ret = QT_STAT(nativeFilePath.constData(), &st);
558    } else {
559        // Unbuffered stdio mode.
560        ret = QT_FSTAT(fd, &st);
561    }
562    if (ret == -1)
563        return 0;
564    return st.st_size;
565}
566
567/*!
568    \reimp
569*/
570qint64 QFSFileEngine::pos() const
571{
572    Q_D(const QFSFileEngine);
573    return d->nativePos();
574}
575
576/*!
577    \internal
578*/
579qint64 QFSFileEnginePrivate::posFdFh() const
580{
581    if (fh)
582        return qint64(QT_FTELL(fh));
583    return QT_LSEEK(fd, 0, SEEK_CUR);
584}
585
586/*!
587    \reimp
588*/
589bool QFSFileEngine::seek(qint64 pos)
590{
591    Q_D(QFSFileEngine);
592    return d->nativeSeek(pos);
593}
594
595/*!
596    \internal
597*/
598bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
599{
600    Q_Q(QFSFileEngine);
601
602    // On Windows' stdlib implementation, the results of calling fread and
603    // fwrite are undefined if not called either in sequence, or if preceded
604    // with a call to fflush().
605    if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
606        return false;
607
608    if (pos < 0 || pos != qint64(QT_OFF_T(pos)))
609        return false;
610
611    if (fh) {
612        // Buffered stdlib mode.
613        int ret;
614        do {
615            ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
616        } while (ret != 0 && errno == EINTR);
617
618        if (ret != 0) {
619            q->setError(QFile::ReadError, qt_error_string(int(errno)));
620            return false;
621        }
622    } else {
623        // Unbuffered stdio mode.
624        if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
625            qWarning() << "QFile::at: Cannot set file position" << pos;
626            q->setError(QFile::PositionError, qt_error_string(errno));
627            return false;
628        }
629    }
630    return true;
631}
632
633/*!
634    \reimp
635*/
636int QFSFileEngine::handle() const
637{
638    Q_D(const QFSFileEngine);
639    return d->nativeHandle();
640}
641
642/*!
643    \reimp
644*/
645qint64 QFSFileEngine::read(char *data, qint64 maxlen)
646{
647    Q_D(QFSFileEngine);
648
649    // On Windows' stdlib implementation, the results of calling fread and
650    // fwrite are undefined if not called either in sequence, or if preceded
651    // with a call to fflush().
652    if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
653        flush();
654        d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
655    }
656
657    return d->nativeRead(data, maxlen);
658}
659
660/*!
661    \internal
662*/
663qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
664{
665    Q_Q(QFSFileEngine);
666
667    if (len < 0 || len != qint64(size_t(len))) {
668        q->setError(QFile::ReadError, qt_error_string(EINVAL));
669        return -1;
670    }
671
672    qint64 readBytes = 0;
673    bool eof = false;
674
675    if (fh) {
676        // Buffered stdlib mode.
677
678        size_t result;
679        bool retry = true;
680        do {
681            result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
682            eof = feof(fh);
683            if (retry && eof && result == 0) {
684                // On Mac OS, this is needed, e.g., if a file was written to
685                // through another stream since our last read. See test
686                // tst_QFile::appendAndRead
687                QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
688                retry = false;
689                continue;
690            }
691            readBytes += result;
692        } while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
693
694    } else if (fd != -1) {
695        // Unbuffered stdio mode.
696
697#ifdef Q_OS_WIN
698        int result;
699#else
700        ssize_t result;
701#endif
702        do {
703            result = QT_READ(fd, data + readBytes, size_t(len - readBytes));
704        } while ((result == -1 && errno == EINTR)
705                || (result > 0 && (readBytes += result) < len));
706
707        eof = !(result == -1);
708    }
709
710    if (!eof && readBytes == 0) {
711        readBytes = -1;
712        q->setError(QFile::ReadError, qt_error_string(errno));
713    }
714
715    return readBytes;
716}
717
718/*!
719    \reimp
720*/
721qint64 QFSFileEngine::readLine(char *data, qint64 maxlen)
722{
723    Q_D(QFSFileEngine);
724
725    // On Windows' stdlib implementation, the results of calling fread and
726    // fwrite are undefined if not called either in sequence, or if preceded
727    // with a call to fflush().
728    if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
729        flush();
730        d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
731    }
732
733    return d->nativeReadLine(data, maxlen);
734}
735
736/*!
737    \internal
738*/
739qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
740{
741    Q_Q(QFSFileEngine);
742    if (!fh)
743        return q->QAbstractFileEngine::readLine(data, maxlen);
744
745    QT_OFF_T oldPos = 0;
746#ifdef Q_OS_WIN
747    bool seq = q->isSequential();
748    if (!seq)
749#endif
750        oldPos = QT_FTELL(fh);
751
752    // QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
753    // because it has made space for the '\0' at the end of data.  But fgets
754    // does the same, so we'd get two '\0' at the end - passing maxlen + 1
755    // solves this.
756    if (!fgets(data, int(maxlen + 1), fh)) {
757        if (!feof(fh))
758            q->setError(QFile::ReadError, qt_error_string(int(errno)));
759        return -1;              // error
760    }
761
762#ifdef Q_OS_WIN
763    if (seq)
764        return qstrlen(data);
765#endif
766
767    qint64 lineLength = QT_FTELL(fh) - oldPos;
768    return lineLength > 0 ? lineLength : qstrlen(data);
769}
770
771/*!
772    \reimp
773*/
774qint64 QFSFileEngine::write(const char *data, qint64 len)
775{
776    Q_D(QFSFileEngine);
777
778    // On Windows' stdlib implementation, the results of calling fread and
779    // fwrite are undefined if not called either in sequence, or if preceded
780    // with a call to fflush().
781    if (d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
782        flush();
783        d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
784    }
785
786    return d->nativeWrite(data, len);
787}
788
789/*!
790    \internal
791*/
792qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
793{
794    Q_Q(QFSFileEngine);
795
796    if (len < 0 || len != qint64(size_t(len))) {
797        q->setError(QFile::WriteError, qt_error_string(EINVAL));
798        return -1;
799    }
800
801    qint64 writtenBytes = 0;
802
803    if (fh) {
804        // Buffered stdlib mode.
805
806        size_t result;
807        do {
808            result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
809            writtenBytes += result;
810        } while (result == 0 ? errno == EINTR : writtenBytes < len);
811
812    } else if (fd != -1) {
813        // Unbuffered stdio mode.
814
815#ifdef Q_OS_WIN
816        int result;
817#else
818        ssize_t result;
819#endif
820        do {
821            result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes));
822        } while ((result == -1 && errno == EINTR)
823                || (result > 0 && (writtenBytes += result) < len));
824    }
825
826    if (len &&  writtenBytes == 0) {
827        writtenBytes = -1;
828        q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
829    }
830
831    return writtenBytes;
832}
833
834/*!
835    \internal
836*/
837QAbstractFileEngine::Iterator *QFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
838{
839    return new QFSFileEngineIterator(filters, filterNames);
840}
841
842/*!
843    \internal
844*/
845QAbstractFileEngine::Iterator *QFSFileEngine::endEntryList()
846{
847    return 0;
848}
849
850/*!
851    \internal
852*/
853QStringList QFSFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
854{
855    return QAbstractFileEngine::entryList(filters, filterNames);
856}
857
858/*!
859    \reimp
860*/
861bool QFSFileEngine::isSequential() const
862{
863    Q_D(const QFSFileEngine);
864    if (d->is_sequential == 0)
865        d->is_sequential = d->nativeIsSequential() ? 1 : 2;
866    return d->is_sequential == 1;
867}
868
869/*!
870    \internal
871*/
872bool QFSFileEnginePrivate::isSequentialFdFh() const
873{
874    if (!tried_stat)
875        doStat();
876    if (could_stat) {
877#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
878        return (st.st_mode & S_IFMT) != S_IFREG;
879        // ### WINDOWS!
880#endif
881    }
882    return true;
883}
884
885/*!
886    \reimp
887*/
888bool QFSFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
889{
890    Q_D(QFSFileEngine);
891    if (extension == AtEndExtension && d->fh && isSequential())
892        return feof(d->fh);
893
894    if (extension == MapExtension) {
895        const MapExtensionOption *options = (MapExtensionOption*)(option);
896        MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
897        returnValue->address = d->map(options->offset, options->size, options->flags);
898        return (returnValue->address != 0);
899    }
900    if (extension == UnMapExtension) {
901        UnMapExtensionOption *options = (UnMapExtensionOption*)option;
902        return d->unmap(options->address);
903    }
904
905    return false;
906}
907
908/*!
909    \reimp
910*/
911bool QFSFileEngine::supportsExtension(Extension extension) const
912{
913    Q_D(const QFSFileEngine);
914    if (extension == AtEndExtension && d->fh && isSequential())
915        return true;
916    if (extension == FastReadLineExtension && d->fh)
917        return true;
918    if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
919        return true;
920    if (extension == UnMapExtension || extension == MapExtension)
921        return true;
922    return false;
923}
924
925/*! \fn bool QFSFileEngine::caseSensitive() const
926  Returns true for Windows, false for Unix.
927*/
928
929/*! \fn bool QFSFileEngine::copy(const QString &copyName)
930
931  For windows, copy the file to file \a copyName.
932
933  Not implemented for Unix.
934*/
935
936/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
937  For Unix, returns the current working directory for the file
938  engine.
939
940  For Windows and OS/2, returns the canonicalized form of the current path used
941  by the file engine for the drive specified by \a fileName.  On Windows and on
942  OS/2, each drive has its own current directory, so a different path is
943  returned for file names that include different drive names (e.g. A: or C:).
944
945  \sa setCurrentPath()
946*/
947
948/*! \fn QFileInfoList QFSFileEngine::drives()
949  For Windows, returns the list of drives in the file system as a list
950  of QFileInfo objects. On unix, Mac OS X and Windows CE, only the
951  root path is returned.  On Windows, this function returns all drives
952  (A:\, C:\, D:\, etc.).
953
954  For Unix, the list contains just the root path "/".
955*/
956
957/*! \fn QString QFSFileEngine::fileName(FileName file) const
958  \reimp
959*/
960
961/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const
962  \reimp
963*/
964
965/*! \fn QString QFSFileEngine::homePath()
966  Returns the home path of the current user.
967
968  \sa rootPath()
969*/
970
971/*! \fn bool QFSFileEngine::isRelativePath() const
972  \reimp
973*/
974
975/*! \fn bool QFSFileEngine::link(const QString &newName)
976
977  Creates a link from the file currently specified by fileName() to
978  \a newName. What a link is depends on the underlying filesystem
979  (be it a shortcut on Windows or a symbolic link on Unix). Returns
980  true if successful; otherwise returns false.
981*/
982
983/*! \fn bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
984  \reimp
985*/
986
987/*! \fn uint QFSFileEngine::ownerId(FileOwner own) const
988  In Unix, if stat() is successful, the \c uid is returned if
989  \a own is the owner. Otherwise the \c gid is returned. If stat()
990  is unsuccessful, -2 is reuturned.
991
992  For Windows, -2 is always returned.
993*/
994
995/*! \fn QString QFSFileEngine::owner(FileOwner own) const
996  \reimp
997*/
998
999/*! \fn bool QFSFileEngine::remove()
1000  \reimp
1001*/
1002
1003/*! \fn bool QFSFileEngine::rename(const QString &newName)
1004  \reimp
1005*/
1006
1007/*! \fn bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
1008  \reimp
1009*/
1010
1011/*! \fn QString QFSFileEngine::rootPath()
1012  Returns the root path.
1013
1014  \sa homePath()
1015*/
1016
1017/*! \fn bool QFSFileEngine::setCurrentPath(const QString &path)
1018  Sets the current path (e.g., for QDir), to \a path. Returns true if the
1019  new path exists; otherwise this function does nothing, and returns false.
1020
1021  \sa currentPath()
1022*/
1023
1024/*! \fn bool QFSFileEngine::setPermissions(uint perms)
1025  \reimp
1026*/
1027
1028/*! \fn bool QFSFileEngine::setSize(qint64 size)
1029  \reimp
1030*/
1031
1032/*! \fn QString QFSFileEngine::tempPath()
1033  Returns the temporary path (i.e., a path in which it is safe
1034  to store temporary files).
1035*/
1036
1037/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
1038    \internal
1039*/
1040
1041QT_END_NAMESPACE
1042
1043#endif // QT_NO_FSFILEENGINE
Note: See TracBrowser for help on using the repository browser.