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