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

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

trunk: Merged in qt 4.6.2 sources.

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