summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Faure <faure@kde.org>2011-12-02 10:39:19 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-02 15:59:58 +0100
commit1bb51cb8b1de3ac795d408757812fc57fbf0a902 (patch)
tree59904e3e52f8fe307b292a4b3c8955a0952edebd
parent8c74fe5c7a754a072349fe4cb88834e6efdd5593 (diff)
Implement QDir::removeRecursively
Task-number: QTBUG-4592 Change-Id: I363e2c24d1c0ada975b8b927d7c6e776b8aae579 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
-rw-r--r--src/corelib/io/qdir.cpp46
-rw-r--r--src/corelib/io/qdir.h2
-rw-r--r--tests/auto/corelib/io/qdir/tst_qdir.cpp83
3 files changed, 131 insertions, 0 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 32fd81981b..44992fcd14 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1471,6 +1471,52 @@ bool QDir::rmpath(const QString &dirPath) const
}
/*!
+ Removes the directory, including all its contents.
+
+ Returns true if successful, otherwise false.
+
+ If a file or directory cannot be removed, removeRecursively() keeps going
+ and attempts to delete as many files and sub-directories as possible,
+ then returns false.
+
+ If the directory was already removed, the method returns true
+ (expected result already reached).
+
+ Note: this function is meant for removing a small application-internal
+ directory (such as a temporary directory), but not user-visible
+ directories. For user-visible operations, it is rather recommended
+ to report errors more precisely to the user, to offer solutions
+ in case of errors, to show progress during the deletion since it
+ could take several minutes, etc.
+*/
+bool QDir::removeRecursively()
+{
+ if (!d_ptr->exists())
+ return true;
+
+ bool success = true;
+ const QString dirPath = path();
+ // not empty -- we must empty it first
+ QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
+ while (di.hasNext()) {
+ di.next();
+ const QFileInfo& fi = di.fileInfo();
+ bool ok;
+ if (fi.isDir())
+ ok = QDir(di.filePath()).removeRecursively(); // recursive
+ else
+ ok = QFile::remove(di.filePath());
+ if (!ok)
+ success = false;
+ }
+
+ if (success)
+ success = rmdir(absolutePath());
+
+ return success;
+}
+
+/*!
Returns true if the directory is readable \e and we can open files
by name; otherwise returns false.
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index 822173dfc8..e246f2f1aa 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -166,6 +166,8 @@ public:
bool mkpath(const QString &dirPath) const;
bool rmpath(const QString &dirPath) const;
+ bool removeRecursively();
+
bool isReadable() const;
bool exists() const;
bool isRoot() const;
diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp
index 339eb55154..e6592a1174 100644
--- a/tests/auto/corelib/io/qdir/tst_qdir.cpp
+++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp
@@ -76,6 +76,7 @@ Q_OBJECT
private slots:
void init();
+ void cleanupTestCase();
void getSetCheck();
void construction();
@@ -99,6 +100,10 @@ private slots:
void rmdir_data();
void rmdir();
+ void removeRecursively_data();
+ void removeRecursively();
+ void removeRecursivelyFailure();
+
void exists_data();
void exists();
@@ -201,6 +206,11 @@ void tst_QDir::init()
QVERIFY2(QDir::setCurrent(m_dataPath), qPrintable("Could not chdir to " + m_dataPath));
}
+void tst_QDir::cleanupTestCase()
+{
+ QDir(QDir::currentPath() + "/tmpdir").removeRecursively();
+}
+
// Testing get/set functions
void tst_QDir::getSetCheck()
{
@@ -332,6 +342,79 @@ void tst_QDir::rmdir()
QVERIFY(!fi.exists());
}
+void tst_QDir::removeRecursively_data()
+{
+ QTest::addColumn<QString>("path");
+
+ // Create dirs and files
+ const QString tmpdir = QDir::currentPath() + "/tmpdir/";
+ QStringList dirs;
+ dirs << tmpdir + "empty"
+ << tmpdir + "one"
+ << tmpdir + "two/three"
+ << "relative";
+ QDir dir;
+ for (int i = 0; i < dirs.count(); ++i)
+ dir.mkpath(dirs.at(i));
+ QStringList files;
+ files << tmpdir + "one/file";
+ files << tmpdir + "two/three/file";
+ for (int i = 0; i < files.count(); ++i) {
+ QFile file(files.at(i));
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ file.write("Hello");
+ }
+
+ QTest::newRow("empty") << tmpdir + "empty";
+ QTest::newRow("one") << tmpdir + "one";
+ QTest::newRow("two") << tmpdir + "two";
+ QTest::newRow("does not exist") << tmpdir + "doesnotexist";
+ QTest::newRow("relative") << "relative";
+}
+
+void tst_QDir::removeRecursively()
+{
+ QFETCH(QString, path);
+
+ QDir dir(path);
+ QVERIFY(dir.removeRecursively());
+
+ //make sure it really doesn't exist (ie that remove worked)
+ QVERIFY(!dir.exists());
+}
+
+void tst_QDir::removeRecursivelyFailure()
+{
+ const QString tmpdir = QDir::currentPath() + "/tmpdir/";
+ const QString path = tmpdir + "undeletable";
+ QDir().mkpath(path);
+
+ // Need a file in there, otherwise rmdir works even w/o permissions
+ QFile file(path + "/file");
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ file.write("Hello");
+ file.close();
+
+#ifdef Q_OS_UNIX
+ QFile dirAsFile(path); // yay, I have to use QFile to change a dir's permissions...
+ QVERIFY(dirAsFile.setPermissions(QFile::Permissions(0))); // no permissions
+#else
+ QVERIFY(file.setPermissions(QFile::ReadOwner));
+#endif
+ QVERIFY(!QDir().rmdir(path));
+ QDir dir(path);
+ QVERIFY(!dir.removeRecursively()); // didn't work
+ QVERIFY(dir.exists()); // still exists
+
+#ifdef Q_OS_UNIX
+ QVERIFY(dirAsFile.setPermissions(QFile::Permissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner)));
+#else
+ QVERIFY(file.setPermissions(QFile::ReadOwner | QFile::WriteOwner));
+#endif
+ QVERIFY(dir.removeRecursively());
+ QVERIFY(!dir.exists());
+}
+
void tst_QDir::exists_data()
{
QTest::addColumn<QString>("path");