Mercurial > hg > orthanc
changeset 2143:fd5875662670
creation of namespace SystemToolbox
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 09 Nov 2016 16:54:23 +0100 |
parents | 5a8840920121 |
children | a979ded1dbb1 |
files | CMakeLists.txt Core/FileStorage/FilesystemStorage.cpp Core/HttpClient.cpp Core/HttpServer/FilesystemHttpHandler.cpp Core/Images/Font.cpp Core/Images/IImageWriter.cpp Core/Images/JpegReader.cpp Core/Images/JpegWriter.cpp Core/Images/PngReader.cpp Core/Images/PngWriter.cpp Core/Logging.cpp Core/PrecompiledHeaders.h Core/SystemToolbox.cpp Core/SystemToolbox.h Core/TemporaryFile.cpp Core/TemporaryFile.h Core/Toolbox.cpp Core/Toolbox.h Core/WebServiceParameters.cpp OrthancServer/DicomDirWriter.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/ServerIndexChange.h Resources/CMake/BoostConfiguration.cmake Resources/Samples/Tools/RecoverCompressedFile.cpp UnitTestsSources/MultiThreadingTests.cpp UnitTestsSources/RestApiTests.cpp UnitTestsSources/SQLiteTests.cpp UnitTestsSources/StreamTests.cpp |
diffstat | 28 files changed, 667 insertions(+), 557 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Wed Nov 09 16:26:40 2016 +0100 +++ b/CMakeLists.txt Wed Nov 09 16:54:23 2016 +0100 @@ -146,6 +146,7 @@ Core/SQLite/StatementId.cpp Core/SQLite/StatementReference.cpp Core/SQLite/Transaction.cpp + Core/SystemToolbox.cpp Core/TemporaryFile.cpp Core/Toolbox.cpp Core/WebServiceParameters.cpp @@ -406,11 +407,12 @@ add_definitions( -DORTHANC_VERSION="${ORTHANC_VERSION}" -DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION} + -DORTHANC_BUILD_UNIT_TESTS=1 + -DORTHANC_ENABLE_BASE64=1 -DORTHANC_ENABLE_LOGGING=1 - -DORTHANC_ENABLE_BASE64=1 -DORTHANC_ENABLE_MD5=1 -DORTHANC_MAXIMUM_TAG_LENGTH=256 - -DORTHANC_BUILD_UNIT_TESTS=1 + -DORTHANC_SANDBOXED=0 # Macros for the plugins -DMODALITY_WORKLISTS_VERSION="${ORTHANC_VERSION}"
--- a/Core/FileStorage/FilesystemStorage.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/FileStorage/FilesystemStorage.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -39,6 +39,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../Toolbox.h" +#include "../SystemToolbox.h" #include <boost/filesystem/fstream.hpp>
--- a/Core/HttpClient.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/HttpClient.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -37,6 +37,7 @@ #include "OrthancException.h" #include "Logging.h" #include "ChunkedBuffer.h" +#include "SystemToolbox.h" #include <string.h> #include <curl/curl.h>
--- a/Core/HttpServer/FilesystemHttpHandler.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/HttpServer/FilesystemHttpHandler.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -34,6 +34,7 @@ #include "FilesystemHttpHandler.h" #include "../OrthancException.h" +#include "../SystemToolbox.h" #include "FilesystemHttpSender.h" #include <boost/filesystem.hpp>
--- a/Core/Images/Font.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/Font.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -33,6 +33,7 @@ #include "../PrecompiledHeaders.h" #include "Font.h" +#include "../SystemToolbox.h" #include "../Toolbox.h" #include "../OrthancException.h"
--- a/Core/Images/IImageWriter.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/IImageWriter.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -33,7 +33,14 @@ #include "IImageWriter.h" #include "../OrthancException.h" -#include "../Toolbox.h" + +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if ORTHANC_SANDBOXED == 0 +# include "../SystemToolbox.h" +#endif namespace Orthanc {
--- a/Core/Images/JpegReader.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/JpegReader.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -36,7 +36,7 @@ #include "JpegErrorManager.h" #include "../OrthancException.h" #include "../Logging.h" -#include "../Toolbox.h" +#include "../SystemToolbox.h" namespace Orthanc {
--- a/Core/Images/JpegWriter.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/JpegWriter.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -35,7 +35,7 @@ #include "../OrthancException.h" #include "../Logging.h" -#include "../Toolbox.h" +#include "../SystemToolbox.h" #include "JpegErrorManager.h"
--- a/Core/Images/PngReader.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/PngReader.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -34,6 +34,7 @@ #include "PngReader.h" #include "../OrthancException.h" +#include "../SystemToolbox.h" #include "../Toolbox.h" #include <png.h>
--- a/Core/Images/PngWriter.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Images/PngWriter.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -39,6 +39,7 @@ #include "../OrthancException.h" #include "../ChunkedBuffer.h" #include "../Toolbox.h" +#include "../SystemToolbox.h" // http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
--- a/Core/Logging.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Logging.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -83,6 +83,7 @@ #include "OrthancException.h" #include "Enumerations.h" #include "Toolbox.h" +#include "SystemToolbox.h" #include <fstream> #include <boost/filesystem.hpp>
--- a/Core/PrecompiledHeaders.h Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/PrecompiledHeaders.h Wed Nov 09 16:54:23 2016 +0100 @@ -56,6 +56,5 @@ #include "Logging.h" #include "OrthancException.h" #include "Toolbox.h" -#include "Uuid.h" #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/SystemToolbox.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -0,0 +1,502 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "SystemToolbox.h" + + +#if BOOST_HAS_DATE_TIME == 1 +#include <boost/date_time/posix_time/posix_time.hpp> +#endif + + +#if defined(_WIN32) +#include <windows.h> +#include <process.h> // For "_spawnvp()" and "_getpid()" +#else +#include <unistd.h> // For "execvp()" +#include <sys/wait.h> // For "waitpid()" +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include <mach-o/dyld.h> /* _NSGetExecutablePath */ +#include <limits.h> /* PATH_MAX */ +#endif + +#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#include <limits.h> /* PATH_MAX */ +#include <signal.h> +#include <unistd.h> +#endif + + +#include "Logging.h" +#include "OrthancException.h" +#include "Toolbox.h" + +#include <boost/filesystem.hpp> +#include <boost/filesystem/fstream.hpp> + + +namespace Orthanc +{ + static bool finish_; + static ServerBarrierEvent barrierEvent_; + +#if defined(_WIN32) + static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) + { + // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx + finish_ = true; + return true; + } +#else + static void SignalHandler(int signal) + { + if (signal == SIGHUP) + { + barrierEvent_ = ServerBarrierEvent_Reload; + } + + finish_ = true; + } +#endif + + + static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) + { +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, true); +#else + signal(SIGINT, SignalHandler); + signal(SIGQUIT, SignalHandler); + signal(SIGTERM, SignalHandler); + signal(SIGHUP, SignalHandler); +#endif + + // Active loop that awakens every 100ms + finish_ = false; + barrierEvent_ = ServerBarrierEvent_Stop; + while (!(*stopFlag || finish_)) + { + Toolbox::USleep(100 * 1000); + } + +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, false); +#else + signal(SIGINT, NULL); + signal(SIGQUIT, NULL); + signal(SIGTERM, NULL); + signal(SIGHUP, NULL); +#endif + + return barrierEvent_; + } + + + ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag) + { + return ServerBarrierInternal(&stopFlag); + } + + + ServerBarrierEvent SystemToolbox::ServerBarrier() + { + const bool stopFlag = false; + return ServerBarrierInternal(&stopFlag); + } + + + static std::streamsize GetStreamSize(std::istream& f) + { + // http://www.cplusplus.com/reference/iostream/istream/tellg/ + f.seekg(0, std::ios::end); + std::streamsize size = f.tellg(); + f.seekg(0, std::ios::beg); + + return size; + } + + + void SystemToolbox::ReadFile(std::string& content, + const std::string& path) + { + if (!IsRegularFile(path)) + { + LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; + throw OrthancException(ErrorCode_RegularFileExpected); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + std::streamsize size = GetStreamSize(f); + content.resize(size); + if (size != 0) + { + f.read(reinterpret_cast<char*>(&content[0]), size); + } + + f.close(); + } + + + bool SystemToolbox::ReadHeader(std::string& header, + const std::string& path, + size_t headerSize) + { + if (!IsRegularFile(path)) + { + LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; + throw OrthancException(ErrorCode_RegularFileExpected); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + bool full = true; + + { + std::streamsize size = GetStreamSize(f); + if (size <= 0) + { + headerSize = 0; + full = false; + } + else if (static_cast<size_t>(size) < headerSize) + { + headerSize = size; // Truncate to the size of the file + full = false; + } + } + + header.resize(headerSize); + if (headerSize != 0) + { + f.read(reinterpret_cast<char*>(&header[0]), headerSize); + } + + f.close(); + + return full; + } + + + void SystemToolbox::WriteFile(const void* content, + size_t size, + const std::string& path) + { + boost::filesystem::ofstream f; + f.open(path, std::ofstream::out | std::ofstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_CannotWriteFile); + } + + if (size != 0) + { + f.write(reinterpret_cast<const char*>(content), size); + + if (!f.good()) + { + f.close(); + throw OrthancException(ErrorCode_FileStorageCannotWrite); + } + } + + f.close(); + } + + + void SystemToolbox::WriteFile(const std::string& content, + const std::string& path) + { + WriteFile(content.size() > 0 ? content.c_str() : NULL, + content.size(), path); + } + + + void SystemToolbox::RemoveFile(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (IsRegularFile(path)) + { + boost::filesystem::remove(path); + } + else + { + throw OrthancException(ErrorCode_RegularFileExpected); + } + } + } + + + uint64_t SystemToolbox::GetFileSize(const std::string& path) + { + try + { + return static_cast<uint64_t>(boost::filesystem::file_size(path)); + } + catch (boost::filesystem::filesystem_error&) + { + throw OrthancException(ErrorCode_InexistentFile); + } + } + + + void SystemToolbox::MakeDirectory(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (!boost::filesystem::is_directory(path)) + { + throw OrthancException(ErrorCode_DirectoryOverFile); + } + } + else + { + if (!boost::filesystem::create_directories(path)) + { + throw OrthancException(ErrorCode_MakeDirectory); + } + } + } + + + bool SystemToolbox::IsExistingFile(const std::string& path) + { + return boost::filesystem::exists(path); + } + + +#if defined(_WIN32) + static std::string GetPathToExecutableInternal() + { + // Yes, this is ugly, but there is no simple way to get the + // required buffer size, so we use a big constant + std::vector<char> buffer(32768); + /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1)); + return std::string(&buffer[0]); + } + +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) + static std::string GetPathToExecutableInternal() + { + std::vector<char> buffer(PATH_MAX + 1); + ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); + if (bytes == 0) + { + throw OrthancException(ErrorCode_PathToExecutable); + } + + return std::string(&buffer[0]); + } + +#elif defined(__APPLE__) && defined(__MACH__) + static std::string GetPathToExecutableInternal() + { + char pathbuf[PATH_MAX + 1]; + unsigned int bufsize = static_cast<int>(sizeof(pathbuf)); + + _NSGetExecutablePath( pathbuf, &bufsize); + + return std::string(pathbuf); + } + +#else +#error Support your platform here +#endif + + + std::string SystemToolbox::GetPathToExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p).string(); + } + + + std::string SystemToolbox::GetDirectoryOfExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p.parent_path()).string(); + } + + + void SystemToolbox::ExecuteSystemCommand(const std::string& command, + const std::vector<std::string>& arguments) + { + // Convert the arguments as a C array + std::vector<char*> args(arguments.size() + 2); + + args.front() = const_cast<char*>(command.c_str()); + + for (size_t i = 0; i < arguments.size(); i++) + { + args[i + 1] = const_cast<char*>(arguments[i].c_str()); + } + + args.back() = NULL; + + int status; + +#if defined(_WIN32) + // http://msdn.microsoft.com/en-us/library/275khfab.aspx + status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); + +#else + int pid = fork(); + + if (pid == -1) + { + // Error in fork() +#if ORTHANC_ENABLE_LOGGING == 1 + LOG(ERROR) << "Cannot fork a child process"; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + else if (pid == 0) + { + // Execute the system command in the child process + execvp(command.c_str(), &args[0]); + + // We should never get here + _exit(1); + } + else + { + // Wait for the system command to exit + waitpid(pid, &status, 0); + } +#endif + + if (status != 0) + { +#if ORTHANC_ENABLE_LOGGING == 1 + LOG(ERROR) << "System command failed with status code " << status; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + } + + + int SystemToolbox::GetProcessId() + { +#if defined(_WIN32) + return static_cast<int>(_getpid()); +#else + return static_cast<int>(getpid()); +#endif + } + + + bool SystemToolbox::IsRegularFile(const std::string& path) + { + namespace fs = boost::filesystem; + + try + { + if (fs::exists(path)) + { + fs::file_status status = fs::status(path); + return (status.type() == boost::filesystem::regular_file || + status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 + } + } + catch (fs::filesystem_error&) + { + } + + return false; + } + + + FILE* SystemToolbox::OpenFile(const std::string& path, + FileMode mode) + { +#if defined(_WIN32) + // TODO Deal with special characters by converting to the current locale +#endif + + const char* m; + switch (mode) + { + case FileMode_ReadBinary: + m = "rb"; + break; + + case FileMode_WriteBinary: + m = "wb"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + return fopen(path.c_str(), m); + } + + +#if BOOST_HAS_DATE_TIME == 1 + std::string SystemToolbox::GetNowIsoString() + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + return boost::posix_time::to_iso_string(now); + } + + void SystemToolbox::GetNowDicom(std::string& date, + std::string& time) + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + tm tm = boost::posix_time::to_tm(now); + + char s[32]; + sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + date.assign(s); + + // TODO milliseconds + sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); + time.assign(s); + } +#endif +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/SystemToolbox.h Wed Nov 09 16:54:23 2016 +0100 @@ -0,0 +1,100 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if ORTHANC_SANDBOXED == 1 +# error The namespace SystemToolbox cannot be used in sandboxed environments +#endif + +#include "Enumerations.h" + +#include <vector> +#include <string> +#include <stdint.h> + +namespace Orthanc +{ + namespace SystemToolbox + { + ServerBarrierEvent ServerBarrier(const bool& stopFlag); + + ServerBarrierEvent ServerBarrier(); + + void ReadFile(std::string& content, + const std::string& path); + + bool ReadHeader(std::string& header, + const std::string& path, + size_t headerSize); + + void WriteFile(const void* content, + size_t size, + const std::string& path); + + void WriteFile(const std::string& content, + const std::string& path); + + void RemoveFile(const std::string& path); + + uint64_t GetFileSize(const std::string& path); + + void MakeDirectory(const std::string& path); + + bool IsExistingFile(const std::string& path); + + std::string GetPathToExecutable(); + + std::string GetDirectoryOfExecutable(); + + void ExecuteSystemCommand(const std::string& command, + const std::vector<std::string>& arguments); + + int GetProcessId(); + + bool IsRegularFile(const std::string& path); + + FILE* OpenFile(const std::string& path, + FileMode mode); + +#if BOOST_HAS_DATE_TIME == 1 + std::string GetNowIsoString(); + + void GetNowDicom(std::string& date, + std::string& time); +#endif + } +}
--- a/Core/TemporaryFile.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/TemporaryFile.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -33,6 +33,9 @@ #include "PrecompiledHeaders.h" #include "TemporaryFile.h" +#include "SystemToolbox.h" +#include "Toolbox.h" + #include <boost/filesystem.hpp> namespace Orthanc @@ -75,5 +78,17 @@ TemporaryFile::~TemporaryFile() { boost::filesystem::remove(path_); - } + } + + + void TemporaryFile::Write(const std::string& content) + { + SystemToolbox::WriteFile(content, path_); + } + + + void TemporaryFile::Read(std::string& content) const + { + SystemToolbox::ReadFile(content, path_); + } }
--- a/Core/TemporaryFile.h Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/TemporaryFile.h Wed Nov 09 16:54:23 2016 +0100 @@ -32,17 +32,15 @@ #pragma once -#include <string> - #if !defined(ORTHANC_SANDBOXED) -# define ORTHANC_SANDBOXED 0 +# error The macro ORTHANC_SANDBOXED must be defined #endif #if ORTHANC_SANDBOXED == 1 # error The class TemporaryFile cannot be used in sandboxed environments #endif -#include "Toolbox.h" +#include <string> namespace Orthanc { @@ -63,14 +61,8 @@ return path_; } - void Write(const std::string& content) - { - SystemToolbox::WriteFile(content, path_); - } + void Write(const std::string& content); - void Read(std::string& content) const - { - SystemToolbox::ReadFile(content, path_); - } + void Read(std::string& content) const; }; }
--- a/Core/Toolbox.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Toolbox.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -36,55 +36,29 @@ #include "OrthancException.h" #include "Logging.h" +#include <boost/algorithm/string/replace.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/locale.hpp> +#include <boost/uuid/sha1.hpp> + #include <string> #include <stdint.h> #include <string.h> -#include <boost/filesystem.hpp> -#include <boost/filesystem/fstream.hpp> -#include <boost/uuid/sha1.hpp> -#include <boost/lexical_cast.hpp> #include <algorithm> #include <ctype.h> -#if BOOST_HAS_DATE_TIME == 1 -#include <boost/date_time/posix_time/posix_time.hpp> -#endif - #if BOOST_HAS_REGEX == 1 -#include <boost/regex.hpp> -#endif - -#if defined(_WIN32) -#include <windows.h> -#include <process.h> // For "_spawnvp()" and "_getpid()" -#else -#include <unistd.h> // For "execvp()" -#include <sys/wait.h> // For "waitpid()" -#endif - -#if defined(__APPLE__) && defined(__MACH__) -#include <mach-o/dyld.h> /* _NSGetExecutablePath */ -#include <limits.h> /* PATH_MAX */ -#endif - -#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) -#include <limits.h> /* PATH_MAX */ -#include <signal.h> -#include <unistd.h> +# include <boost/regex.hpp> #endif #if BOOST_HAS_LOCALE != 1 -#error Since version 0.7.6, Orthanc entirely relies on boost::locale +# error Since version 0.7.6, Orthanc entirely relies on boost::locale #endif -#include <boost/locale.hpp> - - #if ORTHANC_ENABLE_MD5 == 1 # include "../Resources/ThirdParty/md5/md5.h" #endif - #if ORTHANC_ENABLE_BASE64 == 1 # include "../Resources/ThirdParty/base64/base64.h" #endif @@ -110,16 +84,16 @@ extern "C" { #ifdef WIN32 -#include <rpc.h> +# include <rpc.h> #else -#include <uuid/uuid.h> +# include <uuid/uuid.h> #endif } #if ORTHANC_ENABLE_PUGIXML == 1 -#include "ChunkedBuffer.h" -#include <pugixml.hpp> +# include "ChunkedBuffer.h" +# include <pugixml.hpp> #endif @@ -1319,441 +1293,4 @@ return IsUuid(str.substr(0, 36)); } - - -#if ORTHANC_SANDBOXED == 0 - - static bool finish_; - static ServerBarrierEvent barrierEvent_; - -#if defined(_WIN32) - static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) - { - // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx - finish_ = true; - return true; - } -#else - static void SignalHandler(int signal) - { - if (signal == SIGHUP) - { - barrierEvent_ = ServerBarrierEvent_Reload; - } - - finish_ = true; - } -#endif - - - static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) - { -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, true); -#else - signal(SIGINT, SignalHandler); - signal(SIGQUIT, SignalHandler); - signal(SIGTERM, SignalHandler); - signal(SIGHUP, SignalHandler); -#endif - - // Active loop that awakens every 100ms - finish_ = false; - barrierEvent_ = ServerBarrierEvent_Stop; - while (!(*stopFlag || finish_)) - { - Toolbox::USleep(100 * 1000); - } - -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, false); -#else - signal(SIGINT, NULL); - signal(SIGQUIT, NULL); - signal(SIGTERM, NULL); - signal(SIGHUP, NULL); -#endif - - return barrierEvent_; - } - - - ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag) - { - return ServerBarrierInternal(&stopFlag); - } - - - ServerBarrierEvent SystemToolbox::ServerBarrier() - { - const bool stopFlag = false; - return ServerBarrierInternal(&stopFlag); - } - - - static std::streamsize GetStreamSize(std::istream& f) - { - // http://www.cplusplus.com/reference/iostream/istream/tellg/ - f.seekg(0, std::ios::end); - std::streamsize size = f.tellg(); - f.seekg(0, std::ios::beg); - - return size; - } - - - void SystemToolbox::ReadFile(std::string& content, - const std::string& path) - { - if (!IsRegularFile(path)) - { - LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; - throw OrthancException(ErrorCode_RegularFileExpected); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - std::streamsize size = GetStreamSize(f); - content.resize(size); - if (size != 0) - { - f.read(reinterpret_cast<char*>(&content[0]), size); - } - - f.close(); - } - - - bool SystemToolbox::ReadHeader(std::string& header, - const std::string& path, - size_t headerSize) - { - if (!IsRegularFile(path)) - { - LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; - throw OrthancException(ErrorCode_RegularFileExpected); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - bool full = true; - - { - std::streamsize size = GetStreamSize(f); - if (size <= 0) - { - headerSize = 0; - full = false; - } - else if (static_cast<size_t>(size) < headerSize) - { - headerSize = size; // Truncate to the size of the file - full = false; - } - } - - header.resize(headerSize); - if (headerSize != 0) - { - f.read(reinterpret_cast<char*>(&header[0]), headerSize); - } - - f.close(); - - return full; - } - - - void SystemToolbox::WriteFile(const void* content, - size_t size, - const std::string& path) - { - boost::filesystem::ofstream f; - f.open(path, std::ofstream::out | std::ofstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - if (size != 0) - { - f.write(reinterpret_cast<const char*>(content), size); - - if (!f.good()) - { - f.close(); - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - f.close(); - } - - - void SystemToolbox::WriteFile(const std::string& content, - const std::string& path) - { - WriteFile(content.size() > 0 ? content.c_str() : NULL, - content.size(), path); - } - - - void SystemToolbox::RemoveFile(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (IsRegularFile(path)) - { - boost::filesystem::remove(path); - } - else - { - throw OrthancException(ErrorCode_RegularFileExpected); - } - } - } - - - uint64_t SystemToolbox::GetFileSize(const std::string& path) - { - try - { - return static_cast<uint64_t>(boost::filesystem::file_size(path)); - } - catch (boost::filesystem::filesystem_error&) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } - - - void SystemToolbox::MakeDirectory(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (!boost::filesystem::is_directory(path)) - { - throw OrthancException(ErrorCode_DirectoryOverFile); - } - } - else - { - if (!boost::filesystem::create_directories(path)) - { - throw OrthancException(ErrorCode_MakeDirectory); - } - } - } - - - bool SystemToolbox::IsExistingFile(const std::string& path) - { - return boost::filesystem::exists(path); - } - - -#if defined(_WIN32) - static std::string GetPathToExecutableInternal() - { - // Yes, this is ugly, but there is no simple way to get the - // required buffer size, so we use a big constant - std::vector<char> buffer(32768); - /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1)); - return std::string(&buffer[0]); - } - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) - static std::string GetPathToExecutableInternal() - { - std::vector<char> buffer(PATH_MAX + 1); - ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); - if (bytes == 0) - { - throw OrthancException(ErrorCode_PathToExecutable); - } - - return std::string(&buffer[0]); - } - -#elif defined(__APPLE__) && defined(__MACH__) - static std::string GetPathToExecutableInternal() - { - char pathbuf[PATH_MAX + 1]; - unsigned int bufsize = static_cast<int>(sizeof(pathbuf)); - - _NSGetExecutablePath( pathbuf, &bufsize); - - return std::string(pathbuf); - } - -#else -#error Support your platform here -#endif - - - std::string SystemToolbox::GetPathToExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p).string(); - } - - - std::string SystemToolbox::GetDirectoryOfExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p.parent_path()).string(); - } - - - void SystemToolbox::ExecuteSystemCommand(const std::string& command, - const std::vector<std::string>& arguments) - { - // Convert the arguments as a C array - std::vector<char*> args(arguments.size() + 2); - - args.front() = const_cast<char*>(command.c_str()); - - for (size_t i = 0; i < arguments.size(); i++) - { - args[i + 1] = const_cast<char*>(arguments[i].c_str()); - } - - args.back() = NULL; - - int status; - -#if defined(_WIN32) - // http://msdn.microsoft.com/en-us/library/275khfab.aspx - status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); - -#else - int pid = fork(); - - if (pid == -1) - { - // Error in fork() -#if ORTHANC_ENABLE_LOGGING == 1 - LOG(ERROR) << "Cannot fork a child process"; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - else if (pid == 0) - { - // Execute the system command in the child process - execvp(command.c_str(), &args[0]); - - // We should never get here - _exit(1); - } - else - { - // Wait for the system command to exit - waitpid(pid, &status, 0); - } -#endif - - if (status != 0) - { -#if ORTHANC_ENABLE_LOGGING == 1 - LOG(ERROR) << "System command failed with status code " << status; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - } - - - int SystemToolbox::GetProcessId() - { -#if defined(_WIN32) - return static_cast<int>(_getpid()); -#else - return static_cast<int>(getpid()); -#endif - } - - - bool SystemToolbox::IsRegularFile(const std::string& path) - { - namespace fs = boost::filesystem; - - try - { - if (fs::exists(path)) - { - fs::file_status status = fs::status(path); - return (status.type() == boost::filesystem::regular_file || - status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 - } - } - catch (fs::filesystem_error&) - { - } - - return false; - } - - - FILE* SystemToolbox::OpenFile(const std::string& path, - FileMode mode) - { -#if defined(_WIN32) - // TODO Deal with special characters by converting to the current locale -#endif - - const char* m; - switch (mode) - { - case FileMode_ReadBinary: - m = "rb"; - break; - - case FileMode_WriteBinary: - m = "wb"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - return fopen(path.c_str(), m); - } - - -#if BOOST_HAS_DATE_TIME == 1 - std::string SystemToolbox::GetNowIsoString() - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - return boost::posix_time::to_iso_string(now); - } - - void SystemToolbox::GetNowDicom(std::string& date, - std::string& time) - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - tm tm = boost::posix_time::to_tm(now); - - char s[32]; - sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - date.assign(s); - - // TODO milliseconds - sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - time.assign(s); - } -#endif - - -#endif /* ORTHANC_SANDBOXED */ }
--- a/Core/Toolbox.h Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/Toolbox.h Wed Nov 09 16:54:23 2016 +0100 @@ -56,10 +56,6 @@ # error The macro BOOST_HAS_REGEX must be defined #endif -#if !defined(ORTHANC_SANDBOXED) -# define ORTHANC_SANDBOXED 0 -#endif - /** * NOTE: GUID vs. UUID @@ -214,57 +210,4 @@ bool StartsWithUuid(const std::string& str); } - - -#if ORTHANC_SANDBOXED == 0 - namespace SystemToolbox - { - ServerBarrierEvent ServerBarrier(const bool& stopFlag); - - ServerBarrierEvent ServerBarrier(); - - void ReadFile(std::string& content, - const std::string& path); - - bool ReadHeader(std::string& header, - const std::string& path, - size_t headerSize); - - void WriteFile(const void* content, - size_t size, - const std::string& path); - - void WriteFile(const std::string& content, - const std::string& path); - - void RemoveFile(const std::string& path); - - uint64_t GetFileSize(const std::string& path); - - void MakeDirectory(const std::string& path); - - bool IsExistingFile(const std::string& path); - - std::string GetPathToExecutable(); - - std::string GetDirectoryOfExecutable(); - - void ExecuteSystemCommand(const std::string& command, - const std::vector<std::string>& arguments); - - int GetProcessId(); - - bool IsRegularFile(const std::string& path); - - FILE* OpenFile(const std::string& path, - FileMode mode); - -#if BOOST_HAS_DATE_TIME == 1 - std::string GetNowIsoString(); - - void GetNowDicom(std::string& date, - std::string& time); -#endif - } -#endif /* ORTHANC_SANDBOXED */ }
--- a/Core/WebServiceParameters.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Core/WebServiceParameters.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -34,6 +34,7 @@ #include "WebServiceParameters.h" #include "../Core/Logging.h" +#include "../Core/SystemToolbox.h" #include "../Core/Toolbox.h" #include "../Core/OrthancException.h"
--- a/OrthancServer/DicomDirWriter.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/OrthancServer/DicomDirWriter.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -106,6 +106,8 @@ #include "../Core/Logging.h" #include "../Core/OrthancException.h" #include "../Core/TemporaryFile.h" +#include "../Core/Toolbox.h" +#include "../Core/SystemToolbox.h" #include <dcmtk/dcmdata/dcdicdir.h> #include <dcmtk/dcmdata/dcmetinf.h>
--- a/OrthancServer/FromDcmtkBridge.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -118,7 +118,7 @@ std::string content; EmbeddedResources::GetFileResource(content, resource); - Toolbox::TemporaryFile tmp; + TemporaryFile tmp; tmp.Write(content); if (!dictionary.loadDictionary(tmp.GetPath().c_str())) @@ -144,7 +144,6 @@ throw OrthancException(ErrorCode_InternalError); } } - #endif
--- a/OrthancServer/ServerIndexChange.h Wed Nov 09 16:26:40 2016 +0100 +++ b/OrthancServer/ServerIndexChange.h Wed Nov 09 16:54:23 2016 +0100 @@ -34,7 +34,7 @@ #include "ServerEnumerations.h" #include "../Core/IDynamicObject.h" -#include "../Core/Toolbox.h" +#include "../Core/SystemToolbox.h" #include <string> #include <json/value.h>
--- a/Resources/CMake/BoostConfiguration.cmake Wed Nov 09 16:26:40 2016 +0100 +++ b/Resources/CMake/BoostConfiguration.cmake Wed Nov 09 16:54:23 2016 +0100 @@ -125,10 +125,11 @@ add_definitions( -DBOOST_HAS_FILESYSTEM_V3=0 -D__INTEGRITY=1 - -DORTHANC_SANDBOXED=1 ) else() - add_definitions(-DBOOST_HAS_FILESYSTEM_V3=1) + add_definitions( + -DBOOST_HAS_FILESYSTEM_V3=1 + ) list(APPEND BOOST_SOURCES ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
--- a/Resources/Samples/Tools/RecoverCompressedFile.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/Resources/Samples/Tools/RecoverCompressedFile.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -19,7 +19,7 @@ #include "../../../Core/Compression/ZlibCompressor.h" -#include "../../../Core/Toolbox.h" +#include "../../../Core/SystemToolbox.h" #include "../../../Core/OrthancException.h" #include <stdio.h>
--- a/UnitTestsSources/MultiThreadingTests.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/UnitTestsSources/MultiThreadingTests.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -35,6 +35,7 @@ #include "../OrthancServer/Scheduler/ServerScheduler.h" #include "../Core/OrthancException.h" +#include "../Core/SystemToolbox.h" #include "../Core/Toolbox.h" #include "../Core/MultiThreading/Locker.h" #include "../Core/MultiThreading/Mutex.h"
--- a/UnitTestsSources/RestApiTests.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/UnitTestsSources/RestApiTests.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -40,6 +40,7 @@ #include "../Core/ChunkedBuffer.h" #include "../Core/HttpClient.h" #include "../Core/Logging.h" +#include "../Core/SystemToolbox.h" #include "../Core/RestApi/RestApi.h" #include "../Core/OrthancException.h" #include "../Core/Compression/ZlibCompressor.h"
--- a/UnitTestsSources/SQLiteTests.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/UnitTestsSources/SQLiteTests.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -33,7 +33,7 @@ #include "PrecompiledHeadersUnitTests.h" #include "gtest/gtest.h" -#include "../Core/Toolbox.h" +#include "../Core/SystemToolbox.h" #include "../Core/SQLite/Connection.h" #include "../Core/SQLite/Statement.h" #include "../Core/SQLite/Transaction.h"
--- a/UnitTestsSources/StreamTests.cpp Wed Nov 09 16:26:40 2016 +0100 +++ b/UnitTestsSources/StreamTests.cpp Wed Nov 09 16:54:23 2016 +0100 @@ -33,6 +33,7 @@ #include "PrecompiledHeadersUnitTests.h" #include "gtest/gtest.h" +#include "../Core/SystemToolbox.h" #include "../Core/Toolbox.h" #include "../Core/OrthancException.h" #include "../Core/HttpServer/BufferHttpSender.h"