diff --git a/Foundation/include/Poco/Exception.h b/Foundation/include/Poco/Exception.h index d09d4ff998..61e05ceebc 100644 --- a/Foundation/include/Poco/Exception.h +++ b/Foundation/include/Poco/Exception.h @@ -246,6 +246,7 @@ POCO_DECLARE_EXCEPTION(Foundation_API, CreateFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, OpenFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, WriteFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, ReadFileException, FileException) +POCO_DECLARE_EXCEPTION(Foundation_API, ExecuteFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, FileNotReadyException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, DirectoryNotEmptyException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, UnknownURISchemeException, RuntimeException) diff --git a/Foundation/include/Poco/File.h b/Foundation/include/Poco/File.h index c13159da25..76e904c766 100644 --- a/Foundation/include/Poco/File.h +++ b/Foundation/include/Poco/File.h @@ -105,9 +105,24 @@ class Foundation_API File: private FileImpl const std::string& path() const; /// Returns the path. + std::string absolutePath() const; + /// Returns absolute path. + /// Attempts to find the existing file + /// using curent work directory and the PATH + /// environment variable. + /// If the file doesn't exist, returns empty string. + bool exists() const; /// Returns true iff the file exists. + bool existsAnywhere() const; + /// If the file path is relative, searches + /// for the file in the current working directory + /// and the environment paths. + /// If the file path is absolute, the + /// functionality is identical to the + /// exists() call. + bool canRead() const; /// Returns true iff the file is readable. diff --git a/Foundation/src/Exception.cpp b/Foundation/src/Exception.cpp index a1460406ee..6a382f8639 100644 --- a/Foundation/src/Exception.cpp +++ b/Foundation/src/Exception.cpp @@ -169,6 +169,7 @@ POCO_IMPLEMENT_EXCEPTION(CreateFileException, FileException, "Cannot create file POCO_IMPLEMENT_EXCEPTION(OpenFileException, FileException, "Cannot open file") POCO_IMPLEMENT_EXCEPTION(WriteFileException, FileException, "Cannot write file") POCO_IMPLEMENT_EXCEPTION(ReadFileException, FileException, "Cannot read file") +POCO_IMPLEMENT_EXCEPTION(ExecuteFileException, FileException, "Cannot execute file") POCO_IMPLEMENT_EXCEPTION(FileNotReadyException, FileException, "File not ready") POCO_IMPLEMENT_EXCEPTION(DirectoryNotEmptyException, FileException, "Directory not empty") POCO_IMPLEMENT_EXCEPTION(UnknownURISchemeException, RuntimeException, "Unknown URI scheme") diff --git a/Foundation/src/File.cpp b/Foundation/src/File.cpp index 9fe69ee2d1..5d9ed5356f 100644 --- a/Foundation/src/File.cpp +++ b/Foundation/src/File.cpp @@ -15,6 +15,8 @@ #include "Poco/File.h" #include "Poco/Path.h" #include "Poco/DirectoryIterator.h" +#include "Poco/Environment.h" +#include "Poco/StringTokenizer.h" #if defined(POCO_OS_FAMILY_WINDOWS) @@ -95,12 +97,66 @@ void File::swap(File& file) noexcept } +std::string File::absolutePath() const +{ + std::string ret; + + if (Path(path()).isAbsolute()) + ret = getPathImpl(); + else + { + Path curPath(Path::current()); + curPath.append(path()); + if (File(curPath).exists()) ret = curPath.toString(); + else + { + std::string envPath = Environment::get("PATH", ""); + std::string pathSeparator(1, Path::pathSeparator()); + if (!envPath.empty()) + { + StringTokenizer st(envPath, pathSeparator, + StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + for (const auto& p: st) + { + std::string fileName(p); + if (p.size() && p[p.size()-1] != Path::separator()) + fileName.append(1, Path::separator()); + fileName.append(path()); + if (File(fileName).exists()) + { + ret = fileName; + break; + } + } + } + } + } + + return ret; +} + + bool File::exists() const { + if (path().empty()) return false; return existsImpl(); } +bool File::existsAnywhere() const +{ + if (path().empty()) return false; + + if (Path(path()).isAbsolute()) + return existsImpl(); + + if (File(absolutePath()).exists()) + return true; + + return false; +} + + bool File::canRead() const { return canReadImpl(); diff --git a/Foundation/src/ProcessRunner.cpp b/Foundation/src/ProcessRunner.cpp index f07523c963..58db7f7d35 100644 --- a/Foundation/src/ProcessRunner.cpp +++ b/Foundation/src/ProcessRunner.cpp @@ -220,6 +220,18 @@ void ProcessRunner::start() { if (!_started.exchange(true)) { + File exe(_cmd); + if (!exe.existsAnywhere()) + { + throw Poco::FileNotFoundException( + Poco::format("ProcessRunner::start(%s): command not found", _cmd)); + } + else if (!File(exe.absolutePath()).canExecute()) + { + throw Poco::ExecuteFileException( + Poco::format("ProcessRunner::start(%s): cannot execute", _cmd)); + } + int prevRunCnt = runCount(); _t.start(*this); @@ -256,7 +268,6 @@ void ProcessRunner::start() } else throw Poco::InvalidAccessException("start() called on started ProcessRunner"); - checkStatus("", false); } diff --git a/Foundation/testsuite/src/FileTest.cpp b/Foundation/testsuite/src/FileTest.cpp index c1c9673fa7..66a866cc9c 100644 --- a/Foundation/testsuite/src/FileTest.cpp +++ b/Foundation/testsuite/src/FileTest.cpp @@ -18,7 +18,9 @@ #include "Poco/Thread.h" #include #include - +#if defined(POCO_OS_FAMILY_WINDOWS) +#include +#endif using Poco::File; using Poco::TemporaryFile; @@ -192,6 +194,54 @@ void FileTest::testCreateFile() } +void FileTest::testExists() +{ + assertFalse (File("").exists()); + + { + File f("testfile.dat"); + f.createFile(); + assertTrue (f.exists()); + assertTrue (f.existsAnywhere()); + assertFalse (f.canExecute()); + } + + { + File f("/testfile.dat"); + assertFalse (f.exists()); + assertFalse (f.existsAnywhere()); + try + { + f.canExecute(); + failmsg("file does not exist - must throw exception"); + } catch(const Poco::FileNotFoundException&) {} + } + + { +#if defined(POCO_OS_FAMILY_UNIX) + File f("echo"); + File f2("/dev/null"); +#elif defined(POCO_OS_FAMILY_WINDOWS) + File f("cmd.exe"); + + std::string buffer(Path::system()); + UINT r = GetSystemDirectoryA(buffer.c_str(), buffer.size()); + Path p(buffer); + p.makeDirectory().makeAbsolute().makeParent(); + buffer = p.toString(); + buffer.append("win.ini"); + File f2(buffer); +#endif + assertFalse (f.exists()); + assertTrue (f.existsAnywhere()); + assertTrue (File(f.absolutePath()).canExecute()); + assertTrue (f2.exists()); + assertTrue (f2.existsAnywhere()); + assertFalse (f2.canExecute()); + } +} + + void FileTest::testFileAttributes2() { TemporaryFile f; @@ -660,6 +710,7 @@ CppUnit::Test* FileTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileTest"); CppUnit_addTest(pSuite, FileTest, testCreateFile); + CppUnit_addTest(pSuite, FileTest, testExists); CppUnit_addTest(pSuite, FileTest, testFileAttributes1); CppUnit_addTest(pSuite, FileTest, testFileAttributes2); CppUnit_addTest(pSuite, FileTest, testFileAttributes3); diff --git a/Foundation/testsuite/src/FileTest.h b/Foundation/testsuite/src/FileTest.h index 65acb507cd..d964c97df8 100644 --- a/Foundation/testsuite/src/FileTest.h +++ b/Foundation/testsuite/src/FileTest.h @@ -26,6 +26,7 @@ class FileTest: public CppUnit::TestCase void testFileAttributes1(); void testCreateFile(); + void testExists(); void testFileAttributes2(); void testFileAttributes3(); void testCompare(); diff --git a/Foundation/testsuite/src/PathTest.cpp b/Foundation/testsuite/src/PathTest.cpp index 86145e9b30..15cca8b6f9 100644 --- a/Foundation/testsuite/src/PathTest.cpp +++ b/Foundation/testsuite/src/PathTest.cpp @@ -349,6 +349,9 @@ void PathTest::testParseUnix4() assertTrue (!p.isDirectory()); assertTrue (p.isFile()); assertTrue (p.toString(Path::PATH_UNIX) == "a/b/c/d"); + + p.makeDirectory(); + assertTrue (p.toString(Path::PATH_UNIX) == "a/b/c/d/"); } diff --git a/Foundation/testsuite/src/ProcessRunnerTest.cpp b/Foundation/testsuite/src/ProcessRunnerTest.cpp index e6fcf57a71..bd37357c10 100644 --- a/Foundation/testsuite/src/ProcessRunnerTest.cpp +++ b/Foundation/testsuite/src/ProcessRunnerTest.cpp @@ -276,8 +276,8 @@ void ProcessRunnerTest::testProcessRunner() try { pr.reset(new ProcessRunner(cmd, args)); - fail("ProcessRunner should throw an exception.", __LINE__, __FILE__); - } catch(const Poco::RuntimeException& e) {} + failmsg("ProcessRunner should throw an exception."); + } catch(const Poco::FileException& e) {} } assertTrue (!File(pidFile).exists()); } @@ -294,8 +294,8 @@ void ProcessRunnerTest::testProcessRunner() try { pr.reset(new ProcessRunner(cmd, args)); - fail("ProcessRunner should throw an exception.", __LINE__, __FILE__); - } catch(const Poco::RuntimeException& e) {} + failmsg("ProcessRunner should throw an exception."); + } catch(const Poco::FileException& e) {} } assertTrue (!File(pidFile).exists()); }