# HG changeset patch # User Alain Mazy # Date 1549040046 -3600 # Node ID 92bbc5274220b0e110d588b132ed8cd119b32e8d # Parent c6dab987f43a236029ed26f52ec183973658aa46# Parent 5d1f5984dc4170c7dfcb239d34de12e92f28994e merge diff -r c6dab987f43a -r 92bbc5274220 Core/Compression/ZipWriter.cpp --- a/Core/Compression/ZipWriter.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/Core/Compression/ZipWriter.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -148,7 +148,8 @@ if (!pimpl_->file_) { - throw OrthancException(ErrorCode_CannotWriteFile); + throw OrthancException(ErrorCode_CannotWriteFile, + "Cannot create new ZIP archive: " + path_); } } @@ -169,7 +170,8 @@ if (level >= 10) { throw OrthancException(ErrorCode_ParameterOutOfRange, - "ZIP compression level must be between 0 (no compression) and 9 (highest compression)"); + "ZIP compression level must be between 0 (no compression) " + "and 9 (highest compression)"); } Close(); @@ -208,7 +210,8 @@ if (result != 0) { - throw OrthancException(ErrorCode_CannotWriteFile); + throw OrthancException(ErrorCode_CannotWriteFile, + "Cannot add new file inside ZIP archive: " + std::string(path)); } hasFileInZip_ = true; @@ -239,7 +242,8 @@ if (zipWriteInFileInZip(pimpl_->file_, data, bytes)) { - throw OrthancException(ErrorCode_CannotWriteFile); + throw OrthancException(ErrorCode_CannotWriteFile, + "Cannot write data to ZIP archive: " + path_); } data += bytes; @@ -253,6 +257,4 @@ Close(); append_ = append; } - - } diff -r c6dab987f43a -r 92bbc5274220 Core/TemporaryFile.cpp --- a/Core/TemporaryFile.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/Core/TemporaryFile.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -34,6 +34,7 @@ #include "PrecompiledHeaders.h" #include "TemporaryFile.h" +#include "OrthancException.h" #include "SystemToolbox.h" #include "Toolbox.h" @@ -41,15 +42,25 @@ namespace Orthanc { - static std::string CreateTemporaryPath(const char* extension) + static std::string CreateTemporaryPath(const char* temporaryDirectory, + const char* extension) { + boost::filesystem::path dir; + + if (temporaryDirectory == NULL) + { #if BOOST_HAS_FILESYSTEM_V3 == 1 - boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path(); + dir = boost::filesystem::temp_directory_path(); #elif defined(__linux__) - boost::filesystem::path tmpDir("/tmp"); + dir = "/tmp"; #else -#error Support your platform here +# error Support your platform here #endif + } + else + { + dir = temporaryDirectory; + } // We use UUID to create unique path to temporary files std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid(); @@ -59,19 +70,20 @@ filename.append(extension); } - tmpDir /= filename; - return tmpDir.string(); + dir /= filename; + return dir.string(); } TemporaryFile::TemporaryFile() : - path_(CreateTemporaryPath(NULL)) + path_(CreateTemporaryPath(NULL, NULL)) { } - TemporaryFile::TemporaryFile(const char* extension) : - path_(CreateTemporaryPath(extension)) + TemporaryFile::TemporaryFile(const std::string& temporaryDirectory, + const std::string& extension) : + path_(CreateTemporaryPath(temporaryDirectory.c_str(), extension.c_str())) { } @@ -84,12 +96,39 @@ void TemporaryFile::Write(const std::string& content) { - SystemToolbox::WriteFile(content, path_); + try + { + SystemToolbox::WriteFile(content, path_); + } + catch (OrthancException& e) + { + throw OrthancException(e.GetErrorCode(), + "Can't create temporary file \"" + path_ + + "\" with " + boost::lexical_cast(content.size()) + + " bytes: Check you have write access to the " + "temporary directory and that it is not full"); + } } void TemporaryFile::Read(std::string& content) const { - SystemToolbox::ReadFile(content, path_); + try + { + SystemToolbox::ReadFile(content, path_); + } + catch (OrthancException& e) + { + throw OrthancException(e.GetErrorCode(), + "Can't read temporary file \"" + path_ + + "\": Another process has corrupted the temporary directory"); + } + } + + + void TemporaryFile::Touch() + { + std::string empty; + Write(empty); } } diff -r c6dab987f43a -r 92bbc5274220 Core/TemporaryFile.h --- a/Core/TemporaryFile.h Fri Feb 01 17:53:40 2019 +0100 +++ b/Core/TemporaryFile.h Fri Feb 01 17:54:06 2019 +0100 @@ -53,7 +53,8 @@ public: TemporaryFile(); - TemporaryFile(const char* extension); + TemporaryFile(const std::string& temporaryFolder, + const std::string& extension); ~TemporaryFile(); @@ -65,5 +66,7 @@ void Write(const std::string& content); void Read(std::string& content) const; + + void Touch(); }; } diff -r c6dab987f43a -r 92bbc5274220 NEWS --- a/NEWS Fri Feb 01 17:53:40 2019 +0100 +++ b/NEWS Fri Feb 01 17:54:06 2019 +0100 @@ -5,8 +5,9 @@ ------- * New configuration options: - - "MetricsEnabled" to track the metrics of Orthanc + - "MetricsEnabled" to enable the tracking of the metrics of Orthanc - "HttpThreadsCount" to set the number of threads in the embedded HTTP server + - "TemporaryDirectory" to set the folder containing the temporary files REST API -------- @@ -18,12 +19,14 @@ Plugins ------- -* New primitives to set and refresh metrics +* New primitives in the plugin SDK to set and refresh metrics Maintenance ----------- +* Fix regression if calling "/tools/find" with the tag "ModalitiesInStudy" * Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()") +* Fix issue #130 (Orthanc failed to start when /tmp partition was full) Version 1.5.3 (2019-01-25) diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/OrthancConfiguration.cpp --- a/OrthancServer/OrthancConfiguration.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/OrthancConfiguration.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -38,6 +38,7 @@ #include "../Core/Logging.h" #include "../Core/OrthancException.h" #include "../Core/SystemToolbox.h" +#include "../Core/TemporaryFile.h" #include "../Core/Toolbox.h" #include "ServerIndex.h" @@ -47,6 +48,7 @@ static const char* const DICOM_MODALITIES_IN_DB = "DicomModalitiesInDatabase"; static const char* const ORTHANC_PEERS = "OrthancPeers"; static const char* const ORTHANC_PEERS_IN_DB = "OrthancPeersInDatabase"; +static const char* const TEMPORARY_DIRECTORY = "TemporaryDirectory"; namespace Orthanc { @@ -826,4 +828,17 @@ { serverIndex_ = NULL; } + + + TemporaryFile* OrthancConfiguration::CreateTemporaryFile() const + { + if (json_.isMember(TEMPORARY_DIRECTORY)) + { + return new TemporaryFile(InterpretStringParameterAsPath(GetStringParameter(TEMPORARY_DIRECTORY, ".")), ""); + } + else + { + return new TemporaryFile; + } + } } diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/OrthancConfiguration.h --- a/OrthancServer/OrthancConfiguration.h Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/OrthancConfiguration.h Fri Feb 01 17:54:06 2019 +0100 @@ -47,6 +47,7 @@ { class HttpServer; class ServerIndex; + class TemporaryFile; class OrthancConfiguration : public boost::noncopyable { @@ -224,5 +225,7 @@ void SetServerIndex(ServerIndex& index); void ResetServerIndex(); + + TemporaryFile* CreateTemporaryFile() const; }; } diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/OrthancRestApi/OrthancRestArchive.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -37,6 +37,7 @@ #include "../../Core/HttpServer/FilesystemHttpSender.h" #include "../../Core/OrthancException.h" #include "../../Core/SerializationToolbox.h" +#include "../OrthancConfiguration.h" #include "../ServerContext.h" #include "../ServerJobs/ArchiveJob.h" @@ -136,7 +137,13 @@ if (synchronous) { - boost::shared_ptr tmp(new TemporaryFile); + boost::shared_ptr tmp; + + { + OrthancConfiguration::ReaderLock lock; + tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + job->SetSynchronousTarget(tmp); Json::Value publicContent; diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/Search/DatabaseLookup.cpp --- a/OrthancServer/Search/DatabaseLookup.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/Search/DatabaseLookup.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -172,7 +172,8 @@ (tag, ConstraintType_SmallerOrEqual, upper, caseSensitive, mandatoryTag)); } } - else if (dicomQuery.find('\\') != std::string::npos) + else if (tag == DICOM_TAG_MODALITIES_IN_STUDY || + dicomQuery.find('\\') != std::string::npos) { DicomTag fixedTag(tag); diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/ServerJobs/ArchiveJob.cpp --- a/OrthancServer/ServerJobs/ArchiveJob.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/ServerJobs/ArchiveJob.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -39,6 +39,7 @@ #include "../../Core/DicomParsing/DicomDirWriter.h" #include "../../Core/Logging.h" #include "../../Core/OrthancException.h" +#include "../OrthancConfiguration.h" #include "../ServerContext.h" #include @@ -867,13 +868,20 @@ if (synchronousTarget_.get() == NULL) { - asynchronousTarget_.reset(new TemporaryFile); + { + OrthancConfiguration::ReaderLock lock; + asynchronousTarget_.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + target = asynchronousTarget_.get(); } else { target = synchronousTarget_.get(); } + + assert(target != NULL); + target->Touch(); // Make sure we can write to the temporary file if (writer_.get() != NULL) { diff -r c6dab987f43a -r 92bbc5274220 OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp --- a/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -43,6 +43,7 @@ #include "../../../Core/TemporaryFile.h" #include "../../../Core/Toolbox.h" #include "../../../Core/SystemToolbox.h" +#include "../../OrthancConfiguration.h" namespace Orthanc { @@ -92,7 +93,11 @@ std::string dicom; instance.ReadDicom(dicom); - tmp.reset(new TemporaryFile); + { + OrthancConfiguration::ReaderLock lock; + tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + tmp->Write(dicom); arguments.push_back(tmp->GetPath()); diff -r c6dab987f43a -r 92bbc5274220 Resources/Configuration.json --- a/Resources/Configuration.json Fri Feb 01 17:53:40 2019 +0100 +++ b/Resources/Configuration.json Fri Feb 01 17:54:06 2019 +0100 @@ -17,6 +17,18 @@ // a RAM-drive or a SSD device for performance reasons. "IndexDirectory" : "OrthancStorage", + // Path to the directory where Orthanc stores its large temporary + // files. The content of this folder can be safely deleted if + // Orthanc once stopped. The folder must exist. The corresponding + // filesystem must be properly sized, given that for instance a ZIP + // archive of DICOM images created by a job can weight several GBs, + // and that there might be up to "min(JobsHistorySize, + // MediaArchiveSize)" archives to be stored simultaneously. If not + // set, Orthanc will use the default temporary folder of the + // operating system (such as "/tmp/" on UNIX-like systems, or + // "C:/Temp" on Microsoft Windows). + // "TemporaryDirectory" : "/tmp/Orthanc/", + // Enable the transparent compression of the DICOM instances "StorageCompression" : false, diff -r c6dab987f43a -r 92bbc5274220 UnitTestsSources/ImageTests.cpp --- a/UnitTestsSources/ImageTests.cpp Fri Feb 01 17:53:40 2019 +0100 +++ b/UnitTestsSources/ImageTests.cpp Fri Feb 01 17:54:06 2019 +0100 @@ -185,7 +185,7 @@ { Orthanc::TemporaryFile tmp; - Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath()); + tmp.Write(s); Orthanc::PngReader r2; r2.ReadFromFile(tmp.GetPath()); @@ -411,7 +411,7 @@ { Orthanc::TemporaryFile tmp; - Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath()); + tmp.Write(s); Orthanc::PamReader r2; r2.ReadFromFile(tmp.GetPath()); @@ -433,4 +433,3 @@ } } } -