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

source code of qtbase/tests/auto/corelib/io/qfile/tst_qfile.cpp