diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -50,6 +50,7 @@ kdelibs4migrationtest.cpp kdelibs4configmigratortest.cpp kprocesslisttest.cpp + klistopenfilestest.cpp LINK_LIBRARIES Qt5::Test KF5::CoreAddons ) diff --git a/autotests/klistopenfilestest.h b/autotests/klistopenfilestest.h new file mode 100644 --- /dev/null +++ b/autotests/klistopenfilestest.h @@ -0,0 +1,35 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2019 David Hallas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KLISTOPENFILESTEST_H +#define KLISTOPENFILESTEST_H + +#include + +class KListOpenFilesTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testOpenFiles(); + void testNoOpenFiles(); + void testNonExistingDir(); +}; + +#endif diff --git a/autotests/klistopenfilestest.cpp b/autotests/klistopenfilestest.cpp new file mode 100644 --- /dev/null +++ b/autotests/klistopenfilestest.cpp @@ -0,0 +1,91 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2019 David Hallas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "klistopenfilestest.h" +#include "klistopenfiles.h" +#include +#include +#include +#include +#include +#include + +QTEST_MAIN(KListOpenFilesTest) + +void KListOpenFilesTest::testOpenFiles() +{ + QEventLoop eventLoop; + QTimer delayedStart; + KProcessList::KProcessInfoList processInfoList; + delayedStart.singleShot(0, [&eventLoop, &processInfoList]() + { + KListOpenFiles::listProcessesWithOpenFiles(QCoreApplication::applicationDirPath(), [&eventLoop, &processInfoList](KProcessList::KProcessInfoList _processInfoList) + { + processInfoList = _processInfoList; + eventLoop.exit(); + }); + }); + eventLoop.exec(); + QVERIFY(processInfoList.empty() == false); + auto testProcessIterator = std::find_if(processInfoList.begin(), processInfoList.end(), [](const KProcessList::KProcessInfo& info) + { + return info.pid() == QCoreApplication::applicationPid(); + }); + QVERIFY(testProcessIterator != processInfoList.end()); + const auto& processInfo = *testProcessIterator; + QVERIFY(processInfo.isValid() == true); + QCOMPARE(processInfo.pid(), QCoreApplication::applicationPid()); +} + +void KListOpenFilesTest::testNoOpenFiles() +{ + QTemporaryDir tempDir; + QEventLoop eventLoop; + QTimer delayedStart; + KProcessList::KProcessInfoList processInfoList; + delayedStart.singleShot(0, [&tempDir, &eventLoop, &processInfoList]() + { + KListOpenFiles::listProcessesWithOpenFiles(tempDir.path(), [&eventLoop, &processInfoList](KProcessList::KProcessInfoList _processInfoList) + { + processInfoList = _processInfoList; + eventLoop.exit(); + }); + }); + eventLoop.exec(); + QVERIFY(processInfoList.empty() == true); +} + +void KListOpenFilesTest::testNonExistingDir() +{ + QTemporaryDir tempDir; + tempDir.remove(); + QEventLoop eventLoop; + QTimer delayedStart; + KProcessList::KProcessInfoList processInfoList; + delayedStart.singleShot(0, [&tempDir, &eventLoop, &processInfoList]() + { + KListOpenFiles::listProcessesWithOpenFiles(tempDir.path(), [&eventLoop, &processInfoList](KProcessList::KProcessInfoList _processInfoList) + { + processInfoList = _processInfoList; + eventLoop.exit(); + }); + }); + eventLoop.exec(); + QVERIFY(processInfoList.empty() == true); +} diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -88,6 +88,7 @@ util/kdelibs4configmigrator.cpp util/kformat.cpp util/kformatprivate.cpp + util/klistopenfiles.cpp util/kosrelease.cpp util/kprocesslist.cpp util/kshell.cpp @@ -247,6 +248,7 @@ text/ktexttohtml.h text/ktexttohtmlemoticonsinterface.h util/kformat.h + util/klistopenfiles.h util/kosrelease.h util/kprocesslist.h util/kuser.h diff --git a/src/lib/util/klistopenfiles.h b/src/lib/util/klistopenfiles.h new file mode 100644 --- /dev/null +++ b/src/lib/util/klistopenfiles.h @@ -0,0 +1,44 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2019 David Hallas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KLISTOPENFILES_H +#define KLISTOPENFILES_H + +#include +#include +#include +#include + +namespace KListOpenFiles +{ + +typedef std::function Callback; +/** + * @brief Retrieves list of processes that has open files in path or any subdirectory of path. The function + * will collect all processes and call callback once it is done. If an error occurs callback will be called + * with an empty list. + * @param path The path to list processes with open files from + * @param callback The callback to call with the list of processes + * @since 5.60 + */ +KCOREADDONS_EXPORT void listProcessesWithOpenFiles(QDir path, Callback callback); + +} // KListOpenFiles namespace + +#endif // KLISTOPENFILES_H diff --git a/src/lib/util/klistopenfiles.cpp b/src/lib/util/klistopenfiles.cpp new file mode 100644 --- /dev/null +++ b/src/lib/util/klistopenfiles.cpp @@ -0,0 +1,52 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2019 David Hallas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "klistopenfiles.h" +#include +#include + +namespace KListOpenFiles { + +void listProcessesWithOpenFiles(QDir path, Callback callback) +{ + QProcess *p = new QProcess; + QObject::connect(p, static_cast(&QProcess::error), [p, callback](QProcess::ProcessError) { + p->deleteLater(); + callback({}); + }); + QObject::connect(p, static_cast(&QProcess::finished), [p, callback](int,QProcess::ExitStatus) { + QStringList blockApps; + QString out(QString::fromLocal8Bit(p->readAll())); + QStringList pidList = out.split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); + pidList.removeDuplicates(); + KProcessList::KProcessInfoList processInfoList; + for (const auto& pidStr : pidList) { + qint64 pid = pidStr.toLongLong(); + if (!pid) { + continue; + } + processInfoList << KProcessList::processInfo(pid); + } + p->deleteLater(); + callback(processInfoList); + }); + p->start(QStringLiteral("lsof"), {QStringLiteral("-t"), QStringLiteral("+d"), path.path()}); +} + +}