diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 9d9f9b1..9190baa 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,104 +1,119 @@ include(ECMAddTests) include(ConfigureChecks.cmake) #configure checks for QFileSystemWatcher find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG QUIET) if(NOT Qt5Test_FOUND) message(STATUS "Qt5Test not found, autotests will not be built.") return() endif() if(NOT CMAKE_BUILD_TYPE MATCHES "[Dd]ebug$") set(ENABLE_BENCHMARKS 1) endif() configure_file(config-tests.h.in config-tests.h) macro(build_plugin pname) add_library(${pname} MODULE ${ARGN}) ecm_mark_as_test(${pname}) target_link_libraries(${pname} KF5::CoreAddons) endmacro() # Build some sample plugins build_plugin(jsonplugin jsonplugin.cpp) build_plugin(jsonplugin2 jsonplugin2.cpp) build_plugin(versionedplugin versionedplugin.cpp) build_plugin(unversionedplugin unversionedplugin.cpp) build_plugin(multiplugin multiplugin.cpp) build_plugin(alwaysunloadplugin alwaysunloadplugin.cpp) add_definitions( -DKDELIBS4CONFIGMIGRATOR_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" ) +if (WIN32) + set(autotests_OPTIONAL_SRCS + ${autotests_OPTIONAL_SRCS} + klistopenfilesjobtest_win.cpp + ) +endif () + +if (UNIX) + set(autotests_OPTIONAL_SRCS + ${autotests_OPTIONAL_SRCS} + klistopenfilesjobtest_unix.cpp + ) +endif () + ecm_add_tests( kaboutdatatest.cpp kaboutdataapplicationdatatest.cpp kautosavefiletest.cpp kcompositejobtest.cpp kformattest.cpp kjobtest.cpp kosreleasetest.cpp kpluginfactorytest.cpp kpluginloadertest.cpp kpluginmetadatatest.cpp kprocesstest.cpp krandomtest.cpp kshareddatacachetest.cpp kshelltest.cpp kurlmimedatatest.cpp kstringhandlertest.cpp kusertest.cpp kdelibs4migrationtest.cpp kdelibs4configmigratortest.cpp kprocesslisttest.cpp kfileutilstest.cpp + ${autotests_OPTIONAL_SRCS} LINK_LIBRARIES Qt5::Test KF5::CoreAddons ) if(NOT CMAKE_CROSSCOMPILING) ecm_add_tests(desktoptojsontest.cpp LINK_LIBRARIES Qt5::Test KF5::CoreAddons) target_compile_definitions(desktoptojsontest PRIVATE DESKTOP_TO_JSON_EXE="$" ) endif() set(ktexttohtmltest_SRCS ktexttohtmltest.cpp ${CMAKE_SOURCE_DIR}/src/lib/text/ktexttohtml.cpp) ecm_add_test(${ktexttohtmltest_SRCS} TEST_NAME ktexttohtmltest LINK_LIBRARIES Qt5::Test) # include the binary dir in order to get kcoreaddons_export.h target_include_directories(ktexttohtmltest PRIVATE ${KCoreAddons_BINARY_DIR}/src/lib) # fake static linking to prevent the export macros on Windows from kicking in target_compile_definitions(ktexttohtmltest PRIVATE -DKCOREADDONS_STATIC_DEFINE=1) add_executable(kprocesstest_helper kprocesstest_helper.cpp) target_link_libraries(kprocesstest_helper KF5::CoreAddons) target_compile_definitions(kpluginloadertest PRIVATE JSONPLUGIN_FILE="$" VERSIONEDPLUGIN_FILE="$" UNVERSIONEDPLUGIN_FILE="$" MULTIPLUGIN_FILE="$" ALWAYSUNLOADPLUGIN_FILE="$" ) set(KDIRWATCH_BACKENDS_TO_TEST Stat)#Stat is always compiled if (HAVE_SYS_INOTIFY_H) list(APPEND KDIRWATCH_BACKENDS_TO_TEST INotify) endif() if (HAVE_FAM) list(APPEND KDIRWATCH_BACKENDS_TO_TEST Fam) endif() if (HAVE_QFILESYSTEMWATCHER) list(APPEND KDIRWATCH_BACKENDS_TO_TEST QFSWatch) endif() foreach(_backendName ${KDIRWATCH_BACKENDS_TO_TEST}) string(TOLOWER ${_backendName} _lowercaseBackendName) set(BACKEND_TEST_TARGET kdirwatch_${_lowercaseBackendName}_unittest) add_executable(${BACKEND_TEST_TARGET} kdirwatch_unittest.cpp) target_link_libraries(${BACKEND_TEST_TARGET} Qt5::Test KF5::CoreAddons) ecm_mark_as_test(${BACKEND_TEST_TARGET}) add_test(NAME ${BACKEND_TEST_TARGET} COMMAND ${BACKEND_TEST_TARGET}) target_compile_definitions(${BACKEND_TEST_TARGET} PUBLIC -DKDIRWATCH_TEST_METHOD=\"${_backendName}\") endforeach() diff --git a/autotests/klistopenfilesjobtest_unix.cpp b/autotests/klistopenfilesjobtest_unix.cpp new file mode 100644 index 0000000..25d8b96 --- /dev/null +++ b/autotests/klistopenfilesjobtest_unix.cpp @@ -0,0 +1,98 @@ +/* + * 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 "klistopenfilesjobtest_unix.h" +#include "klistopenfilesjob.h" +#include +#include +#include +#include +#include + +QTEST_MAIN(KListOpenFilesJobTest) + +void KListOpenFilesJobTest::testOpenFiles() +{ + QDir path(QCoreApplication::applicationDirPath()); + auto job = new KListOpenFilesJob(path.path()); + job->exec(); + QCOMPARE(job->error(), KJob::NoError); + auto processInfoList = job->processInfoList(); + QVERIFY(!processInfoList.empty()); + 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()); + QCOMPARE(processInfo.pid(), QCoreApplication::applicationPid()); +} + +void KListOpenFilesJobTest::testNoOpenFiles() +{ + QTemporaryDir tempDir; + auto job = new KListOpenFilesJob(tempDir.path()); + job->exec(); + QCOMPARE(job->error(), KJob::NoError); + QVERIFY(job->processInfoList().empty()); +} + +void KListOpenFilesJobTest::testNonExistingDir() +{ + QString nonExistingDir(QStringLiteral("/does/not/exist")); + auto job = new KListOpenFilesJob(nonExistingDir); + job->exec(); + QCOMPARE(job->error(), static_cast(KListOpenFilesJob::Error::DoesNotExist)); + QCOMPARE(job->errorText(), QStringLiteral("Path %1 doesn't exist").arg(nonExistingDir)); + QVERIFY(job->processInfoList().empty()); +} + +/** + * @brief Helper class to temporarily set an environment variable and reset it on destruction + */ +class ScopedEnvVariable +{ +public: + ScopedEnvVariable(const QLatin1String& Name, const QByteArray& NewValue) + : name(Name) + , originalValue(qgetenv(name.latin1())) + { + qputenv(name.latin1(), NewValue); + } + ~ScopedEnvVariable() + { + qputenv(name.latin1(), originalValue); + } +private: + const QLatin1String name; + const QByteArray originalValue; +}; + +void KListOpenFilesJobTest::testLsofNotFound() +{ + // This test relies on clearing the PATH variable so that lsof is not found + ScopedEnvVariable emptyPathEnvironment(QLatin1String("PATH"), QByteArray()); + QDir path(QCoreApplication::applicationDirPath()); + auto job = new KListOpenFilesJob(path.path()); + job->exec(); + QCOMPARE(job->error(), static_cast(KListOpenFilesJob::Error::InternalError)); + QVERIFY(job->processInfoList().empty()); +} diff --git a/autotests/klistopenfilesjobtest_unix.h b/autotests/klistopenfilesjobtest_unix.h new file mode 100644 index 0000000..af78955 --- /dev/null +++ b/autotests/klistopenfilesjobtest_unix.h @@ -0,0 +1,36 @@ +/* + * 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 KLISTOPENFILESJOBTEST_UNIX_H +#define KLISTOPENFILESJOBTEST_UNIX_H + +#include + +class KListOpenFilesJobTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testOpenFiles(); + void testNoOpenFiles(); + void testNonExistingDir(); + void testLsofNotFound(); +}; + +#endif diff --git a/autotests/klistopenfilesjobtest_win.cpp b/autotests/klistopenfilesjobtest_win.cpp new file mode 100644 index 0000000..f45a234 --- /dev/null +++ b/autotests/klistopenfilesjobtest_win.cpp @@ -0,0 +1,36 @@ +/* + * 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 "klistopenfilesjobtest_win.h" +#include "klistopenfilesjob.h" +#include +#include +#include + +QTEST_MAIN(KListOpenFilesJobTest) + +void KListOpenFilesJobTest::testNotSupported() +{ + QDir path(QCoreApplication::applicationDirPath()); + auto job = new KListOpenFilesJob(path.path()); + job->exec(); + QCOMPARE(job->error(), static_cast(KListOpenFilesJob::Error::NotSupported)); + QCOMPARE(job->errorText(), QStringLiteral("KListOpenFilesJob is not supported on Windows")); + QVERIFY(job->processInfoList().empty()); +} diff --git a/autotests/klistopenfilesjobtest_win.h b/autotests/klistopenfilesjobtest_win.h new file mode 100644 index 0000000..6bd7868 --- /dev/null +++ b/autotests/klistopenfilesjobtest_win.h @@ -0,0 +1,33 @@ +/* + * 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 KLISTOPENFILESJOBTEST_WIN_H +#define KLISTOPENFILESJOBTEST_WIN_H + +#include + +class KListOpenFilesJobTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testNotSupported(); +}; + +#endif diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 62c24c5..e0cb6d2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,296 +1,299 @@ # Configure checks for the caching subdir include(CheckIncludeFiles) check_include_files("sys/types.h;sys/mman.h" HAVE_SYS_MMAN_H) configure_file(caching/config-caching.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-caching.h) include(CheckSymbolExists) check_symbol_exists("getgrouplist" "grp.h" HAVE_GETGROUPLIST) configure_file(util/config-getgrouplist.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-getgrouplist.h) set (KDE4_DEFAULT_HOME ".kde${_KDE4_DEFAULT_HOME_POSTFIX}" CACHE STRING "The default KDE home directory" ) configure_file(util/config-kde4home.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kde4home.h) set (ACCOUNTS_SERVICE_ICON_DIR "/var/lib/AccountsService/icons" CACHE STRING "Accounts Services icon storage directory") configure_file(util/config-accountsservice.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-accountsservice.h) ecm_create_qm_loader(kcoreaddons_QM_LOADER kcoreaddons5_qt) set(kcoreaddons_OPTIONAL_SRCS ) set(kcoreaddons_OPTIONAL_LIBS ) if (FAM_FOUND) include_directories(${FAM_INCLUDE_DIR}) set(kcoreaddons_OPTIONAL_LIBS ${kcoreaddons_OPTIONAL_LIBS} ${FAM_LIBRARIES}) endif () if (Inotify_FOUND) include_directories(${Inotify_INCLUDE_DIRS}) set(kcoreaddons_OPTIONAL_LIBS ${kcoreaddons_OPTIONAL_LIBS} ${Inotify_LIBRARIES}) endif () if(NOT WIN32) set(kcoreaddons_OPTIONAL_SRCS caching/kshareddatacache.cpp) set(kcoreaddons_OPTIONAL_LIBS ${kcoreaddons_OPTIONAL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) set_source_files_properties(caching/kshareddatacache.cpp PROPERTIES COMPILE_FLAGS -fexceptions) else() set(kcoreaddons_OPTIONAL_SRCS caching/kshareddatacache_win.cpp ) endif() if (WIN32) set(kcoreaddons_OPTIONAL_SRCS ${kcoreaddons_OPTIONAL_SRCS} text/kmacroexpander_win.cpp + util/klistopenfilesjob_win.cpp util/kprocesslist_win.cpp util/kshell_win.cpp util/kuser_win.cpp ) endif () if (UNIX) set(kcoreaddons_OPTIONAL_SRCS ${kcoreaddons_OPTIONAL_SRCS} text/kmacroexpander_unix.cpp + util/klistopenfilesjob_unix.cpp util/kprocesslist_unix.cpp util/kuser_unix.cpp util/kshell_unix.cpp ) endif () set(libkcoreaddons_SRCS kaboutdata.cpp kcoreaddons.cpp io/kautosavefile.cpp io/kdirwatch.cpp io/kfilesystemtype.cpp io/kmessage.cpp io/kprocess.cpp io/kbackup.cpp io/kurlmimedata.cpp io/kfileutils.cpp jobs/kcompositejob.cpp jobs/kjob.cpp jobs/kjobtrackerinterface.cpp jobs/kjobuidelegate.cpp plugin/kpluginfactory.cpp plugin/kpluginloader.cpp plugin/kpluginmetadata.cpp plugin/desktopfileparser.cpp randomness/krandom.cpp randomness/krandomsequence.cpp text/kmacroexpander.cpp text/kstringhandler.cpp text/ktexttohtml.cpp util/kdelibs4migration.cpp util/kdelibs4configmigrator.cpp util/kformat.cpp util/kformatprivate.cpp util/kosrelease.cpp util/kprocesslist.cpp util/kshell.cpp ${kcoreaddons_OPTIONAL_SRCS} ${kcoreaddons_QM_LOADER} ) set(kcoreaddons_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/../.. # for kcoreaddons_version.h ${CMAKE_CURRENT_SOURCE_DIR}/caching/ ${CMAKE_CURRENT_BINARY_DIR}/io/ ${CMAKE_CURRENT_SOURCE_DIR}/io/ ${CMAKE_CURRENT_SOURCE_DIR}/jobs/ ${CMAKE_CURRENT_SOURCE_DIR}/plugin/ ${CMAKE_CURRENT_SOURCE_DIR}/randomness/ ${CMAKE_CURRENT_SOURCE_DIR}/text/ ${CMAKE_CURRENT_SOURCE_DIR}/util/ ) ecm_qt_declare_logging_category(libkcoreaddons_SRCS HEADER kcoreaddons_debug.h IDENTIFIER KCOREADDONS_DEBUG CATEGORY_NAME org.kde.kcoreaddons) add_library(KF5CoreAddons ${libkcoreaddons_SRCS}) generate_export_header(KF5CoreAddons BASE_NAME KCoreAddons) add_library(KF5::CoreAddons ALIAS KF5CoreAddons) target_include_directories(KF5CoreAddons PUBLIC "$") target_link_libraries(KF5CoreAddons PUBLIC Qt5::Core PRIVATE ${kcoreaddons_OPTIONAL_LIBS} ) target_link_libraries(KF5CoreAddons PRIVATE ${CMAKE_THREAD_LIBS_INIT}) if(WIN32) target_link_libraries(KF5CoreAddons PRIVATE netapi32 userenv) endif() target_include_directories(KF5CoreAddons INTERFACE "$" ) target_compile_definitions(KF5CoreAddons INTERFACE "$") set_target_properties(KF5CoreAddons PROPERTIES VERSION ${KCOREADDONS_VERSION_STRING} SOVERSION ${KCOREADDONS_SOVERSION} EXPORT_NAME CoreAddons ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KAboutData KCoreAddons REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KSharedDataCache RELATIVE caching REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KAutoSaveFile KDirWatch KMessage KProcess KBackup KUrlMimeData KFileSystemType KFileUtils RELATIVE io REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KCompositeJob KJob KJobTrackerInterface KJobUiDelegate RELATIVE jobs REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KExportPlugin KPluginFactory KPluginLoader KPluginMetaData RELATIVE plugin REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KRandom KRandomSequence RELATIVE randomness REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KMacroExpander KStringHandler KTextToHTML KTextToHTMLEmoticonsInterface RELATIVE text REQUIRED_HEADERS KCoreAddons_HEADERS ) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KFormat KOSRelease KUser KShell KProcessList Kdelibs4Migration Kdelibs4ConfigMigrator RELATIVE util REQUIRED_HEADERS KCoreAddons_HEADERS ) find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) ecm_generate_python_binding( TARGET KF5::CoreAddons PYTHONNAMESPACE PyKF5 MODULENAME KCoreAddons RULES_FILE "${CMAKE_SOURCE_DIR}/cmake/rules_PyKF5.py" SIP_DEPENDS QtCore/QtCoremod.sip HEADERS kaboutdata.h kcoreaddons.h caching/kshareddatacache.h io/kautosavefile.h io/kdirwatch.h io/kmessage.h io/kprocess.h io/kbackup.h io/kurlmimedata.h io/kfilesystemtype.h jobs/kcompositejob.h jobs/kjob.h jobs/kjobtrackerinterface.h jobs/kjobuidelegate.h plugin/kexportplugin.h plugin/kpluginfactory.h plugin/kpluginloader.h plugin/kpluginmetadata.h randomness/krandom.h randomness/krandomsequence.h text/kmacroexpander.h text/kstringhandler.h text/ktexttohtml.h text/ktexttohtmlemoticonsinterface.h util/kformat.h + util/klistopenfilesjob.h util/kosrelease.h util/kprocesslist.h util/kuser.h util/kshell.h util/kdelibs4migration.h util/kdelibs4configmigrator.h ) endif() install(TARGETS KF5CoreAddons EXPORT KF5CoreAddonsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KCoreAddons_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kcoreaddons_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KCoreAddons COMPONENT Devel ) # Includes CMake code to install open-source license texts for KAboutData. add_subdirectory(licenses) if(BUILD_QCH) ecm_add_qch( KF5CoreAddons_QCH NAME KCoreAddons BASE_NAME KF5CoreAddons VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KCoreAddons_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Core_QCH BLANK_MACROS KCOREADDONS_EXPORT KCOREADDONS_DEPRECATED KCOREADDONS_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KCoreAddons LIB_NAME KF5CoreAddons DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KCoreAddons) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/lib/util/klistopenfilesjob.h b/src/lib/util/klistopenfilesjob.h new file mode 100644 index 0000000..3ebad5d --- /dev/null +++ b/src/lib/util/klistopenfilesjob.h @@ -0,0 +1,80 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2010 by Jacopo De Simoi + * Copyright (C) 2014 by Lukáš Tinkl + * Copyright (C) 2016 by Kai Uwe Broulik + * 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 KLISTOPENFILESJOB_H +#define KLISTOPENFILESJOB_H + +#include +#include +#include +#include +#include +#include + +class KListOpenFilesJobPrivate; + + +/** + * @brief Provides information about processes that have open files in a given path or subdirectory of path. + * + * When start() is invoked it starts to collect information about processes that have any files open in path or a + * subdirectory of path. When it is done the KJob::result signal is emitted and the result can be retrieved with the + * processInfoList function. + * + * On Unix like systems the lsof utility is used to get the list of processes. + * On Windows the listing always fails with error code NotSupported. + * + * @since 5.63 + */ +class KCOREADDONS_EXPORT KListOpenFilesJob : public KJob +{ + Q_OBJECT +public: + explicit KListOpenFilesJob(const QString &path); + ~KListOpenFilesJob() override; + void start() override; + /** + * @brief Returns the list of processes with open files for the requested path + * @return The list of processes with open files for the requested path + */ + KProcessList::KProcessInfoList processInfoList() const; + +public: + /** + * @brief Special error codes emitted by KListOpenFilesJob + * + * The KListOpenFilesJob uses the error codes defined here besides the standard error codes defined by KJob + */ + enum class Error { + /*** Indicates that the platform doesn't support listing open files by processes */ + NotSupported = KJob::UserDefinedError + 1, + /*** Internal error has ocurred */ + InternalError = KJob::UserDefinedError + 2, + /*** The specified path does not exist */ + DoesNotExist = KJob::UserDefinedError + 11, + }; +private: + friend class KListOpenFilesJobPrivate; + QScopedPointer d; +}; + +#endif // KLISTOPENFILESJOB_H diff --git a/src/lib/util/klistopenfilesjob_unix.cpp b/src/lib/util/klistopenfilesjob_unix.cpp new file mode 100644 index 0000000..945698a --- /dev/null +++ b/src/lib/util/klistopenfilesjob_unix.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2010 by Jacopo De Simoi + * Copyright (C) 2014 by Lukáš Tinkl + * Copyright (C) 2016 by Kai Uwe Broulik + * 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 "klistopenfilesjob.h" +#include +#include + +class KListOpenFilesJobPrivate +{ +public: + KListOpenFilesJobPrivate(KListOpenFilesJob *Job, QDir Path) + : job(Job) + , path(Path) + , hasEmittedResult(false) + { + QObject::connect(&lsofProcess, &QProcess::errorOccurred, [this](QProcess::ProcessError error) { + lsofError(error); + }); + QObject::connect(&lsofProcess, QOverload::of(&QProcess::finished), + [this](int exitCode, QProcess::ExitStatus exitStatus) { + lsofFinished(exitCode, exitStatus); + }); + } + void start() + { + if (!path.exists()) { + emitResult(static_cast(KListOpenFilesJob::Error::DoesNotExist), + QObject::tr("Path %1 doesn't exist").arg(path.path())); + return; + } + lsofProcess.start(QStringLiteral("lsof"), {QStringLiteral("-t"), QStringLiteral("+d"), path.path()}); + } + KProcessList::KProcessInfoList getProcessInfoList() const + { + return processInfoList; + } +private: + void lsofError(QProcess::ProcessError processError) + { + emitResult(static_cast(KListOpenFilesJob::Error::InternalError), + QObject::tr("Failed to execute `lsof' error code %1").arg(processError)); + } + void lsofFinished(int, QProcess::ExitStatus) + { + if (hasEmittedResult) { + return; + } + QStringList blockApps; + const QString out(QString::fromLocal8Bit(lsofProcess.readAll())); + QStringList pidList = out.split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); + pidList.removeDuplicates(); + for (const auto& pidStr : qAsConst(pidList)) { + qint64 pid = pidStr.toLongLong(); + if (!pid) { + continue; + } + processInfoList << KProcessList::processInfo(pid); + } + job->emitResult(); + } + void emitResult(int error, const QString& errorText) + { + if (hasEmittedResult) { + return; + } + job->setError(error); + job->setErrorText(errorText); + job->emitResult(); + hasEmittedResult = true; + } +private: + KListOpenFilesJob *job; + const QDir path; + bool hasEmittedResult; + QProcess lsofProcess; + KProcessList::KProcessInfoList processInfoList; +}; + +KListOpenFilesJob::KListOpenFilesJob(const QString& path) + : d(new KListOpenFilesJobPrivate(this, path)) +{ +} + +KListOpenFilesJob::~KListOpenFilesJob() = default; + +void KListOpenFilesJob::start() +{ + d->start(); +} + +KProcessList::KProcessInfoList KListOpenFilesJob::processInfoList() const +{ + return d->getProcessInfoList(); +} + +#include "moc_klistopenfilesjob.cpp" diff --git a/src/lib/util/klistopenfilesjob_win.cpp b/src/lib/util/klistopenfilesjob_win.cpp new file mode 100644 index 0000000..3c87a3d --- /dev/null +++ b/src/lib/util/klistopenfilesjob_win.cpp @@ -0,0 +1,48 @@ +/* + * 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 "klistopenfilesjob.h" +#include + +class KListOpenFilesJobPrivate +{ +}; + +KListOpenFilesJob::KListOpenFilesJob(const QString&) + : d(nullptr) +{ +} + +KListOpenFilesJob::~KListOpenFilesJob() = default; + +void KListOpenFilesJob::start() +{ + QTimer::singleShot(0, [this](){ + setError(static_cast(KListOpenFilesJob::Error::NotSupported)); + setErrorText(QObject::tr("KListOpenFilesJob is not supported on Windows")); + emitResult(); + }); +} + +KProcessList::KProcessInfoList KListOpenFilesJob::processInfoList() const +{ + return KProcessList::KProcessInfoList(); +} + +#include "moc_klistopenfilesjob.cpp"