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 test suite 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 
43 #include <QtTest/QtTest>
44 #include <qplatformdefs.h>
45 
46 #include <QAbstractFileEngine>
47 #include <QFSFileEngine>
48 #include <QCoreApplication>
49 #include <QDebug>
50 #include <QDir>
51 #include <QFile>
52 #include <QFileInfo>
53 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
54 #include <QHostInfo>
55 #endif
56 #include <QProcess>
57 #ifndef Q_OS_WIN
58 # include <sys/types.h>
59 # include <unistd.h>
60 #endif
61 #ifdef Q_OS_MAC
62 # include <sys/mount.h>
63 #elif defined(Q_OS_LINUX)
64 # include <sys/vfs.h>
65 #elif defined(Q_OS_FREEBSD)
66 # include <sys/param.h>
67 # include <sys/mount.h>
68 #elif defined(Q_OS_IRIX)
69 # include <sys/statfs.h>
70 #elif defined(Q_OS_WINCE)
71 # include <qplatformdefs.h>
72 # include <private/qfsfileengine_p.h>
73 #elif defined(Q_OS_SYMBIAN)
74 # include <f32file.h>
75 #endif
76 
77 #include <stdio.h>
78 #include <errno.h>
79 
80 #ifndef NO_NETWORK_TEST
81 #  include "../network-settings.h"
82 #endif
83 
84 #if defined(Q_OS_SYMBIAN)
85 # define SRCDIR ""
86 #endif
87 
88 #ifndef STDIN_FILENO
89 #define STDIN_FILENO 0
90 #endif
91 
92 #ifndef STDOUT_FILENO
93 #define STDOUT_FILENO 1
94 #endif
95 
96 #ifndef STDERR_FILENO
97 #define STDERR_FILENO 2
98 #endif
99 
100 #ifndef QT_OPEN_BINARY
101 #define QT_OPEN_BINARY 0
102 #endif
103 
104 Q_DECLARE_METATYPE(QFile::FileError)
105 
106 //TESTED_CLASS=
107 //TESTED_FILES=
108 
109 class tst_QFile : public QObject
110 {
111     Q_OBJECT
112 
113 public:
114     tst_QFile();
115     virtual ~tst_QFile();
116 
117 
118 public slots:
119     void init();
120     void cleanup();
121 private slots:
122     void initTestCase();
123     void cleanupTestCase();
124     void exists();
125     void open_data();
126     void open();
127     void openUnbuffered();
128     void size_data();
129     void size();
130     void sizeNoExist();
131     void seek();
132     void setSize();
133     void setSizeSeek();
134     void seekToSamePosition();
135     void atEnd();
136     void readLine();
137     void readLine2();
138     void readLineNullInLine();
139     void readAll_data();
140     void readAll();
141     void readAllBuffer();
142     void readAllStdin();
143     void readLineStdin();
144     void readLineStdin_lineByLine();
145     void text();
146     void missingEndOfLine();
147     void readBlock();
148     void getch();
149     void ungetChar();
150     void createFile();
151     void append();
152     void permissions_data();
153     void permissions();
154     void setPermissions();
155     void copy();
156     void copyAfterFail();
157     void copyRemovesTemporaryFile() const;
158     void copyShouldntOverwrite();
159     void copyFallback();
160     void link();
161     void linkToDir();
162     void absolutePathLinkToRelativePath();
163     void readBrokenLink();
164     void readTextFile_data();
165     void readTextFile();
166     void readTextFile2();
167     void writeTextFile_data();
168     void writeTextFile();
169     /* void largeFileSupport(); */
170 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
171     void largeUncFileSupport();
172 #endif
173     void tailFile();
174     void flush();
175     void bufferedRead();
176     void isSequential();
177     void encodeName();
178     void truncate();
179     void seekToPos();
180     void seekAfterEndOfFile();
181     void FILEReadWrite();
182     void i18nFileName_data();
183     void i18nFileName();
184     void longFileName_data();
185     void longFileName();
186     void fileEngineHandler();
187     void useQFileInAFileHandler();
188     void getCharFF();
189     void remove_and_exists();
190     void removeOpenFile();
191     void fullDisk();
192     void writeLargeDataBlock_data();
193     void writeLargeDataBlock();
194     void readFromWriteOnlyFile();
195     void writeToReadOnlyFile();
196     void virtualFile();
197     void textFile();
198     void rename_data();
199     void rename();
200     void renameWithAtEndSpecialFile() const;
201     void renameFallback();
202     void renameMultiple();
203     void appendAndRead();
204     void miscWithUncPathAsCurrentDir();
205     void standarderror();
206     void handle();
207     void nativeHandleLeaks();
208 
209     void readEof_data();
210     void readEof();
211 
212     void map_data();
213     void map();
214     void mapResource_data();
215     void mapResource();
216     void mapOpenMode_data();
217     void mapOpenMode();
218 
219     void openStandardStreams();
220 
221     void resize_data();
222     void resize();
223 
224     void objectConstructors();
225 #ifdef Q_OS_SYMBIAN
226     void platformSecurity_data();
227     void platformSecurity();
228 #endif
229     void caseSensitivity();
230 
231     void autocloseHandle();
232 
233     // --- Task related tests below this line
234     void task167217();
235 
236     void openDirectory();
237     void writeNothing();
238 
239 public:
240 // disabled this test for the moment... it hangs
241     void invalidFile_data();
242     void invalidFile();
243 
244 private:
245     enum FileType {
246         OpenQFile,
247         OpenFd,
248         OpenStream,
249 #ifdef Q_OS_SYMBIAN
250         OpenRFile,
251 #endif
252         NumberOfFileTypes
253     };
254 
255     void openStandardStreamsFileDescriptors();
256     void openStandardStreamsBufferedStreams();
257 
openFd(QFile & file,QIODevice::OpenMode mode,QFile::FileHandleFlags handleFlags)258     bool openFd(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
259     {
260         int fdMode = QT_OPEN_LARGEFILE | QT_OPEN_BINARY;
261 
262         // File will be truncated if in Write mode.
263         if (mode & QIODevice::WriteOnly)
264             fdMode |= QT_OPEN_WRONLY | QT_OPEN_TRUNC;
265         if (mode & QIODevice::ReadOnly)
266             fdMode |= QT_OPEN_RDONLY;
267 
268         fd_ = QT_OPEN(qPrintable(file.fileName()), fdMode);
269 
270         return (-1 != fd_) && file.open(fd_, mode, handleFlags);
271     }
272 
openStream(QFile & file,QIODevice::OpenMode mode,QFile::FileHandleFlags handleFlags)273     bool openStream(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
274     {
275         char const *streamMode = "";
276 
277         // File will be truncated if in Write mode.
278         if (mode & QIODevice::WriteOnly)
279             streamMode = "wb+";
280         else if (mode & QIODevice::ReadOnly)
281             streamMode = "rb";
282 
283         stream_ = QT_FOPEN(qPrintable(file.fileName()), streamMode);
284 
285         return stream_ && file.open(stream_, mode, handleFlags);
286     }
287 
288 #ifdef Q_OS_SYMBIAN
openRFile(QFile & file,QIODevice::OpenMode mode,QFile::FileHandleFlags handleFlags)289     bool openRFile(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
290     {
291         //connect file server first time
292         if (!rfs_.Handle() && rfs_.Connect() != KErrNone)
293                 return false;
294         //symbian does not like ./ in filenames, so open by absolute path
295         QString fileName(QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()));
296         TPtrC fn(fileName.utf16(), fileName.length());
297         TInt smode = 0;
298         if (mode & QIODevice::WriteOnly)
299             smode |= EFileWrite;
300         if (mode & QIODevice::ReadOnly)
301             smode |= EFileRead;
302         TInt r;
303         if ((mode & QIODevice::Truncate) || (!(mode & QIODevice::ReadOnly) && !(mode & QIODevice::Append))) {
304             r = rfile_.Replace(rfs_, fn, smode);
305         } else {
306             r = rfile_.Open(rfs_, fn, smode);
307             if (r == KErrNotFound && (mode & QIODevice::WriteOnly)) {
308                 r = rfile_.Create(rfs_, fn, smode);
309             }
310         }
311         return (r == KErrNone) && file.open(rfile_, mode, handleFlags);
312     }
313 #endif
314 
openFile(QFile & file,QIODevice::OpenMode mode,FileType type=OpenQFile,QFile::FileHandleFlags handleFlags=QFile::DontCloseHandle)315     bool openFile(QFile &file, QIODevice::OpenMode mode, FileType type = OpenQFile, QFile::FileHandleFlags handleFlags = QFile::DontCloseHandle)
316     {
317         if (mode & QIODevice::WriteOnly && !file.exists())
318         {
319             // Make sure the file exists
320             QFile createFile(file.fileName());
321             if (!createFile.open(QIODevice::ReadWrite))
322                 return false;
323         }
324 
325         // Note: openFd and openStream will truncate the file if write mode.
326         switch (type)
327         {
328             case OpenQFile:
329                 return file.open(mode);
330 
331             case OpenFd:
332                 return openFd(file, mode, handleFlags);
333 
334             case OpenStream:
335                 return openStream(file, mode, handleFlags);
336 #ifdef Q_OS_SYMBIAN
337             case OpenRFile:
338                 return openRFile(file, mode, handleFlags);
339 #endif
340         }
341 
342         return false;
343     }
344 
closeFile(QFile & file)345     void closeFile(QFile &file)
346     {
347         file.close();
348 
349         if (-1 != fd_)
350             QT_CLOSE(fd_);
351         if (stream_)
352             ::fclose(stream_);
353 #ifdef Q_OS_SYMBIAN
354         if (rfile_.SubSessionHandle())
355             rfile_.Close();
356 #endif
357 
358         fd_ = -1;
359         stream_ = 0;
360     }
361 
362     int fd_;
363     FILE *stream_;
364 #ifdef Q_OS_SYMBIAN
365     RFs rfs_;
366     RFile rfile_;
367 #endif
368 
369     const QString m_srcDir;
370     const QString m_stdinProcess;
371 };
372 
findStdinProcess()373 static inline QString findStdinProcess()
374 {
375     QString result = QCoreApplication::applicationDirPath();
376 #ifdef Q_OS_WIN
377     // cd up from debug/release paths
378     if (result.endsWith(QLatin1String("debug"), Qt::CaseInsensitive)
379         || result.endsWith(QLatin1String("release"), Qt::CaseInsensitive)) {
380         result.truncate(result.lastIndexOf(QLatin1Char('/')));
381     }
382 #endif
383     result += QLatin1String("/stdinprocess/stdinprocess");
384 #ifdef Q_OS_WIN
385     result += QLatin1String(".exe");
386 #endif
387     const QFileInfo fi(result);
388     if (fi.exists() && fi.isExecutable())
389         return fi.absoluteFilePath();
390     return QString();
391 }
392 
tst_QFile()393 tst_QFile::tst_QFile()
394     : m_srcDir(QLatin1String(SRCDIR))
395     , m_stdinProcess(findStdinProcess())
396 {
397 }
398 
~tst_QFile()399 tst_QFile::~tst_QFile()
400 {
401 
402 }
403 
init()404 void tst_QFile::init()
405 {
406 // TODO: Add initialization code here.
407 // This will be executed immediately before each test is run.
408     fd_ = -1;
409     stream_ = 0;
410 }
411 
cleanup()412 void tst_QFile::cleanup()
413 {
414 // TODO: Add cleanup code here.
415 // This will be executed immediately after each test is run.
416 
417     // for copyFallback()
418     if (QFile::exists("file-copy-destination.txt")) {
419         QFile::setPermissions("file-copy-destination.txt",
420                 QFile::ReadOwner | QFile::WriteOwner);
421         QFile::remove("file-copy-destination.txt");
422     }
423 
424     // for renameFallback()
425     QFile::remove("file-rename-destination.txt");
426 
427     // for copyAfterFail()
428     QFile::remove("file-to-be-copied.txt");
429     QFile::remove("existing-file.txt");
430     QFile::remove("copied-file-1.txt");
431     QFile::remove("copied-file-2.txt");
432 
433     // for renameMultiple()
434     QFile::remove("file-to-be-renamed.txt");
435     QFile::remove("existing-file.txt");
436     QFile::remove("file-renamed-once.txt");
437     QFile::remove("file-renamed-twice.txt");
438 
439     if (-1 != fd_)
440         QT_CLOSE(fd_);
441     if (stream_)
442         ::fclose(stream_);
443 }
444 
initTestCase()445 void tst_QFile::initTestCase()
446 {
447     QDir srcDir(m_srcDir);
448     QVERIFY2(srcDir.exists(), qPrintable(m_srcDir + QLatin1String(" does not exist.")));
449     QDir::setCurrent(srcDir.absolutePath());
450     QVERIFY2(!m_stdinProcess.isEmpty(),
451              qPrintable("Cannot locate stdinprocess from " + QCoreApplication::applicationDirPath()));
452 
453     QFile::remove("noreadfile");
454 
455     // create a file and make it read-only
456     QFile file("readonlyfile");
457     file.open(QFile::WriteOnly);
458     file.write("a", 1);
459     file.close();
460     file.setPermissions(QFile::ReadOwner);
461 
462     // create another file and make it not readable
463     file.setFileName("noreadfile");
464     file.open(QFile::WriteOnly);
465     file.write("b", 1);
466     file.close();
467     file.setPermissions(0);
468 }
469 
cleanupTestCase()470 void tst_QFile::cleanupTestCase()
471 {
472     // clean up the files we created
473     QFile::remove("readonlyfile");
474     QFile::remove("noreadfile");
475     QFile::remove("myLink.lnk");
476     QFile::remove("appendme.txt");
477     QFile::remove("createme.txt");
478     QFile::remove("file.txt");
479     QFile::remove("genfile.txt");
480     QFile::remove("seekToPos.txt");
481     QFile::remove("setsizeseek.txt");
482     QFile::remove("stdfile.txt");
483     QFile::remove("textfile.txt");
484     QFile::remove("truncate.txt");
485     QFile::remove("winfile.txt");
486     QFile::remove("writeonlyfile");
487     QFile::remove("largeblockfile.txt");
488     QFile::remove("tst_qfile_copy.cpp");
489     QFile::remove("nullinline.txt");
490     QFile::remove("myLink2.lnk");
491     QFile::remove("resources");
492     QFile::remove("qfile_map_testfile");
493     QFile::remove("readAllBuffer.txt");
494     QFile::remove("qt_file.tmp");
495     QFile::remove("File.txt");
496     QFile::remove("seekToSamePosition.txt");
497 }
498 
499 //------------------------------------------
500 // The 'testfile' is currently just a
501 // testfile. The path of this file, the
502 // attributes and the contents itself
503 // will be changed as far as we have a
504 // proper way to handle files in the
505 // testing environment.
506 //------------------------------------------
507 
exists()508 void tst_QFile::exists()
509 {
510     QFile f( SRCDIR "testfile.txt" );
511     QCOMPARE( f.exists(), (bool)TRUE );
512 
513     QFile file("nobodyhassuchafile");
514     file.remove();
515     QVERIFY(!file.exists());
516 
517     QFile file2("nobodyhassuchafile");
518     QVERIFY(file2.open(QIODevice::WriteOnly));
519     file2.close();
520 
521     QVERIFY(file.exists());
522 
523     QVERIFY(file.open(QIODevice::WriteOnly));
524     file.close();
525     QVERIFY(file.exists());
526 
527     file.remove();
528     QVERIFY(!file.exists());
529 
530 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
531     QFile unc("//" + QtNetworkSettings::winServerName() + "/testshare/readme.txt");
532     QVERIFY(unc.exists());
533 #endif
534 }
535 
open_data()536 void tst_QFile::open_data()
537 {
538     QTest::addColumn<QString>("filename");
539     QTest::addColumn<int>("mode");
540     QTest::addColumn<bool>("ok");
541     QTest::addColumn<QFile::FileError>("status");
542 
543 #ifdef Q_OS_MAC
544     static const QString denied("Operation not permitted");
545 #else
546     static const QString denied("Permission denied");
547 #endif
548     QTest::newRow( "exist_readOnly"  )
549         << QString(SRCDIR "testfile.txt") << int(QIODevice::ReadOnly)
550         << (bool)TRUE << QFile::NoError;
551 
552     QTest::newRow( "exist_writeOnly" )
553         << QString("readonlyfile")
554         << int(QIODevice::WriteOnly)
555         << (bool)FALSE
556         << QFile::OpenError;
557 
558     QTest::newRow( "exist_append"    )
559         << QString("readonlyfile") << int(QIODevice::Append)
560         << (bool)FALSE << QFile::OpenError;
561 
562     QTest::newRow( "nonexist_readOnly"  )
563         << QString("nonExist.txt") << int(QIODevice::ReadOnly)
564         << (bool)FALSE << QFile::OpenError;
565 
566     QTest::newRow("emptyfile")
567         << QString("")
568         << int(QIODevice::ReadOnly)
569         << (bool)FALSE
570         << QFile::OpenError;
571 
572     QTest::newRow("nullfile") << QString() << int(QIODevice::ReadOnly) << (bool)FALSE
573         << QFile::OpenError;
574 
575     QTest::newRow("two-dots") << QString(SRCDIR "two.dots.file") << int(QIODevice::ReadOnly) << (bool)TRUE
576         << QFile::NoError;
577 
578     QTest::newRow("readonlyfile") << QString("readonlyfile") << int(QIODevice::WriteOnly)
579                                   << (bool)FALSE << QFile::OpenError;
580     QTest::newRow("noreadfile") << QString("noreadfile") << int(QIODevice::ReadOnly)
581                                 << (bool)FALSE << QFile::OpenError;
582 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
583     const QString drive0 = QLatin1String("//./PhysicalDrive0");
584     const QFileInfo drive0Fi(drive0);
585     if (drive0Fi.exists() && drive0Fi.isReadable()) {
586         QTest::newRow(qPrintable(drive0))
587             << drive0 << int(QIODevice::ReadOnly)
588             << (bool)TRUE << QFile::NoError;
589     } else {
590         qWarning("Skipping '%s' (requires administrative permissions)", qPrintable(drive0));
591     }
592 #  ifndef NO_NETWORK_TEST
593     QTest::newRow("uncFile") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri" << int(QIODevice::ReadOnly)
594                              << true << QFile::NoError;
595 #  endif
596 #endif
597 }
598 
open()599 void tst_QFile::open()
600 {
601     QFETCH( QString, filename );
602     QFETCH( int, mode );
603 
604     QFile f( filename );
605 
606     QFETCH( bool, ok );
607 
608 #if defined(Q_OS_SYMBIAN)
609     if (qstrcmp(QTest::currentDataTag(), "noreadfile") == 0)
610         QSKIP("Symbian does not support non-readable files", SkipSingle);
611 #elif defined(Q_OS_UNIX)
612     if (::getuid() == 0)
613         // root and Chuck Norris don't care for file permissions. Skip.
614         QSKIP("Running this test as root doesn't make sense", SkipAll);
615 #endif
616 
617 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
618     QEXPECT_FAIL("noreadfile", "Windows does not currently support non-readable files.", Abort);
619 #endif
620     if (filename.isEmpty())
621         QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified");
622 
623     if (ok) {
624         QVERIFY2(f.open(QIODevice::OpenMode(mode)),
625                  qPrintable(QString::fromLatin1("Cannot open %1 in mode %2: %3")
626                             .arg(filename).arg(mode).arg(f.errorString())));
627     } else {
628         QVERIFY(!f.open(QIODevice::OpenMode(mode)));
629     }
630 
631     QTEST( f.error(), "status" );
632 }
633 
openUnbuffered()634 void tst_QFile::openUnbuffered()
635 {
636     QFile file(SRCDIR "testfile.txt");
637     QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
638     char c = '\0';
639     QVERIFY(file.seek(1));
640     QCOMPARE(file.pos(), qint64(1));
641     QVERIFY(file.getChar(&c));
642     QCOMPARE(file.pos(), qint64(2));
643     char d = '\0';
644     QVERIFY(file.seek(3));
645     QCOMPARE(file.pos(), qint64(3));
646     QVERIFY(file.getChar(&d));
647     QCOMPARE(file.pos(), qint64(4));
648     QVERIFY(file.seek(1));
649     QCOMPARE(file.pos(), qint64(1));
650     char c2 = '\0';
651     QVERIFY(file.getChar(&c2));
652     QCOMPARE(file.pos(), qint64(2));
653     QVERIFY(file.seek(3));
654     QCOMPARE(file.pos(), qint64(3));
655     char d2 = '\0';
656     QVERIFY(file.getChar(&d2));
657     QCOMPARE(file.pos(), qint64(4));
658     QCOMPARE(c, c2);
659     QCOMPARE(d, d2);
660     QCOMPARE(c, '-');
661     QCOMPARE(d, '-');
662 }
663 
size_data()664 void tst_QFile::size_data()
665 {
666     QTest::addColumn<QString>("filename");
667     QTest::addColumn<qint64>("size");
668 
669     QTest::newRow( "exist01" ) << QString(SRCDIR "testfile.txt") << (qint64)245;
670 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
671     // Only test UNC on Windows./
672     QTest::newRow("unc") << "//" + QString(QtNetworkSettings::winServerName() + "/testshare/test.pri") << (qint64)34;
673 #endif
674 }
675 
size()676 void tst_QFile::size()
677 {
678     QFETCH( QString, filename );
679     QFETCH( qint64, size );
680 
681 #ifdef Q_WS_WINCE
682         filename = QFileInfo(filename).absoluteFilePath();
683 #endif
684 
685     {
686         QFile f( filename );
687         QCOMPARE( f.size(), size );
688 
689         QVERIFY( f.open(QIODevice::ReadOnly) );
690         QCOMPARE( f.size(), size );
691     }
692 
693     {
694         QFile f;
695         FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb");
696         QVERIFY( stream );
697         QVERIFY( f.open(stream, QIODevice::ReadOnly) );
698         QCOMPARE( f.size(), size );
699 
700         f.close();
701         fclose(stream);
702     }
703 
704     {
705 #ifdef Q_WS_WINCE
706         QSKIP("Currently low level file I/O not well supported on Windows CE", SkipSingle);
707 #endif
708         QFile f;
709 
710         int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY);
711 
712         QVERIFY( fd != -1 );
713         QVERIFY( f.open(fd, QIODevice::ReadOnly) );
714         QCOMPARE( f.size(), size );
715 
716         f.close();
717         QT_CLOSE(fd);
718     }
719 }
720 
sizeNoExist()721 void tst_QFile::sizeNoExist()
722 {
723     QFile file("nonexist01");
724     QVERIFY( !file.exists() );
725     QCOMPARE( file.size(), (qint64)0 );
726     QVERIFY( !file.open(QIODevice::ReadOnly) );
727 }
728 
seek()729 void tst_QFile::seek()
730 {
731     QFile::remove("newfile.txt");
732     QFile file("newfile.txt");
733     file.open(QIODevice::WriteOnly);
734     QCOMPARE(file.size(), qint64(0));
735     QCOMPARE(file.pos(), qint64(0));
736     QVERIFY(file.seek(10));
737     QCOMPARE(file.pos(), qint64(10));
738     QCOMPARE(file.size(), qint64(0));
739     file.close();
740     QFile::remove("newfile.txt");
741 }
742 
setSize()743 void tst_QFile::setSize()
744 {
745     DEPENDS_ON( "size" );
746 
747     if ( QFile::exists( "createme.txt" ) )
748         QFile::remove( "createme.txt" );
749     QVERIFY( !QFile::exists( "createme.txt" ) );
750 
751     QFile f("createme.txt");
752     QVERIFY(f.open(QIODevice::Truncate | QIODevice::ReadWrite));
753     f.putChar('a');
754 
755     f.seek(0);
756     char c = '\0';
757     f.getChar(&c);
758     QCOMPARE(c, 'a');
759 
760     QCOMPARE(f.size(), (qlonglong)1);
761 	bool ok = f.resize(99);
762     QVERIFY(ok);
763     QCOMPARE(f.size(), (qlonglong)99);
764 
765     f.seek(0);
766     c = '\0';
767     f.getChar(&c);
768     QCOMPARE(c, 'a');
769 
770     QVERIFY(f.resize(1));
771     QCOMPARE(f.size(), (qlonglong)1);
772 
773     f.seek(0);
774     c = '\0';
775     f.getChar(&c);
776     QCOMPARE(c, 'a');
777 
778     f.close();
779 
780     QCOMPARE(f.size(), (qlonglong)1);
781     QVERIFY(f.resize(100));
782     QCOMPARE(f.size(), (qlonglong)100);
783     QVERIFY(f.resize(50));
784     QCOMPARE(f.size(), (qlonglong)50);
785 }
786 
setSizeSeek()787 void tst_QFile::setSizeSeek()
788 {
789     QFile::remove("setsizeseek.txt");
790     QFile f("setsizeseek.txt");
791     QVERIFY(f.open(QFile::WriteOnly));
792     f.write("ABCD");
793 
794     QCOMPARE(f.pos(), qint64(4));
795     f.resize(2);
796     QCOMPARE(f.pos(), qint64(2));
797     f.resize(4);
798     QCOMPARE(f.pos(), qint64(2));
799     f.resize(0);
800     QCOMPARE(f.pos(), qint64(0));
801     f.resize(4);
802     QCOMPARE(f.pos(), qint64(0));
803 
804     f.seek(3);
805     QCOMPARE(f.pos(), qint64(3));
806     f.resize(2);
807     QCOMPARE(f.pos(), qint64(2));
808 }
809 
seekToSamePosition()810 void tst_QFile::seekToSamePosition()
811 {
812     QFile in(SRCDIR "testfile.txt");
813     QFile out("seekToSamePosition.txt");
814     QVERIFY(in.open(QFile::ReadOnly));
815     QVERIFY(out.open(QFile::WriteOnly));
816     QByteArray plusses;
817     plusses.fill('+', 58);
818 
819     qint64 cursor = 0;
820     QVERIFY(in.seek(cursor));
821     QVERIFY(out.seek(cursor));
822 
823     QVERIFY(out.write(plusses));
824 
825     cursor += 58;
826     QVERIFY(in.seek(cursor));
827     QVERIFY(out.seek(cursor));
828 
829     QByteArray copy = in.read(60);
830     QVERIFY(out.write(copy));
831 
832     cursor += 60;
833     QVERIFY(in.seek(cursor));
834     QVERIFY(out.seek(cursor));
835 
836     QVERIFY(out.write(plusses));
837 
838     cursor += 58;
839     QVERIFY(in.seek(cursor));
840     QVERIFY(out.seek(cursor));
841 
842     copy = in.readAll();
843     QVERIFY(out.write(copy));
844 
845     //compare
846     out.close();
847     QVERIFY(out.open(QFile::ReadOnly));
848     QVERIFY(in.seek(0));
849 
850     QByteArray clean = in.readAll();
851     QByteArray dirty = out.readAll();
852     out.close();
853 
854     QVERIFY(clean.size() == dirty.size());
855     for (int i=0;i<clean.size();i++) {
856         if (clean[i] == '-')
857             QVERIFY2(dirty[i] == '+', qPrintable(QString("no + at pos %1").arg(i)));
858         else
859             QVERIFY2(dirty[i] == clean[i], qPrintable(QString("char at pos %1 mismatched, %2 vs %3").arg(i).arg(clean[i]).arg(dirty[i])));
860     }
861 }
862 
atEnd()863 void tst_QFile::atEnd()
864 {
865     QFile f( SRCDIR "testfile.txt" );
866     QVERIFY(f.open( QIODevice::ReadOnly ));
867 
868     int size = f.size();
869     f.seek( size );
870 
871     bool end = f.atEnd();
872     f.close();
873     QCOMPARE( end, (bool)TRUE );
874 }
875 
readLine()876 void tst_QFile::readLine()
877 {
878     QFile f( SRCDIR "testfile.txt" );
879     QVERIFY(f.open( QIODevice::ReadOnly ));
880 
881     int i = 0;
882     char p[128];
883     int foo;
884     while ( (foo=f.readLine( p, 128 )) > 0 ) {
885         ++i;
886         if ( i == 5 ) {
887             QCOMPARE( p[0], 'T' );
888             QCOMPARE( p[3], 's' );
889             QCOMPARE( p[11], 'i' );
890         }
891     }
892     f.close();
893     QCOMPARE( i, 6 );
894 }
895 
readLine2()896 void tst_QFile::readLine2()
897 {
898     QFile f( SRCDIR "testfile.txt" );
899     f.open( QIODevice::ReadOnly );
900 
901     char p[128];
902     QCOMPARE(f.readLine(p, 60), qlonglong(59));
903     QCOMPARE(f.readLine(p, 60), qlonglong(59));
904     memset(p, '@', sizeof(p));
905     QCOMPARE(f.readLine(p, 60), qlonglong(59));
906 
907     QCOMPARE(p[57], '-');
908     QCOMPARE(p[58], '\n');
909     QCOMPARE(p[59], '\0');
910     QCOMPARE(p[60], '@');
911 }
912 
readLineNullInLine()913 void tst_QFile::readLineNullInLine()
914 {
915     QFile::remove("nullinline.txt");
916     QFile file("nullinline.txt");
917     QVERIFY(file.open(QIODevice::ReadWrite));
918     QVERIFY(file.write("linewith\0null\nanotherline\0withnull\n\0\nnull\0", 42) > 0);
919     QVERIFY(file.flush());
920     file.reset();
921 
922     QCOMPARE(file.readLine(), QByteArray("linewith\0null\n", 14));
923     QCOMPARE(file.readLine(), QByteArray("anotherline\0withnull\n", 21));
924     QCOMPARE(file.readLine(), QByteArray("\0\n", 2));
925     QCOMPARE(file.readLine(), QByteArray("null\0", 5));
926     QCOMPARE(file.readLine(), QByteArray());
927 }
928 
readAll_data()929 void tst_QFile::readAll_data()
930 {
931     QTest::addColumn<bool>("textMode");
932     QTest::addColumn<QString>("fileName");
933     QTest::newRow( "TextMode unixfile" ) <<  true << SRCDIR "testfile.txt";
934     QTest::newRow( "BinaryMode unixfile" ) <<  false << SRCDIR "testfile.txt";
935     QTest::newRow( "TextMode dosfile" ) <<  true << SRCDIR "dosfile.txt";
936     QTest::newRow( "BinaryMode dosfile" ) <<  false << SRCDIR "dosfile.txt";
937     QTest::newRow( "TextMode bigfile" ) <<  true << SRCDIR "tst_qfile.cpp";
938     QTest::newRow( "BinaryMode  bigfile" ) <<  false << SRCDIR "tst_qfile.cpp";
939     QVERIFY(QFile(SRCDIR "tst_qfile.cpp").size() > 64*1024);
940 }
941 
readAll()942 void tst_QFile::readAll()
943 {
944     QFETCH( bool, textMode );
945     QFETCH( QString, fileName );
946 
947     QFile file(fileName);
948     if (textMode)
949         QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
950     else
951         QVERIFY(file.open(QFile::ReadOnly));
952 
953     QByteArray a = file.readAll();
954     file.reset();
955     QVERIFY(file.pos() == 0);
956 
957     QVERIFY(file.bytesAvailable() > 7);
958     QByteArray b = file.read(1);
959     char x;
960     file.getChar(&x);
961     b.append(x);
962     b.append(file.read(5));
963     b.append(file.readAll());
964 
965     QCOMPARE(a, b);
966 }
967 
readAllBuffer()968 void tst_QFile::readAllBuffer()
969 {
970     QString fileName = QLatin1String("readAllBuffer.txt");
971 
972     QFile::remove(fileName);
973 
974     QFile writer(fileName);
975     QFile reader(fileName);
976 
977     QByteArray data1("This is arguably a very simple text.");
978     QByteArray data2("This is surely not as simple a test.");
979 
980     QVERIFY( writer.open(QIODevice::ReadWrite | QIODevice::Unbuffered) );
981     QVERIFY( reader.open(QIODevice::ReadOnly) );
982 
983     QCOMPARE( writer.write(data1), qint64(data1.size()) );
984     QVERIFY( writer.seek(0) );
985 
986     QByteArray result;
987     result = reader.read(18);
988     QCOMPARE( result.size(), 18 );
989 
990     QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, old version buffered in reader
991     QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, unbuffered in reader
992 
993     result += reader.readAll();
994 
995     QCOMPARE( result, data1 + data2 );
996 
997     QFile::remove(fileName);
998 }
999 
readAllStdin()1000 void tst_QFile::readAllStdin()
1001 {
1002 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
1003     QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll);
1004 #endif
1005 #if defined(QT_NO_PROCESS)
1006     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
1007 #else
1008     QByteArray lotsOfData(1024, '@'); // 10 megs
1009 
1010     QProcess process;
1011     process.start(m_stdinProcess + QLatin1String(" all"));
1012     QVERIFY( process.waitForStarted() );
1013     for (int i = 0; i < 5; ++i) {
1014         QTest::qWait(1000);
1015         process.write(lotsOfData);
1016         while (process.bytesToWrite() > 0) {
1017             QVERIFY(process.waitForBytesWritten());
1018         }
1019     }
1020 
1021     process.closeWriteChannel();
1022     process.waitForFinished();
1023     QCOMPARE(process.readAll().size(), lotsOfData.size() * 5);
1024 #endif
1025 }
1026 
readLineStdin()1027 void tst_QFile::readLineStdin()
1028 {
1029 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
1030     QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll);
1031 #endif
1032 #if defined(QT_NO_PROCESS)
1033     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
1034 #else
1035 
1036     QByteArray lotsOfData(1024, '@'); // 10 megs
1037     for (int i = 0; i < lotsOfData.size(); ++i) {
1038         if ((i % 32) == 31)
1039             lotsOfData[i] = '\n';
1040         else
1041             lotsOfData[i] = char('0' + i % 32);
1042     }
1043 
1044     for (int i = 0; i < 2; ++i) {
1045         QProcess process;
1046         process.start(m_stdinProcess + QString::fromLatin1(" line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite);
1047         for (int i = 0; i < 5; ++i) {
1048             QTest::qWait(1000);
1049             process.write(lotsOfData);
1050             while (process.bytesToWrite() > 0) {
1051                 QVERIFY(process.waitForBytesWritten());
1052             }
1053         }
1054 
1055         process.closeWriteChannel();
1056         QVERIFY(process.waitForFinished(5000));
1057 
1058         QByteArray array = process.readAll();
1059         QCOMPARE(array.size(), lotsOfData.size() * 5);
1060         for (int i = 0; i < array.size(); ++i) {
1061             if ((i % 32) == 31)
1062                 QCOMPARE(char(array[i]), '\n');
1063             else
1064                 QCOMPARE(char(array[i]), char('0' + i % 32));
1065         }
1066     }
1067 #endif
1068 }
1069 
readLineStdin_lineByLine()1070 void tst_QFile::readLineStdin_lineByLine()
1071 {
1072 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
1073     QSKIP("Currently no stdin/out supported for Windows CE", SkipAll);
1074 #endif
1075 #if defined(QT_NO_PROCESS)
1076     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
1077 #else
1078     for (int i = 0; i < 2; ++i) {
1079         QProcess process;
1080         process.start(m_stdinProcess + QString::fromLatin1(" line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite);
1081         QVERIFY(process.waitForStarted());
1082 
1083         for (int j = 0; j < 3; ++j) {
1084             QByteArray line = "line " + QByteArray::number(j) + "\n";
1085             QCOMPARE(process.write(line), qint64(line.size()));
1086             QVERIFY(process.waitForBytesWritten(2000));
1087             if (process.bytesAvailable() == 0)
1088                 QVERIFY(process.waitForReadyRead(2000));
1089             QCOMPARE(process.readAll(), line);
1090         }
1091 
1092         process.closeWriteChannel();
1093         QVERIFY(process.waitForFinished(5000));
1094     }
1095 #endif
1096 }
1097 
text()1098 void tst_QFile::text()
1099 {
1100     // dosfile.txt is a binary CRLF file
1101     QFile file(SRCDIR "dosfile.txt");
1102     QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
1103     QCOMPARE(file.readLine(),
1104             QByteArray("/dev/system/root     /                    reiserfs   acl,user_xattr        1 1\n"));
1105     QCOMPARE(file.readLine(),
1106             QByteArray("/dev/sda1            /boot                ext3       acl,user_xattr        1 2\n"));
1107     file.ungetChar('\n');
1108     file.ungetChar('2');
1109     QCOMPARE(file.readLine().constData(), QByteArray("2\n").constData());
1110 }
1111 
missingEndOfLine()1112 void tst_QFile::missingEndOfLine()
1113 {
1114     QFile file(SRCDIR "noendofline.txt");
1115     QVERIFY(file.open(QFile::ReadOnly));
1116 
1117     int nlines = 0;
1118     while (!file.atEnd()) {
1119         ++nlines;
1120         file.readLine();
1121     }
1122 
1123     QCOMPARE(nlines, 3);
1124 }
1125 
readBlock()1126 void tst_QFile::readBlock()
1127 {
1128     QFile f( SRCDIR "testfile.txt" );
1129     f.open( QIODevice::ReadOnly );
1130 
1131     int length = 0;
1132     char p[256];
1133     length = f.read( p, 256 );
1134     f.close();
1135     QCOMPARE( length, 245 );
1136     QCOMPARE( p[59], 'D' );
1137     QCOMPARE( p[178], 'T' );
1138     QCOMPARE( p[199], 'l' );
1139 }
1140 
getch()1141 void tst_QFile::getch()
1142 {
1143     QFile f( SRCDIR "testfile.txt" );
1144     f.open( QIODevice::ReadOnly );
1145 
1146     char c;
1147     int i = 0;
1148     while (f.getChar(&c)) {
1149         QCOMPARE(f.pos(), qint64(i + 1));
1150         if ( i == 59 )
1151             QCOMPARE( c, 'D' );
1152         ++i;
1153     }
1154     f.close();
1155     QCOMPARE( i, 245 );
1156 }
1157 
ungetChar()1158 void tst_QFile::ungetChar()
1159 {
1160     QFile f(SRCDIR "testfile.txt");
1161     QVERIFY(f.open(QIODevice::ReadOnly));
1162 
1163     QByteArray array = f.readLine();
1164     QCOMPARE(array.constData(), "----------------------------------------------------------\n");
1165     f.ungetChar('\n');
1166 
1167     array = f.readLine();
1168     QCOMPARE(array.constData(), "\n");
1169 
1170     f.ungetChar('\n');
1171     f.ungetChar('-');
1172     f.ungetChar('-');
1173 
1174     array = f.readLine();
1175     QCOMPARE(array.constData(), "--\n");
1176 
1177     QFile::remove("genfile.txt");
1178     QFile out("genfile.txt");
1179     QVERIFY(out.open(QIODevice::ReadWrite));
1180     out.write("123");
1181     out.seek(0);
1182     QCOMPARE(out.readAll().constData(), "123");
1183     out.ungetChar('3');
1184     out.write("4");
1185     out.seek(0);
1186     QCOMPARE(out.readAll().constData(), "124");
1187     out.ungetChar('4');
1188     out.ungetChar('2');
1189     out.ungetChar('1');
1190     char buf[3];
1191     QCOMPARE(out.read(buf, sizeof(buf)), qint64(3));
1192     QCOMPARE(buf[0], '1');
1193     QCOMPARE(buf[1], '2');
1194     QCOMPARE(buf[2], '4');
1195 }
1196 
invalidFile_data()1197 void tst_QFile::invalidFile_data()
1198 {
1199     QTest::addColumn<QString>("fileName");
1200 #if !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN)
1201     QTest::newRow( "x11" ) << QString( "qwe//" );
1202 #else
1203     QTest::newRow( "colon1" ) << QString( "fail:invalid" );
1204     QTest::newRow( "colon2" ) << QString( "f:ail:invalid" );
1205     QTest::newRow( "colon3" ) << QString( ":failinvalid" );
1206     QTest::newRow( "forwardslash" ) << QString( "fail/invalid" );
1207     QTest::newRow( "asterisk" ) << QString( "fail*invalid" );
1208     QTest::newRow( "questionmark" ) << QString( "fail?invalid" );
1209     QTest::newRow( "quote" ) << QString( "fail\"invalid" );
1210     QTest::newRow( "lt" ) << QString( "fail<invalid" );
1211     QTest::newRow( "gt" ) << QString( "fail>invalid" );
1212     QTest::newRow( "pipe" ) << QString( "fail|invalid" );
1213 #endif
1214 }
1215 
invalidFile()1216 void tst_QFile::invalidFile()
1217 {
1218     QFETCH( QString, fileName );
1219     QFile f( fileName );
1220     QVERIFY( !f.open( QIODevice::ReadWrite ) );
1221 }
1222 
createFile()1223 void tst_QFile::createFile()
1224 {
1225     if ( QFile::exists( "createme.txt" ) )
1226         QFile::remove( "createme.txt" );
1227     QVERIFY( !QFile::exists( "createme.txt" ) );
1228 
1229     QFile f( "createme.txt" );
1230     QVERIFY( f.open( QIODevice::WriteOnly ) );
1231     f.close();
1232     QVERIFY( QFile::exists( "createme.txt" ) );
1233 }
1234 
append()1235 void tst_QFile::append()
1236 {
1237     const QString name("appendme.txt");
1238     if (QFile::exists(name))
1239         QFile::remove(name);
1240     QVERIFY(!QFile::exists(name));
1241 
1242     QFile f(name);
1243     QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
1244     f.putChar('a');
1245     f.close();
1246 
1247     QVERIFY(f.open(QIODevice::Append));
1248     QVERIFY(f.pos() == 1);
1249     f.putChar('a');
1250     f.close();
1251     QCOMPARE(int(f.size()), 2);
1252 }
1253 
permissions_data()1254 void tst_QFile::permissions_data()
1255 {
1256     QTest::addColumn<QString>("file");
1257     QTest::addColumn<uint>("perms");
1258     QTest::addColumn<bool>("expected");
1259 
1260     QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << uint(QFile::ExeUser) << true;
1261     QTest::newRow("data1") << SRCDIR "tst_qfile.cpp" << uint(QFile::ReadUser) << true;
1262 //    QTest::newRow("data2") << "tst_qfile.cpp" << int(QFile::WriteUser) << false;
1263     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ReadUser) << true;
1264     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::WriteUser) << false;
1265     QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ExeUser) << false;
1266 }
1267 
permissions()1268 void tst_QFile::permissions()
1269 {
1270 #if defined(Q_OS_SYMBIAN)
1271     if (qstrcmp(QTest::currentDataTag(), "data0") == 0)
1272         QSKIP("Symbian does not have execution permissions", SkipSingle);
1273 #endif
1274     QFETCH(QString, file);
1275     QFETCH(uint, perms);
1276     QFETCH(bool, expected);
1277     QFile f(file);
1278     QCOMPARE(((f.permissions() & perms) == QFile::Permissions(perms)), expected);
1279     QCOMPARE(((QFile::permissions(file) & perms) == QFile::Permissions(perms)), expected);
1280 }
1281 
setPermissions()1282 void tst_QFile::setPermissions()
1283 {
1284     DEPENDS_ON( "permissions" ); //if that doesn't work...
1285 
1286     if ( QFile::exists( "createme.txt" ) )
1287         QFile::remove( "createme.txt" );
1288     QVERIFY( !QFile::exists( "createme.txt" ) );
1289 
1290     QFile f("createme.txt");
1291     QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
1292     f.putChar('a');
1293     f.close();
1294 
1295     QFile::Permissions perms(QFile::WriteUser | QFile::ReadUser);
1296     QVERIFY(f.setPermissions(perms));
1297     QVERIFY((f.permissions() & perms) == perms);
1298 
1299 }
1300 
copy()1301 void tst_QFile::copy()
1302 {
1303     QFile::setPermissions("tst_qfile_copy.cpp", QFile::WriteUser);
1304     QFile::remove("tst_qfile_copy.cpp");
1305     QFile::remove("test2");
1306     QVERIFY(QFile::copy(SRCDIR "tst_qfile.cpp", "tst_qfile_copy.cpp"));
1307     QFile in1(SRCDIR "tst_qfile.cpp"), in2("tst_qfile_copy.cpp");
1308     QVERIFY(in1.open(QFile::ReadOnly));
1309     QVERIFY(in2.open(QFile::ReadOnly));
1310     QByteArray data1 = in1.readAll(), data2 = in2.readAll();
1311     QCOMPARE(data1, data2);
1312     QFile::remove( "main_copy.cpp" );
1313 
1314     QFile::copy(QDir::currentPath(), QDir::currentPath() + QLatin1String("/test2"));
1315 }
1316 
copyAfterFail()1317 void tst_QFile::copyAfterFail()
1318 {
1319     QFile file1("file-to-be-copied.txt");
1320     QFile file2("existing-file.txt");
1321 
1322     QVERIFY(file1.open(QIODevice::ReadWrite) && "(test-precondition)");
1323     QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
1324     file2.close();
1325     QVERIFY(!QFile::exists("copied-file-1.txt") && "(test-precondition)");
1326     QVERIFY(!QFile::exists("copied-file-2.txt") && "(test-precondition)");
1327 
1328     QVERIFY(!file1.copy("existing-file.txt"));
1329     QCOMPARE(file1.error(), QFile::CopyError);
1330 
1331     QVERIFY(file1.copy("copied-file-1.txt"));
1332     QVERIFY(!file1.isOpen());
1333     QCOMPARE(file1.error(), QFile::NoError);
1334 
1335     QVERIFY(!file1.copy("existing-file.txt"));
1336     QCOMPARE(file1.error(), QFile::CopyError);
1337 
1338     QVERIFY(file1.copy("copied-file-2.txt"));
1339     QVERIFY(!file1.isOpen());
1340     QCOMPARE(file1.error(), QFile::NoError);
1341 
1342     QVERIFY(QFile::exists("copied-file-1.txt"));
1343     QVERIFY(QFile::exists("copied-file-2.txt"));
1344 
1345     QVERIFY(QFile::remove("file-to-be-copied.txt") && "(test-cleanup)");
1346     QVERIFY(QFile::remove("existing-file.txt") && "(test-cleanup)");
1347     QVERIFY(QFile::remove("copied-file-1.txt") && "(test-cleanup)");
1348     QVERIFY(QFile::remove("copied-file-2.txt") && "(test-cleanup)");
1349 }
1350 
copyRemovesTemporaryFile() const1351 void tst_QFile::copyRemovesTemporaryFile() const
1352 {
1353     const QString newName(QLatin1String("copyRemovesTemporaryFile"));
1354     QVERIFY(QFile::copy(SRCDIR "forCopying.txt", newName));
1355 
1356     QVERIFY(!QFile::exists(QLatin1String( SRCDIR "qt_temp.XXXXXX")));
1357     QVERIFY(QFile::remove(newName));
1358 }
1359 
copyShouldntOverwrite()1360 void tst_QFile::copyShouldntOverwrite()
1361 {
1362     // Copy should not overwrite existing files.
1363     QFile::remove("tst_qfile.cpy");
1364     QFile file(SRCDIR "tst_qfile.cpp");
1365     QVERIFY(file.copy("tst_qfile.cpy"));
1366 #if defined(Q_OS_SYMBIAN)
1367 	bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteUser);
1368 #else
1369 	bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteOther);
1370 #endif
1371     QVERIFY(ok);
1372     QVERIFY(!file.copy("tst_qfile.cpy"));
1373     QFile::remove("tst_qfile.cpy");
1374 }
1375 
copyFallback()1376 void tst_QFile::copyFallback()
1377 {
1378     // Using a resource file to trigger QFile::copy's fallback handling
1379     QFile file(":/copy-fallback.qrc");
1380     QFile::remove("file-copy-destination.txt");
1381 
1382     QVERIFY2(file.exists(), "test precondition");
1383     QVERIFY2(!QFile::exists("file-copy-destination.txt"), "test precondition");
1384 
1385     // Fallback copy of closed file.
1386     QVERIFY(file.copy("file-copy-destination.txt"));
1387     QVERIFY(QFile::exists("file-copy-destination.txt"));
1388     QVERIFY(!file.isOpen());
1389 
1390 #ifdef Q_WS_WINCE
1391     // Need to reset permissions on Windows to be able to delete
1392     QVERIFY(QFile::setPermissions("file-copy-destination.txt",
1393             QFile::WriteOther));
1394 #else
1395      // Need to reset permissions on Windows to be able to delete
1396     QVERIFY(QFile::setPermissions("file-copy-destination.txt",
1397            QFile::ReadOwner | QFile::WriteOwner));
1398 #endif
1399     QVERIFY(QFile::remove("file-copy-destination.txt"));
1400 
1401     // Fallback copy of open file.
1402     QVERIFY(file.open(QIODevice::ReadOnly));
1403     QVERIFY(file.copy("file-copy-destination.txt"));
1404     QVERIFY(QFile::exists("file-copy-destination.txt"));
1405     QVERIFY(!file.isOpen());
1406 
1407     file.close();
1408     QFile::remove("file-copy-destination.txt");
1409 }
1410 
1411 #ifdef Q_OS_WIN
1412 #include <objbase.h>
1413 #include <shlobj.h>
1414 #endif
1415 
1416 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
getWorkingDirectoryForLink(const QString & linkFileName)1417 static QString getWorkingDirectoryForLink(const QString &linkFileName)
1418 {
1419     bool neededCoInit = false;
1420     QString ret;
1421 
1422     IShellLink *psl;
1423     HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
1424     if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
1425         neededCoInit = true;
1426         CoInitialize(NULL);
1427         hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
1428     }
1429 
1430     if (SUCCEEDED(hres)) {    // Get pointer to the IPersistFile interface.
1431         IPersistFile *ppf;
1432         hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
1433         if (SUCCEEDED(hres))  {
1434             hres = ppf->Load((LPOLESTR)linkFileName.utf16(), STGM_READ);
1435             //The original path of the link is retrieved. If the file/folder
1436             //was moved, the return value still have the old path.
1437             if(SUCCEEDED(hres)) {
1438                 wchar_t szGotPath[MAX_PATH];
1439                 if (psl->GetWorkingDirectory(szGotPath, MAX_PATH) == NOERROR)
1440                     ret = QString::fromWCharArray(szGotPath);
1441             }
1442             ppf->Release();
1443         }
1444         psl->Release();
1445     }
1446 
1447     if (neededCoInit) {
1448         CoUninitialize();
1449     }
1450 
1451     return ret;
1452 }
1453 #endif
1454 
link()1455 void tst_QFile::link()
1456 {
1457 #if defined(Q_OS_SYMBIAN)
1458     QSKIP("Symbian does not support links", SkipAll);
1459 #endif
1460     QFile::remove("myLink.lnk");
1461 
1462     QFileInfo info1(SRCDIR "tst_qfile.cpp");
1463     QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath());
1464 
1465     QVERIFY(QFile::link(SRCDIR "tst_qfile.cpp", "myLink.lnk"));
1466 
1467     QFileInfo info2("myLink.lnk");
1468     QVERIFY(info2.isSymLink());
1469     QCOMPARE(info2.symLinkTarget(), referenceTarget);
1470 
1471     QFile link("myLink.lnk");
1472     QVERIFY(link.open(QIODevice::ReadOnly));
1473     QCOMPARE(link.symLinkTarget(), referenceTarget);
1474     link.close();
1475 
1476     QCOMPARE(QFile::symLinkTarget("myLink.lnk"), referenceTarget);
1477 
1478 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1479     QString wd = getWorkingDirectoryForLink(info2.absoluteFilePath());
1480     QCOMPARE(QDir::fromNativeSeparators(wd), QDir::cleanPath(info1.absolutePath()));
1481 #endif
1482 
1483     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1484 }
1485 
linkToDir()1486 void tst_QFile::linkToDir()
1487 {
1488 #if defined(Q_OS_SYMBIAN)
1489     QSKIP("Symbian does not support linking to directories", SkipAll);
1490 #endif
1491     QFile::remove("myLinkToDir.lnk");
1492     QDir dir;
1493     dir.mkdir("myDir");
1494     QFileInfo info1("myDir");
1495     QVERIFY(QFile::link("myDir", "myLinkToDir.lnk"));
1496     QFileInfo info2("myLinkToDir.lnk");
1497 #if !(defined Q_OS_HPUX && defined(__ia64))
1498     // absurd HP-UX filesystem bug on gravlaks - checking if a symlink
1499     // resolves or not alters the file system to make the broken symlink
1500     // later fail...
1501     QVERIFY(info2.isSymLink());
1502 #endif
1503     QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
1504     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1505     QFile::remove("myLinkToDir.lnk");
1506     dir.rmdir("myDir");
1507 }
1508 
absolutePathLinkToRelativePath()1509 void tst_QFile::absolutePathLinkToRelativePath()
1510 {
1511 #if defined(Q_OS_SYMBIAN)
1512     QSKIP("Symbian does not support links", SkipAll);
1513 #endif
1514     QFile::remove("myDir/test.txt");
1515     QFile::remove("myDir/myLink.lnk");
1516     QDir dir;
1517     dir.mkdir("myDir");
1518     QFile("myDir/test.txt").open(QFile::WriteOnly);
1519 
1520 #ifdef Q_OS_WIN
1521     QVERIFY(QFile::link("test.txt", "myDir/myLink.lnk"));
1522 #else
1523     QVERIFY(QFile::link("myDir/test.txt", "myDir/myLink.lnk"));
1524 #endif
1525     QEXPECT_FAIL("", "Symlinking using relative paths is currently different on Windows and Unix/Symbian", Continue);
1526     QCOMPARE(QFileInfo(QFile(QFileInfo("myDir/myLink.lnk").absoluteFilePath()).symLinkTarget()).absoluteFilePath(),
1527              QFileInfo("myDir/test.txt").absoluteFilePath());
1528 
1529     QFile::remove("myDir/test.txt");
1530     QFile::remove("myDir/myLink.lnk");
1531     dir.rmdir("myDir");
1532 }
1533 
readBrokenLink()1534 void tst_QFile::readBrokenLink()
1535 {
1536 #if defined(Q_OS_SYMBIAN)
1537     QSKIP("Symbian does not support links", SkipAll);
1538 #endif
1539     QFile::remove("myLink2.lnk");
1540     QFileInfo info1("file12");
1541 #if defined(Q_OS_SYMBIAN)
1542     // In Symbian can't link to nonexisting file directly, so create the file temporarily
1543     QFile tempFile("file12");
1544     tempFile.open(QIODevice::WriteOnly);
1545     tempFile.link("myLink2.lnk");
1546     tempFile.remove();
1547 #else
1548     QVERIFY(QFile::link("file12", "myLink2.lnk"));
1549 #endif
1550     QFileInfo info2("myLink2.lnk");
1551     QVERIFY(info2.isSymLink());
1552     QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
1553     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1554 
1555 #if !defined(Q_OS_SYMBIAN)
1556     QVERIFY(QFile::link("ole/..", "myLink2.lnk"));
1557     QCOMPARE(QFileInfo("myLink2.lnk").symLinkTarget(), QDir::currentPath());
1558 #endif
1559 }
1560 
readTextFile_data()1561 void tst_QFile::readTextFile_data()
1562 {
1563     QTest::addColumn<QByteArray>("in");
1564     QTest::addColumn<QByteArray>("out");
1565 
1566     QTest::newRow("empty") << QByteArray() << QByteArray();
1567     QTest::newRow("a") << QByteArray("a") << QByteArray("a");
1568     QTest::newRow("a\\rb") << QByteArray("a\rb") << QByteArray("ab");
1569     QTest::newRow("\\n") << QByteArray("\n") << QByteArray("\n");
1570     QTest::newRow("\\r\\n") << QByteArray("\r\n") << QByteArray("\n");
1571     QTest::newRow("\\r") << QByteArray("\r") << QByteArray();
1572     QTest::newRow("twolines") << QByteArray("Hello\r\nWorld\r\n") << QByteArray("Hello\nWorld\n");
1573     QTest::newRow("twolines no endline") << QByteArray("Hello\r\nWorld") << QByteArray("Hello\nWorld");
1574 }
1575 
readTextFile()1576 void tst_QFile::readTextFile()
1577 {
1578     QFETCH(QByteArray, in);
1579     QFETCH(QByteArray, out);
1580 
1581     QFile winfile("winfile.txt");
1582     QVERIFY(winfile.open(QFile::WriteOnly | QFile::Truncate));
1583     winfile.write(in);
1584     winfile.close();
1585 
1586     QVERIFY(winfile.open(QFile::ReadOnly));
1587     QCOMPARE(winfile.readAll(), in);
1588     winfile.close();
1589 
1590     QVERIFY(winfile.open(QFile::ReadOnly | QFile::Text));
1591     QCOMPARE(winfile.readAll(), out);
1592 }
1593 
readTextFile2()1594 void tst_QFile::readTextFile2()
1595 {
1596     {
1597         QFile file(SRCDIR "testlog.txt");
1598         QVERIFY(file.open(QIODevice::ReadOnly));
1599         file.read(4097);
1600     }
1601 
1602     {
1603         QFile file(SRCDIR "testlog.txt");
1604         QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
1605         file.read(4097);
1606     }
1607 }
1608 
writeTextFile_data()1609 void tst_QFile::writeTextFile_data()
1610 {
1611     QTest::addColumn<QByteArray>("in");
1612 
1613     QTest::newRow("empty") << QByteArray();
1614     QTest::newRow("a") << QByteArray("a");
1615     QTest::newRow("a\\rb") << QByteArray("a\rb");
1616     QTest::newRow("\\n") << QByteArray("\n");
1617     QTest::newRow("\\r\\n") << QByteArray("\r\n");
1618     QTest::newRow("\\r") << QByteArray("\r");
1619     QTest::newRow("twolines crlf") << QByteArray("Hello\r\nWorld\r\n");
1620     QTest::newRow("twolines crlf no endline") << QByteArray("Hello\r\nWorld");
1621     QTest::newRow("twolines lf") << QByteArray("Hello\nWorld\n");
1622     QTest::newRow("twolines lf no endline") << QByteArray("Hello\nWorld");
1623     QTest::newRow("mixed") << QByteArray("this\nis\r\na\nmixed\r\nfile\n");
1624 }
1625 
writeTextFile()1626 void tst_QFile::writeTextFile()
1627 {
1628     QFETCH(QByteArray, in);
1629 
1630     QFile file("textfile.txt");
1631     QVERIFY(file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text));
1632     QByteArray out = in;
1633 #ifdef Q_OS_WIN
1634     out.replace('\n', "\r\n");
1635 #endif
1636     QCOMPARE(file.write(in), qlonglong(in.size()));
1637     file.close();
1638 
1639     file.open(QFile::ReadOnly);
1640     QCOMPARE(file.readAll(), out);
1641 }
1642 
1643 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
largeUncFileSupport()1644 void tst_QFile::largeUncFileSupport()
1645 {
1646     qint64 size = Q_INT64_C(8589934592);
1647     qint64 dataOffset = Q_INT64_C(8589914592);
1648     QByteArray knownData("LargeFile content at offset 8589914592");
1649     QString largeFile("//" + QtNetworkSettings::winServerName() + "/testsharelargefile/file.bin");
1650 
1651     {
1652         // 1) Native file handling.
1653         QFile file(largeFile);
1654         QCOMPARE(file.size(), size);
1655         QVERIFY(file.open(QIODevice::ReadOnly));
1656         QCOMPARE(file.size(), size);
1657         QVERIFY(file.seek(dataOffset));
1658         QCOMPARE(file.read(knownData.size()), knownData);
1659     }
1660     {
1661         // 2) stdlib file handling.
1662 #if _MSC_VER <= 1310
1663         QSKIP("platform SDK for MSVC 2003 does not support large files", SkipAll);
1664 #endif
1665         QFile file;
1666         FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
1667         QVERIFY(file.open(fh, QIODevice::ReadOnly));
1668         QCOMPARE(file.size(), size);
1669         QVERIFY(file.seek(dataOffset));
1670         QCOMPARE(file.read(knownData.size()), knownData);
1671         fclose(fh);
1672     }
1673     {
1674         // 3) stdio file handling.
1675         QFile file;
1676         FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
1677         int fd = int(_fileno(fh));
1678         QVERIFY(file.open(fd, QIODevice::ReadOnly));
1679         QCOMPARE(file.size(), size);
1680         QVERIFY(file.seek(dataOffset));
1681         QCOMPARE(file.read(knownData.size()), knownData);
1682         fclose(fh);
1683     }
1684 }
1685 #endif
1686 
tailFile()1687 void tst_QFile::tailFile()
1688 {
1689     QSKIP("File change notifications are so far unsupported.", SkipAll);
1690 
1691     QFile file("tail.txt");
1692     QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
1693 
1694     QFile tailFile("tail.txt");
1695     QVERIFY(tailFile.open(QFile::ReadOnly));
1696     tailFile.seek(file.size());
1697 
1698     QSignalSpy readSignal(&tailFile, SIGNAL(readyRead()));
1699 
1700     file.write("", 1);
1701 
1702     QTestEventLoop::instance().enterLoop(5);
1703 
1704     QVERIFY(!QTestEventLoop::instance().timeout());
1705     QCOMPARE(readSignal.count(), 1);
1706 }
1707 
flush()1708 void tst_QFile::flush()
1709 {
1710 	QString fileName("stdfile.txt");
1711 
1712 	QFile::remove(fileName);
1713 
1714 	{
1715 		QFile file(fileName);
1716 		QVERIFY(file.open(QFile::WriteOnly));
1717 		QCOMPARE(file.write("abc", 3),qint64(3));
1718 	}
1719 
1720 	{
1721 		QFile file(fileName);
1722 		QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
1723         QCOMPARE(file.pos(), qlonglong(3));
1724         QCOMPARE(file.write("def", 3), qlonglong(3));
1725         QCOMPARE(file.pos(), qlonglong(6));
1726     }
1727 
1728     {
1729         QFile file("stdfile.txt");
1730         QVERIFY(file.open(QFile::ReadOnly));
1731         QCOMPARE(file.readAll(), QByteArray("abcdef"));
1732     }
1733 
1734 	QFile::remove(fileName);
1735 }
1736 
bufferedRead()1737 void tst_QFile::bufferedRead()
1738 {
1739     QFile::remove("stdfile.txt");
1740 
1741     QFile file("stdfile.txt");
1742     QVERIFY(file.open(QFile::WriteOnly));
1743     file.write("abcdef");
1744     file.close();
1745 
1746 #if defined(Q_OS_WINCE)
1747 	FILE *stdFile = fopen((QCoreApplication::applicationDirPath() + "/stdfile.txt").toAscii() , "r");
1748 #else
1749     FILE *stdFile = fopen("stdfile.txt", "r");
1750 #endif
1751     QVERIFY(stdFile);
1752     char c;
1753     QCOMPARE(int(fread(&c, 1, 1, stdFile)), 1);
1754     QCOMPARE(c, 'a');
1755     QCOMPARE(int(ftell(stdFile)), 1);
1756 
1757     {
1758         QFile file;
1759         QVERIFY(file.open(stdFile, QFile::ReadOnly));
1760         QCOMPARE(file.pos(), qlonglong(1));
1761         QCOMPARE(file.read(&c, 1), qlonglong(1));
1762         QCOMPARE(c, 'b');
1763         QCOMPARE(file.pos(), qlonglong(2));
1764     }
1765 
1766     fclose(stdFile);
1767 }
1768 
isSequential()1769 void tst_QFile::isSequential()
1770 {
1771 #if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN)
1772     QSKIP("Unix only test.", SkipAll);
1773 #endif
1774 
1775     QFile zero("/dev/null");
1776     QVERIFY(zero.open(QFile::ReadOnly));
1777     QVERIFY(zero.isSequential());
1778 }
1779 
encodeName()1780 void tst_QFile::encodeName()
1781 {
1782     QCOMPARE(QFile::encodeName(QString::null), QByteArray());
1783 }
1784 
truncate()1785 void tst_QFile::truncate()
1786 {
1787     for (int i = 0; i < 2; ++i) {
1788         QFile file("truncate.txt");
1789         QVERIFY(file.open(QFile::WriteOnly));
1790         file.write(QByteArray(200, '@'));
1791         file.close();
1792 
1793         QVERIFY(file.open((i ? QFile::WriteOnly : QFile::ReadWrite) | QFile::Truncate));
1794         file.write(QByteArray(100, '$'));
1795         file.close();
1796 
1797         QVERIFY(file.open(QFile::ReadOnly));
1798         QCOMPARE(file.readAll(), QByteArray(100, '$'));
1799     }
1800 }
1801 
seekToPos()1802 void tst_QFile::seekToPos()
1803 {
1804     {
1805         QFile file("seekToPos.txt");
1806         QVERIFY(file.open(QFile::WriteOnly));
1807         file.write("a\r\nb\r\nc\r\n");
1808         file.flush();
1809     }
1810 
1811     QFile file("seekToPos.txt");
1812     QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1813     file.seek(1);
1814     char c;
1815     QVERIFY(file.getChar(&c));
1816     QCOMPARE(c, '\n');
1817 
1818     QCOMPARE(file.pos(), qint64(3));
1819     file.seek(file.pos());
1820     QCOMPARE(file.pos(), qint64(3));
1821 
1822     file.seek(1);
1823     file.seek(file.pos());
1824     QCOMPARE(file.pos(), qint64(1));
1825 
1826 }
1827 
seekAfterEndOfFile()1828 void tst_QFile::seekAfterEndOfFile()
1829 {
1830     QLatin1String filename("seekAfterEof.dat");
1831     QFile::remove(filename);
1832     {
1833         QFile file(filename);
1834         QVERIFY(file.open(QFile::WriteOnly));
1835         file.write("abcd");
1836         QCOMPARE(file.size(), qint64(4));
1837         file.seek(8);
1838         file.write("ijkl");
1839         QCOMPARE(file.size(), qint64(12));
1840         file.seek(4);
1841         file.write("efgh");
1842         QCOMPARE(file.size(), qint64(12));
1843         file.seek(16);
1844         file.write("----");
1845         QCOMPARE(file.size(), qint64(20));
1846         file.flush();
1847     }
1848 
1849     QFile file(filename);
1850     QVERIFY(file.open(QFile::ReadOnly));
1851     QByteArray contents = file.readAll();
1852     QCOMPARE(contents.left(12), QByteArray("abcdefghijkl", 12));
1853     //bytes 12-15 are uninitialised so we don't care what they read as.
1854     QCOMPARE(contents.mid(16), QByteArray("----", 4));
1855     file.close();
1856     QFile::remove(filename);
1857 }
1858 
FILEReadWrite()1859 void tst_QFile::FILEReadWrite()
1860 {
1861     // Tests modifying a file. First creates it then reads in 4 bytes and then overwrites these
1862     // 4 bytes with new values. At the end check to see the file contains the new values.
1863 
1864     QFile::remove("FILEReadWrite.txt");
1865 
1866     // create test file
1867     {
1868         QFile f("FILEReadWrite.txt");
1869         QVERIFY(f.open(QFile::WriteOnly));
1870         QDataStream ds(&f);
1871         qint8 c = 0;
1872         ds << c;
1873         c = 1;
1874         ds << c;
1875         c = 2;
1876         ds << c;
1877         c = 3;
1878         ds << c;
1879         c = 4;
1880         ds << c;
1881         c = 5;
1882         ds << c;
1883         c = 6;
1884         ds << c;
1885         c = 7;
1886         ds << c;
1887         c = 8;
1888         ds << c;
1889         c = 9;
1890         ds << c;
1891         c = 10;
1892         ds << c;
1893         c = 11;
1894         ds << c;
1895         f.close();
1896     }
1897 
1898 #ifdef Q_OS_WINCE
1899     FILE *fp = fopen(qPrintable(QCoreApplication::applicationDirPath() + "\\FILEReadWrite.txt"), "r+b");
1900 #else
1901     FILE *fp = fopen("FILEReadWrite.txt", "r+b");
1902 #endif
1903     QVERIFY(fp);
1904     QFile file;
1905     QVERIFY(file.open(fp, QFile::ReadWrite));
1906     QDataStream sfile(&file) ;
1907 
1908     qint8 var1,var2,var3,var4;
1909     while (!sfile.atEnd())
1910     {
1911         qint64 base = file.pos();
1912 
1913         QCOMPARE(file.pos(), base + 0);
1914         sfile >> var1;
1915         QCOMPARE(file.pos(), base + 1);
1916         file.flush(); // flushing should not change the base
1917         QCOMPARE(file.pos(), base + 1);
1918         sfile >> var2;
1919         QCOMPARE(file.pos(), base + 2);
1920         sfile >> var3;
1921         QCOMPARE(file.pos(), base + 3);
1922         sfile >> var4;
1923         QCOMPARE(file.pos(), base + 4);
1924         file.seek(file.pos() - 4) ;   // Move it back 4, for we are going to write new values based on old ones
1925         QCOMPARE(file.pos(), base + 0);
1926         sfile << qint8(var1 + 5);
1927         QCOMPARE(file.pos(), base + 1);
1928         sfile << qint8(var2 + 5);
1929         QCOMPARE(file.pos(), base + 2);
1930         sfile << qint8(var3 + 5);
1931         QCOMPARE(file.pos(), base + 3);
1932         sfile << qint8(var4 + 5);
1933         QCOMPARE(file.pos(), base + 4);
1934 
1935     }
1936     file.close();
1937     fclose(fp);
1938 
1939     // check modified file
1940     {
1941         QFile f("FILEReadWrite.txt");
1942         QVERIFY(f.open(QFile::ReadOnly));
1943         QDataStream ds(&f);
1944         qint8 c = 0;
1945         ds >> c;
1946         QCOMPARE(c, (qint8)5);
1947         ds >> c;
1948         QCOMPARE(c, (qint8)6);
1949         ds >> c;
1950         QCOMPARE(c, (qint8)7);
1951         ds >> c;
1952         QCOMPARE(c, (qint8)8);
1953         ds >> c;
1954         QCOMPARE(c, (qint8)9);
1955         ds >> c;
1956         QCOMPARE(c, (qint8)10);
1957         ds >> c;
1958         QCOMPARE(c, (qint8)11);
1959         ds >> c;
1960         QCOMPARE(c, (qint8)12);
1961         ds >> c;
1962         QCOMPARE(c, (qint8)13);
1963         ds >> c;
1964         QCOMPARE(c, (qint8)14);
1965         ds >> c;
1966         QCOMPARE(c, (qint8)15);
1967         ds >> c;
1968         QCOMPARE(c, (qint8)16);
1969         f.close();
1970     }
1971 
1972     QFile::remove("FILEReadWrite.txt");
1973 }
1974 
1975 
1976 /*
1977 #include <qglobal.h>
1978 #define BUFFSIZE 1
1979 #define FILESIZE   0x10000000f
1980 void tst_QFile::largeFileSupport()
1981 {
1982 #ifdef Q_OS_SOLARIS
1983     QSKIP("Solaris does not support statfs", SkipAll);
1984 #else
1985     qlonglong sizeNeeded = 2147483647;
1986     sizeNeeded *= 2;
1987     sizeNeeded += 1024;
1988     qlonglong freespace = qlonglong(0);
1989 #ifdef Q_WS_WIN
1990     _ULARGE_INTEGER free;
1991     if (::GetDiskFreeSpaceEx((wchar_t*)QDir::currentPath().utf16(), &free, 0, 0))
1992         freespace = free.QuadPart;
1993     if (freespace != 0) {
1994 #elif defined(Q_OS_IRIX)
1995     struct statfs info;
1996     if (statfs(QDir::currentPath().local8Bit(), &info, sizeof(struct statfs), 0) == 0) {
1997         freespace = qlonglong(info.f_bfree * info.f_bsize);
1998 #else
1999     struct statfs info;
2000     if (statfs(const_cast<char *>(QDir::currentPath().toLocal8Bit().constData()), &info) == 0) {
2001         freespace = qlonglong(info.f_bavail * info.f_bsize);
2002 #endif
2003         if (freespace > sizeNeeded) {
2004             QFile bigFile("bigfile");
2005             if (bigFile.open(QFile::ReadWrite)) {
2006                 char c[BUFFSIZE] = {'a'};
2007                 QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
2008                 qlonglong oldPos = bigFile.pos();
2009                 QVERIFY(bigFile.resize(sizeNeeded));
2010                 QCOMPARE(oldPos, bigFile.pos());
2011                 QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
2012                 QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
2013 
2014                 bigFile.close();
2015                 if (bigFile.open(QFile::ReadOnly)) {
2016                     QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
2017                     int i = 0;
2018                     for (i=0; i<BUFFSIZE; i++)
2019                         QCOMPARE(c[i], 'a');
2020                     QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
2021                     QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
2022                     for (i=0; i<BUFFSIZE; i++)
2023                         QCOMPARE(c[i], 'a');
2024                     bigFile.close();
2025                     QVERIFY(bigFile.remove());
2026                 } else {
2027                     QVERIFY(bigFile.remove());
2028                     QFAIL("Could not reopen file");
2029                 }
2030             } else {
2031                 QFAIL("Could not open file");
2032             }
2033         } else {
2034             QSKIP("Not enough space to run test", SkipSingle);
2035         }
2036     } else {
2037         QFAIL("Could not determin disk space");
2038     }
2039 #endif
2040 }
2041 */
2042 
i18nFileName_data()2043 void tst_QFile::i18nFileName_data()
2044 {
2045     QTest::addColumn<QString>("fileName");
2046 
2047     QTest::newRow( "01" ) << QString::fromUtf8("xxxxxxx.txt");
2048 }
2049 
i18nFileName()2050 void tst_QFile::i18nFileName()
2051 {
2052      QFETCH(QString, fileName);
2053      if (QFile::exists(fileName)) {
2054          QVERIFY(QFile::remove(fileName));
2055      }
2056      {
2057         QFile file(fileName);
2058         QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
2059         QTextStream ts(&file);
2060         ts.setCodec("UTF-8");
2061         ts << fileName << endl;
2062      }
2063      {
2064         QFile file(fileName);
2065         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
2066         QTextStream ts(&file);
2067         ts.setCodec("UTF-8");
2068         QString line = ts.readLine();
2069         QCOMPARE(line, fileName);
2070      }
2071      QVERIFY(QFile::remove(fileName));
2072 }
2073 
2074 
longFileName_data()2075 void tst_QFile::longFileName_data()
2076 {
2077     QTest::addColumn<QString>("fileName");
2078 
2079     QTest::newRow( "16 chars" ) << QString::fromLatin1("longFileName.txt");
2080     QTest::newRow( "52 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName.txt");
2081     QTest::newRow( "148 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
2082                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2083                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");
2084     QTest::newRow( "244 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
2085                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2086                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2087                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2088                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");
2089     QTest::newRow( "244 chars to absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
2090                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2091                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2092                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2093                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath();
2094   /* needs to be put on a windows 2000 > test machine
2095   QTest::newRow( "244 chars on UNC" ) <<  QString::fromLatin1("//arsia/D/troll/tmp/longFileNamelongFileNamelongFileNamelongFileName"
2096                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2097                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2098                                                      "longFileNamelongFileNamelongFileNamelongFileName"
2099                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");*/
2100 }
2101 
longFileName()2102 void tst_QFile::longFileName()
2103 {
2104     QFETCH(QString, fileName);
2105     if (QFile::exists(fileName)) {
2106         QVERIFY(QFile::remove(fileName));
2107     }
2108     {
2109         QFile file(fileName);
2110 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
2111         QEXPECT_FAIL("244 chars", "Full pathname must be less than 260 chars", Abort);
2112         QEXPECT_FAIL("244 chars to absolutepath", "Full pathname must be less than 260 chars", Abort);
2113 #endif
2114         QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
2115         QTextStream ts(&file);
2116         ts << fileName << endl;
2117     }
2118     {
2119         QFile file(fileName);
2120         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
2121         QTextStream ts(&file);
2122         QString line = ts.readLine();
2123         QCOMPARE(line, fileName);
2124     }
2125     QString newName = fileName + QLatin1String("1");
2126     {
2127         QVERIFY(QFile::copy(fileName, newName));
2128         QFile file(newName);
2129         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
2130         QTextStream ts(&file);
2131         QString line = ts.readLine();
2132         QCOMPARE(line, fileName);
2133 
2134     }
2135     QVERIFY(QFile::remove(newName));
2136     {
2137         QVERIFY(QFile::rename(fileName, newName));
2138         QFile file(newName);
2139         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
2140         QTextStream ts(&file);
2141         QString line = ts.readLine();
2142         QCOMPARE(line, fileName);
2143     }
2144     QVERIFY(QFile::exists(newName));
2145     QVERIFY(QFile::remove(newName));
2146 }
2147 
2148 class MyEngine : public QAbstractFileEngine
2149 {
2150 public:
MyEngine(int n)2151     MyEngine(int n) { number = n; }
~MyEngine()2152     virtual ~MyEngine() {}
2153 
setFileName(const QString &)2154     void setFileName(const QString &) {}
open(int)2155     bool open(int ) { return false; }
close()2156     bool close() { return false; }
flush()2157     bool flush() { return false; }
size() const2158     qint64 size() const { return 123 + number; }
at() const2159     qint64 at() const { return -1; }
seek(qint64)2160     bool seek(qint64) { return false; }
isSequential() const2161     bool isSequential() const { return false; }
read(char *,qint64)2162     qint64 read(char *, qint64) { return -1; }
write(const char *,qint64)2163     qint64 write(const char *, qint64) { return -1; }
remove()2164     bool remove() { return false; }
copy(const QString &)2165     bool copy(const QString &) { return false; }
rename(const QString &)2166     bool rename(const QString &) { return false; }
link(const QString &)2167     bool link(const QString &) { return false; }
mkdir(const QString &,bool) const2168     bool mkdir(const QString &, bool) const { return false; }
rmdir(const QString &,bool) const2169     bool rmdir(const QString &, bool) const { return false; }
setSize(qint64)2170     bool setSize(qint64) { return false; }
entryList(QDir::Filters,const QStringList &) const2171     QStringList entryList(QDir::Filters, const QStringList &) const { return QStringList(); }
caseSensitive() const2172     bool caseSensitive() const { return false; }
isRelativePath() const2173     bool isRelativePath() const { return false; }
fileFlags(FileFlags) const2174     FileFlags fileFlags(FileFlags) const { return 0; }
chmod(uint)2175     bool chmod(uint) { return false; }
fileName(FileName) const2176     QString fileName(FileName) const { return name; }
ownerId(FileOwner) const2177     uint ownerId(FileOwner) const { return 0; }
owner(FileOwner) const2178     QString owner(FileOwner) const { return QString(); }
fileTime(FileTime) const2179     QDateTime fileTime(FileTime) const { return QDateTime(); }
2180 
2181 private:
2182     int number;
2183     QString name;
2184 };
2185 
2186 class MyHandler : public QAbstractFileEngineHandler
2187 {
2188 public:
create(const QString &) const2189     inline QAbstractFileEngine *create(const QString &) const
2190     {
2191         return new MyEngine(1);
2192     }
2193 };
2194 
2195 class MyHandler2 : public QAbstractFileEngineHandler
2196 {
2197 public:
create(const QString &) const2198     inline QAbstractFileEngine *create(const QString &) const
2199     {
2200         return new MyEngine(2);
2201     }
2202 };
2203 
fileEngineHandler()2204 void tst_QFile::fileEngineHandler()
2205 {
2206     // A file that does not exist has a size of 0.
2207     QFile::remove("ole.bull");
2208     QFile file("ole.bull");
2209     QCOMPARE(file.size(), qint64(0));
2210 
2211     // Instantiating our handler will enable the new engine.
2212     MyHandler handler;
2213     file.setFileName("ole.bull");
2214     QCOMPARE(file.size(), qint64(124));
2215 
2216     // A new, identical handler should take preference over the last one.
2217     MyHandler2 handler2;
2218     file.setFileName("ole.bull");
2219     QCOMPARE(file.size(), qint64(125));
2220 
2221 }
2222 
2223 class MyRecursiveHandler : public QAbstractFileEngineHandler
2224 {
2225 public:
create(const QString & fileName) const2226     inline QAbstractFileEngine *create(const QString &fileName) const
2227     {
2228         if (fileName.startsWith(":!")) {
2229             QDir dir;
2230             QString realFile = SRCDIR + fileName.mid(2);
2231             if (dir.exists(realFile))
2232                 return new QFSFileEngine(realFile);
2233         }
2234         return 0;
2235     }
2236 };
2237 
useQFileInAFileHandler()2238 void tst_QFile::useQFileInAFileHandler()
2239 {
2240     // This test should not dead-lock
2241     MyRecursiveHandler handler;
2242     QFile file(":!tst_qfile.cpp");
2243     QVERIFY(file.exists());
2244 }
2245 
getCharFF()2246 void tst_QFile::getCharFF()
2247 {
2248     QFile file("file.txt");
2249     file.open(QFile::ReadWrite);
2250     file.write("\xff\xff\xff");
2251     file.flush();
2252     file.seek(0);
2253 
2254     char c;
2255     QVERIFY(file.getChar(&c));
2256     QVERIFY(file.getChar(&c));
2257     QVERIFY(file.getChar(&c));
2258 }
2259 
remove_and_exists()2260 void tst_QFile::remove_and_exists()
2261 {
2262     QFile::remove("tull_i_grunn.txt");
2263     QFile f("tull_i_grunn.txt");
2264 
2265     QVERIFY(!f.exists());
2266 
2267     bool opened = f.open(QIODevice::WriteOnly);
2268     QVERIFY(opened);
2269 
2270     f.write(QString("testing that remove/exists work...").toLatin1());
2271     f.close();
2272 
2273     QVERIFY(f.exists());
2274 
2275     f.remove();
2276     QVERIFY(!f.exists());
2277 }
2278 
removeOpenFile()2279 void tst_QFile::removeOpenFile()
2280 {
2281     {
2282         // remove an opened, write-only file
2283         QFile::remove("remove_unclosed.txt");
2284         QFile f("remove_unclosed.txt");
2285 
2286         QVERIFY(!f.exists());
2287         bool opened = f.open(QIODevice::WriteOnly);
2288         QVERIFY(opened);
2289         f.write(QString("testing that remove closes the file first...").toLatin1());
2290 
2291         bool removed = f.remove(); // remove should both close and remove the file
2292         QVERIFY(removed);
2293         QVERIFY(!f.isOpen());
2294         QVERIFY(!f.exists());
2295         QVERIFY(f.error() == QFile::NoError);
2296     }
2297 
2298     {
2299         // remove an opened, read-only file
2300         QFile::remove("remove_unclosed.txt");
2301 
2302         // first, write a file that we can remove
2303         {
2304             QFile f("remove_unclosed.txt");
2305             QVERIFY(!f.exists());
2306             bool opened = f.open(QIODevice::WriteOnly);
2307             QVERIFY(opened);
2308             f.write(QString("testing that remove closes the file first...").toLatin1());
2309             f.close();
2310         }
2311 
2312         QFile f("remove_unclosed.txt");
2313         bool opened = f.open(QIODevice::ReadOnly);
2314         QVERIFY(opened);
2315         f.readAll();
2316         // this used to only fail on FreeBSD (and Mac OS X)
2317         QVERIFY(f.flush());
2318         bool removed = f.remove(); // remove should both close and remove the file
2319         QVERIFY(removed);
2320         QVERIFY(!f.isOpen());
2321         QVERIFY(!f.exists());
2322         QVERIFY(f.error() == QFile::NoError);
2323     }
2324 }
2325 
fullDisk()2326 void tst_QFile::fullDisk()
2327 {
2328     QFile file("/dev/full");
2329     if (!file.exists())
2330         QSKIP("/dev/full doesn't exist on this system", SkipAll);
2331 
2332     QVERIFY(file.open(QIODevice::WriteOnly));
2333     file.write("foobar", 6);
2334 
2335     QVERIFY(!file.flush());
2336     QCOMPARE(file.error(), QFile::ResourceError);
2337     QVERIFY(!file.flush());
2338     QCOMPARE(file.error(), QFile::ResourceError);
2339 
2340     char c = 0;
2341     file.write(&c, 0);
2342     QVERIFY(!file.flush());
2343     QCOMPARE(file.error(), QFile::ResourceError);
2344     QCOMPARE(file.write(&c, 1), qint64(1));
2345     QVERIFY(!file.flush());
2346     QCOMPARE(file.error(), QFile::ResourceError);
2347 
2348     file.close();
2349     QVERIFY(!file.isOpen());
2350     QCOMPARE(file.error(), QFile::ResourceError);
2351 
2352     file.open(QIODevice::WriteOnly);
2353     QCOMPARE(file.error(), QFile::NoError);
2354     QVERIFY(file.flush()); // Shouldn't inherit write buffer
2355     file.close();
2356     QCOMPARE(file.error(), QFile::NoError);
2357 
2358     // try again without flush:
2359     QVERIFY(file.open(QIODevice::WriteOnly));
2360     file.write("foobar", 6);
2361     file.close();
2362     QVERIFY(file.error() != QFile::NoError);
2363 }
2364 
writeLargeDataBlock_data()2365 void tst_QFile::writeLargeDataBlock_data()
2366 {
2367     QTest::addColumn<QString>("fileName");
2368     QTest::addColumn<int>("type");
2369 
2370     QTest::newRow("localfile-QFile")  << "./largeblockfile.txt" << (int)OpenQFile;
2371     QTest::newRow("localfile-Fd")     << "./largeblockfile.txt" << (int)OpenFd;
2372     QTest::newRow("localfile-Stream") << "./largeblockfile.txt" << (int)OpenStream;
2373 #ifdef Q_OS_SYMBIAN
2374     QTest::newRow("localfile-RFile")  << "./largeblockfile.txt" << (int)OpenRFile;
2375 #endif
2376 
2377 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
2378     // Some semi-randomness to avoid collisions.
2379     QTest::newRow("unc file")
2380         << QString("//" + QtNetworkSettings::winServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt")
2381         .arg(QHostInfo::localHostName())
2382         .arg(QTime::currentTime().msec()) << (int)OpenQFile;
2383 #endif
2384 }
2385 
getLargeDataBlock()2386 static QByteArray getLargeDataBlock()
2387 {
2388     static QByteArray array;
2389 
2390     if (array.isNull())
2391     {
2392 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
2393         int resizeSize = 1024 * 1024; // WinCE and Symbian do not have much space
2394 #else
2395         int resizeSize = 64 * 1024 * 1024;
2396 #endif
2397         array.resize(resizeSize);
2398         for (int i = 0; i < array.size(); ++i)
2399             array[i] = uchar(i);
2400     }
2401 
2402     return array;
2403 }
2404 
writeLargeDataBlock()2405 void tst_QFile::writeLargeDataBlock()
2406 {
2407     QFETCH(QString, fileName);
2408     QFETCH( int, type );
2409 
2410     QByteArray const originalData = getLargeDataBlock();
2411 
2412     {
2413         QFile file(fileName);
2414 
2415         QVERIFY2( openFile(file, QIODevice::WriteOnly, (FileType)type),
2416             qPrintable(QString("Couldn't open file for writing: [%1]").arg(fileName)) );
2417         qint64 fileWriteOriginalData = file.write(originalData);
2418         qint64 originalDataSize      = (qint64)originalData.size();
2419 #if defined(Q_OS_WIN)
2420         if (fileWriteOriginalData == -1) {
2421             qWarning() << qPrintable(QString("Error writing a large data block to [%1]: %2")
2422                 .arg(fileName)
2423                 .arg(file.errorString()));
2424             QEXPECT_FAIL("unc file", "QTBUG-26906", Abort);
2425         }
2426 #endif
2427         QCOMPARE( fileWriteOriginalData, originalDataSize );
2428         QVERIFY( file.flush() );
2429 
2430         closeFile(file);
2431     }
2432 
2433     QByteArray readData;
2434 
2435     {
2436         QFile file(fileName);
2437 
2438         QVERIFY2( openFile(file, QIODevice::ReadOnly, (FileType)type),
2439             qPrintable(QString("Couldn't open file for reading: [%1]").arg(fileName)) );
2440         readData = file.readAll();
2441         closeFile(file);
2442     }
2443 
2444     QCOMPARE( readData, originalData );
2445     QVERIFY( QFile::remove(fileName) );
2446 }
2447 
readFromWriteOnlyFile()2448 void tst_QFile::readFromWriteOnlyFile()
2449 {
2450     QFile file("writeonlyfile");
2451     QVERIFY(file.open(QFile::WriteOnly));
2452     char c;
2453     QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device");
2454     QCOMPARE(file.read(&c, 1), qint64(-1));
2455 }
2456 
writeToReadOnlyFile()2457 void tst_QFile::writeToReadOnlyFile()
2458 {
2459     QFile file("readonlyfile");
2460     QVERIFY(file.open(QFile::ReadOnly));
2461     char c = 0;
2462     QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device");
2463     QCOMPARE(file.write(&c, 1), qint64(-1));
2464 }
2465 
virtualFile()2466 void tst_QFile::virtualFile()
2467 {
2468     // test if QFile works with virtual files
2469     QString fname;
2470 #if defined(Q_OS_LINUX)
2471     fname = "/proc/self/maps";
2472 #elif defined(Q_OS_AIX)
2473     fname = QString("/proc/%1/map").arg(getpid());
2474 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
2475     fname = "/proc/curproc/map";
2476 #else
2477     QSKIP("This platform does not have 0-sized virtual files", SkipAll);
2478 #endif
2479 
2480     // consistency check
2481     QFileInfo fi(fname);
2482     QVERIFY(fi.exists());
2483     QVERIFY(fi.isFile());
2484     QCOMPARE(fi.size(), Q_INT64_C(0));
2485 
2486     // open the file
2487     QFile f(fname);
2488     QVERIFY(f.open(QIODevice::ReadOnly));
2489     QCOMPARE(f.size(), Q_INT64_C(0));
2490     QVERIFY(f.atEnd());
2491 
2492     // read data
2493     QByteArray data = f.read(16);
2494     QCOMPARE(data.size(), 16);
2495     QCOMPARE(f.pos(), Q_INT64_C(16));
2496 
2497     // line-reading
2498     data = f.readLine();
2499     QVERIFY(!data.isEmpty());
2500 
2501     // read all:
2502     data = f.readAll();
2503     QVERIFY(f.pos() != 0);
2504     QVERIFY(!data.isEmpty());
2505 
2506     // seeking
2507     QVERIFY(f.seek(1));
2508     QCOMPARE(f.pos(), Q_INT64_C(1));
2509 }
2510 
textFile()2511 void tst_QFile::textFile()
2512 {
2513 #if defined(Q_OS_WINCE)
2514 	FILE *fs = ::fopen((QCoreApplication::applicationDirPath() + "/writeabletextfile").toAscii() , "wt");
2515 #elif defined(Q_OS_WIN)
2516     FILE *fs = ::fopen("writeabletextfile", "wt");
2517 #else
2518     FILE *fs = ::fopen("writeabletextfile", "w");
2519 #endif
2520     QFile f;
2521     QByteArray part1("This\nis\na\nfile\nwith\nnewlines\n");
2522     QByteArray part2("Add\nsome\nmore\nnewlines\n");
2523 
2524     QVERIFY(f.open(fs, QIODevice::WriteOnly));
2525     f.write(part1);
2526     f.write(part2);
2527     f.close();
2528     ::fclose(fs);
2529 
2530     QFile file("writeabletextfile");
2531     QVERIFY(file.open(QIODevice::ReadOnly));
2532 
2533     QByteArray data = file.readAll();
2534 
2535     QByteArray expected = part1 + part2;
2536 #ifdef Q_OS_WIN
2537     expected.replace("\n", "\015\012");
2538 #endif
2539     QCOMPARE(data, expected);
2540     file.close();
2541     file.remove();
2542 }
2543 
rename_data()2544 void tst_QFile::rename_data()
2545 {
2546     QTest::addColumn<QString>("source");
2547     QTest::addColumn<QString>("destination");
2548     QTest::addColumn<bool>("result");
2549 
2550     QTest::newRow("a -> b") << QString("a") << QString("b") << false;
2551     QTest::newRow("a -> .") << QString("a") << QString(".") << false;
2552     QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false;
2553     QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false;
2554 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
2555     QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false;
2556 #endif
2557     QTest::newRow("renamefile -> renamedfile") << QString("renamefile") << QString("renamedfile") << true;
2558     QTest::newRow("renamefile -> ..") << QString("renamefile") << QString("..") << false;
2559 }
2560 
rename()2561 void tst_QFile::rename()
2562 {
2563     QFETCH(QString, source);
2564     QFETCH(QString, destination);
2565     QFETCH(bool, result);
2566 
2567     QFile::remove("renamedfile");
2568     QFile f("renamefile");
2569     f.open(QFile::WriteOnly);
2570     f.close();
2571 
2572     QFile file(source);
2573     QCOMPARE(file.rename(destination), result);
2574 
2575     if (result)
2576         QCOMPARE(file.error(), QFile::NoError);
2577     else
2578         QCOMPARE(file.error(), QFile::RenameError);
2579 
2580     QFile::remove("renamefile");
2581 }
2582 
2583 /*!
2584  \since 4.5
2585 
2586  Some special files have QFile::atEnd() returning true, even though there is
2587  more data available. True for corner cases, as well as some mounts on OS X.
2588 
2589  Here, we reproduce that condition by having a QFile sub-class with this
2590  peculiar atEnd() behavior.
2591 
2592  See task 231583.
2593  */
renameWithAtEndSpecialFile() const2594 void tst_QFile::renameWithAtEndSpecialFile() const
2595 {
2596     class PeculiarAtEnd : public QFile
2597     {
2598     public:
2599         virtual bool atEnd() const
2600         {
2601             return true;
2602         }
2603     };
2604 
2605     const QString newName(QLatin1String("newName.txt"));
2606     /* Cleanup, so we're a bit more robust. */
2607     QFile::remove(newName);
2608 
2609     const QString originalName(QString(SRCDIR "forRenaming.txt"));
2610 
2611     PeculiarAtEnd file;
2612     file.setFileName(originalName);
2613     QVERIFY(file.open(QIODevice::ReadOnly));
2614 
2615     QVERIFY(file.rename(newName));
2616 
2617     file.close();
2618     /* Guess what, we have to rename it back, otherwise we'll fail on second
2619      * invocation. */
2620     QVERIFY(QFile::rename(newName, originalName));
2621 }
2622 
renameFallback()2623 void tst_QFile::renameFallback()
2624 {
2625     // Using a resource file both to trigger QFile::rename's fallback handling
2626     // and as a *read-only* source whose move should fail.
2627     QFile file(":/rename-fallback.qrc");
2628     QVERIFY(file.exists() && "(test-precondition)");
2629     QFile::remove("file-rename-destination.txt");
2630 
2631     QVERIFY(!file.rename("file-rename-destination.txt"));
2632     QVERIFY(!QFile::exists("file-rename-destination.txt"));
2633     QVERIFY(!file.isOpen());
2634 }
2635 
renameMultiple()2636 void tst_QFile::renameMultiple()
2637 {
2638     // create the file if it doesn't exist
2639     QFile file("file-to-be-renamed.txt");
2640     QFile file2("existing-file.txt");
2641     QVERIFY(file.open(QIODevice::ReadWrite) && "(test-precondition)");
2642     QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
2643 
2644     // any stale files from previous test failures?
2645     QFile::remove("file-renamed-once.txt");
2646     QFile::remove("file-renamed-twice.txt");
2647 
2648     // begin testing
2649     QVERIFY(QFile::exists("existing-file.txt"));
2650     QVERIFY(!file.rename("existing-file.txt"));
2651     QCOMPARE(file.error(), QFile::RenameError);
2652     QCOMPARE(file.fileName(), QString("file-to-be-renamed.txt"));
2653 
2654     QVERIFY(file.rename("file-renamed-once.txt"));
2655     QVERIFY(!file.isOpen());
2656     QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
2657 
2658     QVERIFY(QFile::exists("existing-file.txt"));
2659     QVERIFY(!file.rename("existing-file.txt"));
2660     QCOMPARE(file.error(), QFile::RenameError);
2661     QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
2662 
2663     QVERIFY(file.rename("file-renamed-twice.txt"));
2664     QVERIFY(!file.isOpen());
2665     QCOMPARE(file.fileName(), QString("file-renamed-twice.txt"));
2666 
2667     QVERIFY(QFile::exists("existing-file.txt"));
2668     QVERIFY(!QFile::exists("file-to-be-renamed.txt"));
2669     QVERIFY(!QFile::exists("file-renamed-once.txt"));
2670     QVERIFY(QFile::exists("file-renamed-twice.txt"));
2671 
2672     file.remove();
2673     file2.remove();
2674     QVERIFY(!QFile::exists("file-renamed-twice.txt"));
2675     QVERIFY(!QFile::exists("existing-file.txt"));
2676 }
2677 
appendAndRead()2678 void tst_QFile::appendAndRead()
2679 {
2680     QFile writeFile(QLatin1String("appendfile.txt"));
2681     QVERIFY(writeFile.open(QIODevice::WriteOnly | QIODevice::Truncate));
2682 
2683     QFile readFile(QLatin1String("appendfile.txt"));
2684     QVERIFY(readFile.open(QIODevice::ReadOnly));
2685 
2686     // Write to the end of the file, then read that character back, and so on.
2687     for (int i = 0; i < 100; ++i) {
2688         char c = '\0';
2689         writeFile.putChar(char(i % 256));
2690         writeFile.flush();
2691         QVERIFY(readFile.getChar(&c));
2692         QCOMPARE(c, char(i % 256));
2693         QCOMPARE(readFile.pos(), writeFile.pos());
2694     }
2695 
2696     // Write blocks and read them back
2697     for (int j = 0; j < 18; ++j) {
2698         writeFile.write(QByteArray(1 << j, '@'));
2699         writeFile.flush();
2700         QCOMPARE(readFile.read(1 << j).size(), 1 << j);
2701     }
2702 
2703     readFile.close();
2704     QFile::remove(QLatin1String("appendfile.txt"));
2705 }
2706 
miscWithUncPathAsCurrentDir()2707 void tst_QFile::miscWithUncPathAsCurrentDir()
2708 {
2709 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(NO_NETWORK_TEST)
2710     QString current = QDir::currentPath();
2711     QVERIFY(QDir::setCurrent("//" + QtNetworkSettings::winServerName() + "/testshare"));
2712     QFile file("test.pri");
2713     QVERIFY(file.exists());
2714     QCOMPARE(int(file.size()), 34);
2715     QVERIFY(file.open(QIODevice::ReadOnly));
2716     QVERIFY(QDir::setCurrent(current));
2717 #endif
2718 }
2719 
standarderror()2720 void tst_QFile::standarderror()
2721 {
2722     QFile f;
2723     bool ok = f.open(stderr, QFile::WriteOnly);
2724     QVERIFY(ok);
2725     f.close();
2726 }
2727 
handle()2728 void tst_QFile::handle()
2729 {
2730     int fd;
2731 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
2732     QFile file(SRCDIR "tst_qfile.cpp");
2733     QVERIFY(file.open(QIODevice::ReadOnly));
2734     fd = int(file.handle());
2735     QVERIFY(fd > 2);
2736     QCOMPARE(int(file.handle()), fd);
2737     char c = '\0';
2738     QT_READ(int(file.handle()), &c, 1);
2739     QCOMPARE(c, '/');
2740 
2741     // test if the QFile and the handle remain in sync
2742     QVERIFY(file.getChar(&c));
2743     QCOMPARE(c, '*');
2744 
2745     // same, but read from QFile first now
2746     file.close();
2747     QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
2748     fd = int(file.handle());
2749     QVERIFY(fd > 2);
2750     QVERIFY(file.getChar(&c));
2751     QCOMPARE(c, '/');
2752 #ifdef Q_OS_UNIX
2753     QCOMPARE(QT_READ(fd, &c, 1), ssize_t(1));
2754 #else
2755     QCOMPARE(QT_READ(fd, &c, 1), 1);
2756 #endif
2757 
2758     QCOMPARE(c, '*');
2759 #endif
2760 
2761     //test round trip of adopted stdio file handle
2762     QFile file2;
2763     FILE *fp = fopen(SRCDIR "tst_qfile.cpp", "r");
2764     file2.open(fp, QIODevice::ReadOnly);
2765     QCOMPARE(int(file2.handle()), int(fileno(fp)));
2766     QCOMPARE(int(file2.handle()), int(fileno(fp)));
2767     fclose(fp);
2768 
2769     //test round trip of adopted posix file handle
2770 #ifdef Q_OS_UNIX
2771     QFile file3;
2772     fd = QT_OPEN(SRCDIR "tst_qfile.cpp", QT_OPEN_RDONLY);
2773     file3.open(fd, QIODevice::ReadOnly);
2774     QCOMPARE(int(file3.handle()), fd);
2775     QT_CLOSE(fd);
2776 #endif
2777 }
2778 
nativeHandleLeaks()2779 void tst_QFile::nativeHandleLeaks()
2780 {
2781 #ifdef Q_OS_SYMBIAN
2782     QSKIP("test assumptions invalid for symbian", SkipAll);
2783 #else
2784     int fd1, fd2;
2785 
2786 #ifdef Q_OS_WIN
2787     HANDLE handle1, handle2;
2788 #endif
2789 
2790     {
2791         QFile file("qt_file.tmp");
2792         QVERIFY( file.open(QIODevice::ReadWrite) );
2793 
2794         fd1 = file.handle();
2795         QVERIFY( -1 != fd1 );
2796     }
2797 
2798 #ifdef Q_OS_WIN
2799     handle1 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
2800             OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2801     QVERIFY( INVALID_HANDLE_VALUE != handle1 );
2802     QVERIFY( ::CloseHandle(handle1) );
2803 #endif
2804 
2805     {
2806         QFile file("qt_file.tmp");
2807         QVERIFY( file.open(QIODevice::ReadOnly) );
2808 
2809         fd2 = file.handle();
2810         QVERIFY( -1 != fd2 );
2811     }
2812 
2813 #ifdef Q_OS_WIN
2814     handle2 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
2815             OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2816     QVERIFY( INVALID_HANDLE_VALUE != handle2 );
2817     QVERIFY( ::CloseHandle(handle2) );
2818 #endif
2819 
2820     QCOMPARE( fd2, fd1 );
2821 
2822 #ifdef Q_OS_WIN
2823     QCOMPARE( handle2, handle1 );
2824 #endif
2825 #endif
2826 }
2827 
readEof_data()2828 void tst_QFile::readEof_data()
2829 {
2830     QTest::addColumn<QString>("filename");
2831     QTest::addColumn<int>("imode");
2832 
2833     QTest::newRow("buffered") << SRCDIR "testfile.txt" << 0;
2834     QTest::newRow("unbuffered") << SRCDIR "testfile.txt" << int(QIODevice::Unbuffered);
2835 
2836 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
2837     QTest::newRow("sequential,buffered") << "/dev/null" << 0;
2838     QTest::newRow("sequential,unbuffered") << "/dev/null" << int(QIODevice::Unbuffered);
2839 #endif
2840 }
2841 
readEof()2842 void tst_QFile::readEof()
2843 {
2844     QFETCH(QString, filename);
2845     QFETCH(int, imode);
2846     QIODevice::OpenMode mode = QIODevice::OpenMode(imode);
2847 
2848     {
2849         QFile file(filename);
2850         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2851         bool isSequential = file.isSequential();
2852         if (!isSequential) {
2853             QVERIFY(file.seek(245));
2854             QVERIFY(file.atEnd());
2855         }
2856 
2857         char buf[10];
2858         int ret = file.read(buf, sizeof buf);
2859         QCOMPARE(ret, 0);
2860         QVERIFY(file.error() == QFile::NoError);
2861         QVERIFY(file.atEnd());
2862 
2863         // Do it again to ensure that we get the same result
2864         ret = file.read(buf, sizeof buf);
2865         QCOMPARE(ret, 0);
2866         QVERIFY(file.error() == QFile::NoError);
2867         QVERIFY(file.atEnd());
2868     }
2869 
2870     {
2871         QFile file(filename);
2872         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2873         bool isSequential = file.isSequential();
2874         if (!isSequential) {
2875             QVERIFY(file.seek(245));
2876             QVERIFY(file.atEnd());
2877         }
2878 
2879         QByteArray ret = file.read(10);
2880         QVERIFY(ret.isEmpty());
2881         QVERIFY(file.error() == QFile::NoError);
2882         QVERIFY(file.atEnd());
2883 
2884         // Do it again to ensure that we get the same result
2885         ret = file.read(10);
2886         QVERIFY(ret.isEmpty());
2887         QVERIFY(file.error() == QFile::NoError);
2888         QVERIFY(file.atEnd());
2889     }
2890 
2891     {
2892         QFile file(filename);
2893         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2894         bool isSequential = file.isSequential();
2895         if (!isSequential) {
2896             QVERIFY(file.seek(245));
2897             QVERIFY(file.atEnd());
2898         }
2899 
2900         char buf[10];
2901         int ret = file.readLine(buf, sizeof buf);
2902         QCOMPARE(ret, -1);
2903         QVERIFY(file.error() == QFile::NoError);
2904         QVERIFY(file.atEnd());
2905 
2906         // Do it again to ensure that we get the same result
2907         ret = file.readLine(buf, sizeof buf);
2908         QCOMPARE(ret, -1);
2909         QVERIFY(file.error() == QFile::NoError);
2910         QVERIFY(file.atEnd());
2911     }
2912 
2913     {
2914         QFile file(filename);
2915         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2916         bool isSequential = file.isSequential();
2917         if (!isSequential) {
2918             QVERIFY(file.seek(245));
2919             QVERIFY(file.atEnd());
2920         }
2921 
2922         QByteArray ret = file.readLine();
2923         QVERIFY(ret.isNull());
2924         QVERIFY(file.error() == QFile::NoError);
2925         QVERIFY(file.atEnd());
2926 
2927         // Do it again to ensure that we get the same result
2928         ret = file.readLine();
2929         QVERIFY(ret.isNull());
2930         QVERIFY(file.error() == QFile::NoError);
2931         QVERIFY(file.atEnd());
2932     }
2933 
2934     {
2935         QFile file(filename);
2936         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2937         bool isSequential = file.isSequential();
2938         if (!isSequential) {
2939             QVERIFY(file.seek(245));
2940             QVERIFY(file.atEnd());
2941         }
2942 
2943         char c;
2944         QVERIFY(!file.getChar(&c));
2945         QVERIFY(file.error() == QFile::NoError);
2946         QVERIFY(file.atEnd());
2947 
2948         // Do it again to ensure that we get the same result
2949         QVERIFY(!file.getChar(&c));
2950         QVERIFY(file.error() == QFile::NoError);
2951         QVERIFY(file.atEnd());
2952     }
2953 }
2954 
task167217()2955 void tst_QFile::task167217()
2956 {
2957     // Regression introduced in 4.3.0; after a failed stat, pos() could no
2958     // longer be calculated correctly.
2959     QFile::remove("tmp.txt");
2960     QFile file("tmp.txt");
2961     QVERIFY(!file.exists());
2962     QVERIFY(file.open(QIODevice::Append));
2963     QVERIFY(file.exists());
2964     file.write("qt430", 5);
2965     QVERIFY(!file.isSequential());
2966     QCOMPARE(file.pos(), qint64(5));
2967     file.remove();
2968 }
2969 
2970 #define FILESIZE 65536 * 3
2971 
map_data()2972 void tst_QFile::map_data()
2973 {
2974     QTest::addColumn<int>("fileSize");
2975     QTest::addColumn<int>("offset");
2976     QTest::addColumn<int>("size");
2977     QTest::addColumn<QFile::FileError>("error");
2978 
2979     QTest::newRow("zero")         << FILESIZE << 0     << FILESIZE         << QFile::NoError;
2980     QTest::newRow("small, but 0") << FILESIZE << 30    << FILESIZE - 30    << QFile::NoError;
2981     QTest::newRow("a page")       << FILESIZE << 4096  << FILESIZE - 4096  << QFile::NoError;
2982     QTest::newRow("+page")        << FILESIZE << 5000  << FILESIZE - 5000  << QFile::NoError;
2983     QTest::newRow("++page")       << FILESIZE << 65576 << FILESIZE - 65576 << QFile::NoError;
2984     QTest::newRow("bad size")     << FILESIZE << 0     << -1               << QFile::ResourceError;
2985     QTest::newRow("bad offset")   << FILESIZE << -1    << 1                << QFile::UnspecifiedError;
2986     QTest::newRow("zerozero")     << FILESIZE << 0     << 0                << QFile::UnspecifiedError;
2987 }
2988 
map()2989 void tst_QFile::map()
2990 {
2991     QFETCH(int, fileSize);
2992     QFETCH(int, offset);
2993     QFETCH(int, size);
2994     QFETCH(QFile::FileError, error);
2995 
2996     QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
2997 
2998 #ifdef Q_WS_WINCE
2999      fileName = QFileInfo(fileName).absoluteFilePath();
3000 #endif
3001 
3002     if (QFile::exists(fileName)) {
3003         QVERIFY(QFile::setPermissions(fileName,
3004             QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
3005         QFile::remove(fileName);
3006     }
3007     QFile file(fileName);
3008 
3009     // invalid, not open
3010     uchar *memory = file.map(0, size);
3011     QVERIFY(!memory);
3012     QCOMPARE(file.error(), QFile::PermissionsError);
3013     QVERIFY(!file.unmap(memory));
3014     QCOMPARE(file.error(), QFile::PermissionsError);
3015 
3016     // make a file
3017     QVERIFY(file.open(QFile::ReadWrite));
3018     QVERIFY(file.resize(fileSize));
3019     QVERIFY(file.flush());
3020     file.close();
3021     QVERIFY(file.open(QFile::ReadWrite));
3022     memory = file.map(offset, size);
3023     if (error != QFile::NoError) {
3024 
3025 	QVERIFY(file.error() != QFile::NoError);
3026         return;
3027     }
3028 
3029     QCOMPARE(file.error(), error);
3030     QVERIFY(memory);
3031     memory[0] = 'Q';
3032     QVERIFY(file.unmap(memory));
3033     QCOMPARE(file.error(), QFile::NoError);
3034 
3035     // Verify changes were saved
3036     memory = file.map(offset, size);
3037     QCOMPARE(file.error(), QFile::NoError);
3038     QVERIFY(memory);
3039     QVERIFY(memory[0] == 'Q');
3040     QVERIFY(file.unmap(memory));
3041     QCOMPARE(file.error(), QFile::NoError);
3042 
3043     // hpux wont let you map multiple times.
3044 #if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) && !defined(Q_OS_WINCE)
3045     // exotic test to make sure that multiple maps work
3046 
3047     // note: windows ce does not reference count mutliple maps
3048     // it's essentially just the same reference but it
3049     // cause a resource lock on the file which prevents it
3050     // from being removed    uchar *memory1 = file.map(0, file.size());
3051     uchar *memory1 = file.map(0, file.size());
3052     QCOMPARE(file.error(), QFile::NoError);
3053     uchar *memory2 = file.map(0, file.size());
3054     QCOMPARE(file.error(), QFile::NoError);
3055     QVERIFY(memory1);
3056     QVERIFY(memory2);
3057     QVERIFY(file.unmap(memory1));
3058     QCOMPARE(file.error(), QFile::NoError);
3059     QVERIFY(file.unmap(memory2));
3060     QCOMPARE(file.error(), QFile::NoError);
3061     memory1 = file.map(0, file.size());
3062     QCOMPARE(file.error(), QFile::NoError);
3063     QVERIFY(memory1);
3064     QVERIFY(file.unmap(memory1));
3065     QCOMPARE(file.error(), QFile::NoError);
3066 #endif
3067 
3068     file.close();
3069 
3070 #if defined(Q_OS_SYMBIAN)
3071 	 if (false) // No permissions for user makes no sense in Symbian
3072 #elif defined(Q_OS_UNIX)
3073     if (::getuid() != 0)
3074         // root always has permissions
3075 #endif
3076     {
3077         // Change permissions on a file, just to confirm it would fail
3078         QFile::Permissions originalPermissions = file.permissions();
3079         QVERIFY(file.setPermissions(QFile::ReadOther));
3080         QVERIFY(!file.open(QFile::ReadWrite));
3081         memory = file.map(offset, size);
3082         QCOMPARE(file.error(), QFile::PermissionsError);
3083         QVERIFY(!memory);
3084         QVERIFY(file.setPermissions(originalPermissions));
3085     }
3086     QVERIFY(file.remove());
3087 }
3088 
mapResource_data()3089 void tst_QFile::mapResource_data()
3090 {
3091     QTest::addColumn<int>("offset");
3092     QTest::addColumn<int>("size");
3093     QTest::addColumn<QFile::FileError>("error");
3094     QTest::addColumn<QString>("fileName");
3095 
3096     QString validFile = ":/tst_qfileinfo/resources/file1.ext1";
3097     QString invalidFile = ":/tst_qfileinfo/resources/filefoo.ext1";
3098 
3099     for (int i = 0; i < 2; ++i) {
3100         QString file = (i == 0) ? validFile : invalidFile;
3101         QTest::newRow("0, 0") << 0 << 0 << QFile::UnspecifiedError << file;
3102         QTest::newRow("0, BIG") << 0 << 4096 << QFile::UnspecifiedError << file;
3103         QTest::newRow("-1, 0") << -1 << 0 << QFile::UnspecifiedError << file;
3104         QTest::newRow("0, -1") << 0 << -1 << QFile::UnspecifiedError << file;
3105     }
3106 
3107     QTest::newRow("0, 1") << 0 << 1 << QFile::NoError << validFile;
3108 }
3109 
mapResource()3110 void tst_QFile::mapResource()
3111 {
3112     QFETCH(QString, fileName);
3113     QFETCH(int, offset);
3114     QFETCH(int, size);
3115     QFETCH(QFile::FileError, error);
3116 
3117     QFile file(fileName);
3118     uchar *memory = file.map(offset, size);
3119     QCOMPARE(file.error(), error);
3120     QVERIFY((error == QFile::NoError) ? (memory != 0) : (memory == 0));
3121     if (error == QFile::NoError)
3122         QCOMPARE(QString(memory[0]), QString::number(offset + 1));
3123     QVERIFY(file.unmap(memory));
3124 }
3125 
mapOpenMode_data()3126 void tst_QFile::mapOpenMode_data()
3127 {
3128     QTest::addColumn<int>("openMode");
3129 
3130     QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly);
3131     //QTest::newRow("WriteOnly") << int(QIODevice::WriteOnly); // this doesn't make sense
3132     QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite);
3133     QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered);
3134     QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered);
3135 }
3136 
mapOpenMode()3137 void tst_QFile::mapOpenMode()
3138 {
3139     QFETCH(int, openMode);
3140     static const qint64 fileSize = 4096;
3141 
3142     QByteArray pattern(fileSize, 'A');
3143 
3144     QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
3145     if (QFile::exists(fileName)) {
3146         QVERIFY(QFile::setPermissions(fileName,
3147             QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
3148 	QFile::remove(fileName);
3149     }
3150     QFile file(fileName);
3151 
3152     // make a file
3153     QVERIFY(file.open(QFile::ReadWrite));
3154     QVERIFY(file.write(pattern));
3155     QVERIFY(file.flush());
3156     file.close();
3157 
3158     // open according to our mode
3159     QVERIFY(file.open(QIODevice::OpenMode(openMode)));
3160 
3161     uchar *memory = file.map(0, fileSize);
3162     QVERIFY(memory);
3163     QVERIFY(memcmp(memory, pattern, fileSize) == 0);
3164 
3165     if (openMode & QIODevice::WriteOnly) {
3166         // try to write to the file
3167         *memory = 'a';
3168         file.unmap(memory);
3169         file.close();
3170         file.open(QIODevice::OpenMode(openMode));
3171         file.seek(0);
3172         char c;
3173         QVERIFY(file.getChar(&c));
3174         QCOMPARE(c, 'a');
3175     }
3176 
3177     file.close();
3178 }
3179 
openDirectory()3180 void tst_QFile::openDirectory()
3181 {
3182     QFile f1(SRCDIR "resources");
3183     // it's a directory, it must exist
3184     QVERIFY(f1.exists());
3185 
3186     // ...but not be openable
3187     QVERIFY(!f1.open(QIODevice::ReadOnly));
3188     f1.close();
3189     QVERIFY(!f1.open(QIODevice::ReadOnly|QIODevice::Unbuffered));
3190     f1.close();
3191     QVERIFY(!f1.open(QIODevice::ReadWrite));
3192     f1.close();
3193     QVERIFY(!f1.open(QIODevice::WriteOnly));
3194     f1.close();
3195     QVERIFY(!f1.open(QIODevice::WriteOnly|QIODevice::Unbuffered));
3196     f1.close();
3197 }
3198 
streamExpectedSize(int fd)3199 static qint64 streamExpectedSize(int fd)
3200 {
3201     QT_STATBUF sb;
3202     if (QT_FSTAT(fd, &sb) != -1)
3203         return sb.st_size;
3204     return 0;
3205 }
3206 
streamCurrentPosition(int fd)3207 static qint64 streamCurrentPosition(int fd)
3208 {
3209     QT_OFF_T pos = QT_LSEEK(fd, 0, SEEK_CUR);
3210     if (pos != -1)
3211         return pos;
3212     return 0;
3213 }
3214 
streamCurrentPosition(FILE * f)3215 static qint64 streamCurrentPosition(FILE *f)
3216 {
3217     QT_OFF_T pos = QT_FTELL(f);
3218     if (pos != -1)
3219         return pos;
3220     return 0;
3221 }
3222 
openStandardStreamsFileDescriptors()3223 void tst_QFile::openStandardStreamsFileDescriptors()
3224 {
3225 #ifdef Q_WS_WINCE
3226     //allthough Windows CE (not mobile!) has functions that allow redirecting
3227     //the standard file descriptors to a file (see SetStdioPathW/GetStdioPathW)
3228     //it does not have functions to simply open them like below .
3229     QSKIP("Opening standard streams on Windows CE via descriptor not implemented", SkipAll);
3230 #endif
3231 
3232     {
3233         QFile in;
3234         in.open(STDIN_FILENO, QIODevice::ReadOnly);
3235         QCOMPARE( in.pos(), streamCurrentPosition(STDIN_FILENO) );
3236         QCOMPARE( in.size(), streamExpectedSize(STDIN_FILENO) );
3237     }
3238 
3239     {
3240         QFile out;
3241         QVERIFY(out.open(STDOUT_FILENO, QIODevice::WriteOnly));
3242         QCOMPARE( out.pos(), streamCurrentPosition(STDOUT_FILENO) );
3243         QCOMPARE( out.size(), streamExpectedSize(STDOUT_FILENO) );
3244     }
3245 
3246     {
3247         QFile err;
3248         err.open(STDERR_FILENO, QIODevice::WriteOnly);
3249         QCOMPARE( err.pos(), streamCurrentPosition(STDERR_FILENO) );
3250         QCOMPARE( err.size(), streamExpectedSize(STDERR_FILENO) );
3251     }
3252 }
3253 
openStandardStreamsBufferedStreams()3254 void tst_QFile::openStandardStreamsBufferedStreams()
3255 {
3256 #if defined (Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
3257     QSKIP("Not tested on Windows CE or Symbian.");
3258 #endif
3259     // Using streams
3260     {
3261         /* in/out/err.isSequential() are only true when run in a console (CI);
3262         * it is false when they are redirected from/to files.
3263         * Prevent failures in case someone runs tests with stdout/stderr redirected. */
3264         QFile in;
3265         in.open(stdin, QIODevice::ReadOnly);
3266         QCOMPARE( in.pos(), streamCurrentPosition(stdin) );
3267         QCOMPARE( in.size(), streamExpectedSize(QT_FILENO(stdin)) );
3268     }
3269 
3270     {
3271         QFile out;
3272         out.open(stdout, QIODevice::WriteOnly);
3273         QCOMPARE( out.pos(), streamCurrentPosition(stdout) );
3274         QCOMPARE( out.size(), streamExpectedSize(QT_FILENO(stdout)) );
3275     }
3276 
3277     {
3278         QFile err;
3279         err.open(stderr, QIODevice::WriteOnly);
3280         QCOMPARE( err.pos(), streamCurrentPosition(stderr) );
3281         QCOMPARE( err.size(), streamExpectedSize(QT_FILENO(stderr)) );
3282     }
3283 }
3284 
openStandardStreams()3285 void tst_QFile::openStandardStreams()
3286 {
3287     openStandardStreamsFileDescriptors();
3288     openStandardStreamsBufferedStreams();
3289 }
3290 
writeNothing()3291 void tst_QFile::writeNothing()
3292 {
3293     for (int i = 0; i < NumberOfFileTypes; ++i) {
3294         QFile file("file.txt");
3295         QVERIFY( openFile(file, QIODevice::WriteOnly | QIODevice::Unbuffered, FileType(i)) );
3296         QVERIFY( 0 == file.write((char *)0, 0) );
3297         QCOMPARE( file.error(), QFile::NoError );
3298         closeFile(file);
3299     }
3300 }
3301 
resize_data()3302 void tst_QFile::resize_data()
3303 {
3304     QTest::addColumn<int>("filetype");
3305 
3306     QTest::newRow("native") << int(OpenQFile);
3307     QTest::newRow("fileno") << int(OpenFd);
3308     QTest::newRow("stream") << int(OpenStream);
3309 #ifdef Q_OS_SYMBIAN
3310     QTest::newRow("rfile")  << int(OpenRFile);
3311 #endif
3312 }
3313 
resize()3314 void tst_QFile::resize()
3315 {
3316     QFETCH(int, filetype);
3317     QString filename(QLatin1String("file.txt"));
3318     QFile file(filename);
3319     QVERIFY(openFile(file, QIODevice::ReadWrite, FileType(filetype)));
3320     QVERIFY(file.resize(8));
3321     QCOMPARE(file.size(), qint64(8));
3322     closeFile(file);
3323     QFile::resize(filename, 4);
3324     QCOMPARE(QFileInfo(filename).size(), qint64(4));
3325     QVERIFY(QFile::remove(filename));
3326 }
3327 
objectConstructors()3328 void tst_QFile::objectConstructors()
3329 {
3330     QObject ob;
3331     QFile* file1 = new QFile(SRCDIR "testfile.txt", &ob);
3332     QFile* file2 = new QFile(&ob);
3333     QVERIFY(file1->exists());
3334     QVERIFY(!file2->exists());
3335 }
3336 
3337 #ifdef Q_OS_SYMBIAN
platformSecurity_data()3338 void tst_QFile::platformSecurity_data()
3339 {
3340     QTest::addColumn<QString>("file");
3341     QTest::addColumn<bool>("readable");
3342     QTest::addColumn<bool>("writable");
3343 
3344     QString selfname = QCoreApplication::applicationFilePath();
3345     QString ownprivate = QCoreApplication::applicationDirPath();
3346     QString owndrive = selfname.left(2);
3347     bool amiprivileged = RProcess().HasCapability(ECapabilityAllFiles);
3348     QTest::newRow("resource") << owndrive + "/resource/apps/tst_qfile.rsc" << true << amiprivileged;
3349     QTest::newRow("sys") << selfname << amiprivileged << false;
3350     QTest::newRow("own private") << ownprivate + "/testfile.txt" << true << true;
3351     QTest::newRow("other private") << owndrive + "/private/10003a3f/import/apps/tst_qfile_reg.rsc" << amiprivileged << amiprivileged;
3352 }
3353 
platformSecurity()3354 void tst_QFile::platformSecurity()
3355 {
3356     QFETCH(QString,file);
3357     QFETCH(bool,readable);
3358     QFETCH(bool,writable);
3359 
3360     {
3361         QFile f(file);
3362         QCOMPARE(f.open(QIODevice::ReadOnly), readable);
3363     }
3364 
3365     {
3366         QFile f(file);
3367         QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Unbuffered), readable);
3368     }
3369 
3370     //append mode used to avoid truncating the files.
3371     {
3372         QFile f(file);
3373         QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append), writable);
3374     }
3375 
3376     {
3377         QFile f(file);
3378         QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered), writable);
3379     }
3380 
3381     {
3382         QFile f(file);
3383         QCOMPARE(f.open(QIODevice::ReadWrite), writable);
3384     }
3385 
3386     {
3387         QFile f(file);
3388         QCOMPARE(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered), writable);
3389     }
3390 }
3391 #endif
3392 
caseSensitivity()3393 void tst_QFile::caseSensitivity()
3394 {
3395 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) || defined(Q_OS_MAC)
3396     const bool caseSensitive = false;
3397 #else
3398     const bool caseSensitive = true;
3399 #endif
3400     QByteArray testData("a little test");
3401     QString filename("File.txt");
3402     {
3403         QFile f(filename);
3404         QVERIFY(f.open(QIODevice::WriteOnly));
3405         QVERIFY(f.write(testData));
3406         f.close();
3407     }
3408     QStringList alternates;
3409     QFileInfo fi(filename);
3410     QVERIFY(fi.exists());
3411     alternates << "file.txt" << "File.TXT" << "fIlE.TxT" << fi.absoluteFilePath().toUpper() << fi.absoluteFilePath().toLower();
3412     foreach (QString alt, alternates) {
3413         QFileInfo fi2(alt);
3414         QCOMPARE(fi2.exists(), !caseSensitive);
3415         QCOMPARE(fi.size() == fi2.size(), !caseSensitive);
3416         QFile f2(alt);
3417         QCOMPARE(f2.open(QIODevice::ReadOnly), !caseSensitive);
3418         if (!caseSensitive)
3419             QCOMPARE(f2.readAll(), testData);
3420     }
3421 }
3422 
3423 //MSVCRT asserts when any function is called with a closed file handle.
3424 //This replaces the default crashing error handler with one that ignores the error (allowing EBADF to be returned)
3425 class AutoIgnoreInvalidParameter
3426 {
3427 public:
3428 #if defined(Q_OS_WIN) && defined (Q_CC_MSVC)
ignore_invalid_parameter(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t)3429     static void ignore_invalid_parameter(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) {}
AutoIgnoreInvalidParameter()3430     AutoIgnoreInvalidParameter()
3431     {
3432         oldHandler = _set_invalid_parameter_handler(ignore_invalid_parameter);
3433         //also disable the abort/retry/ignore popup
3434         oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
3435     }
~AutoIgnoreInvalidParameter()3436     ~AutoIgnoreInvalidParameter()
3437     {
3438         //restore previous settings
3439         _set_invalid_parameter_handler(oldHandler);
3440         _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
3441     }
3442     _invalid_parameter_handler oldHandler;
3443     int oldReportMode;
3444 #endif
3445 };
3446 
autocloseHandle()3447 void tst_QFile::autocloseHandle()
3448 {
3449 #ifdef Q_OS_SYMBIAN
3450     // these tests are a bit different, because using a closed file handle results in a panic rather than error
3451     {
3452         QFile file("readonlyfile");
3453         QFile file2("readonlyfile");
3454         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::AutoCloseHandle));
3455         // file is opened with mandatory lock, so opening again should fail
3456         QVERIFY(!file2.open(QIODevice::ReadOnly));
3457 
3458         file.close();
3459         // opening again should now succeed (because handle is closed)
3460         QVERIFY(file2.open(QIODevice::ReadOnly));
3461     }
3462 
3463     {
3464         QFile file("readonlyfile");
3465         QFile file2("readonlyfile");
3466         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::DontCloseHandle));
3467         // file is opened with mandatory lock, so opening again should fail
3468         QVERIFY(!file2.open(QIODevice::ReadOnly));
3469 
3470         file.close();
3471         // opening again should still fail (because handle is not auto closed)
3472         QVERIFY(!file2.open(QIODevice::ReadOnly));
3473 
3474         rfile_.Close();
3475         // now it should succeed
3476         QVERIFY(file2.open(QIODevice::ReadOnly));
3477     }
3478 #endif
3479 
3480     {
3481         QFile file("readonlyfile");
3482         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::AutoCloseHandle));
3483         int fd = fd_;
3484         QCOMPARE(file.handle(), fd);
3485         file.close();
3486         fd_ = -1;
3487         QCOMPARE(file.handle(), -1);
3488         AutoIgnoreInvalidParameter a;
3489         Q_UNUSED(a);
3490         //file is closed, read should fail
3491         char buf;
3492         QCOMPARE((int)QT_READ(fd, &buf, 1), -1);
3493         QVERIFY(errno = EBADF);
3494     }
3495 
3496     {
3497         QFile file("readonlyfile");
3498         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::DontCloseHandle));
3499         QCOMPARE(file.handle(), fd_);
3500         file.close();
3501         QCOMPARE(file.handle(), -1);
3502         //file is not closed, read should succeed
3503         char buf;
3504         QCOMPARE((int)QT_READ(fd_, &buf, 1), 1);
3505         ::close(fd_);
3506         fd_ = -1;
3507     }
3508 
3509     {
3510         QFile file("readonlyfile");
3511         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::AutoCloseHandle));
3512         int fd = fileno(stream_);
3513         QCOMPARE(file.handle(), fd);
3514         file.close();
3515         stream_ = 0;
3516         QCOMPARE(file.handle(), -1);
3517         AutoIgnoreInvalidParameter a;
3518         Q_UNUSED(a);
3519         //file is closed, read should fail
3520         char buf;
3521         QCOMPARE((int)QT_READ(fd, &buf, 1), -1); //not using fread because the FILE* was freed by fclose
3522     }
3523 
3524     {
3525         QFile file("readonlyfile");
3526         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::DontCloseHandle));
3527         QCOMPARE(file.handle(), fileno(stream_));
3528         file.close();
3529         QCOMPARE(file.handle(), -1);
3530         //file is not closed, read should succeed
3531         char buf;
3532         QCOMPARE(int(::fread(&buf, 1, 1, stream_)), 1);
3533         ::fclose(stream_);
3534         stream_ = 0;
3535     }
3536 }
3537 
3538 QTEST_MAIN(tst_QFile)
3539 #include "tst_qfile.moc"
3540