Mercurial > hg > orthanc
annotate OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp @ 4231:290ffcb0a147
publishing the DICOM hierarchy as WebDAV bucket
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 06 Oct 2020 20:55:16 +0200 |
parents | b289a1234822 |
children | 0034f855c023 |
rev | line source |
---|---|
0 | 1 /** |
59 | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1250
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
3640
94f4a18a79cc
upgrade to year 2020
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
8 * modify it under the terms of the GNU Lesser General Public License |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
9 * as published by the Free Software Foundation, either version 3 of |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
10 * the License, or (at your option) any later version. |
136 | 11 * |
0 | 12 * This program is distributed in the hope that it will be useful, but |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
15 * Lesser General Public License for more details. |
0 | 16 * |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
17 * You should have received a copy of the GNU Lesser General Public |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
18 * License along with this program. If not, see |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
19 * <http://www.gnu.org/licenses/>. |
0 | 20 **/ |
21 | |
22 | |
824
a811bdf8b8eb
precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
803
diff
changeset
|
23 #include "../PrecompiledHeaders.h" |
1123 | 24 #include "FilesystemStorage.h" |
0 | 25 |
26 // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system | |
27 // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images | |
28 | |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1397
diff
changeset
|
29 #include "../Logging.h" |
234 | 30 #include "../OrthancException.h" |
31 #include "../Toolbox.h" | |
2143
fd5875662670
creation of namespace SystemToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2142
diff
changeset
|
32 #include "../SystemToolbox.h" |
0 | 33 |
34 #include <boost/filesystem/fstream.hpp> | |
1397 | 35 |
0 | 36 |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
37 static std::string ToString(const boost::filesystem::path& p) |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
38 { |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
39 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
40 return p.filename().string(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
41 #else |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
42 return p.filename(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
43 #endif |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
44 } |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
45 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
46 |
59 | 47 namespace Orthanc |
0 | 48 { |
1123 | 49 boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const |
0 | 50 { |
51 namespace fs = boost::filesystem; | |
52 | |
53 if (!Toolbox::IsUuid(uuid)) | |
54 { | |
59 | 55 throw OrthancException(ErrorCode_ParameterOutOfRange); |
0 | 56 } |
57 | |
58 fs::path path = root_; | |
59 | |
60 path /= std::string(&uuid[0], &uuid[2]); | |
61 path /= std::string(&uuid[2], &uuid[4]); | |
62 path /= uuid; | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
63 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
64 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
0 | 65 path.make_preferred(); |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
66 #endif |
0 | 67 |
68 return path; | |
69 } | |
70 | |
4185
b289a1234822
giving a try to cross-platform compilation of SyncStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4119
diff
changeset
|
71 void FilesystemStorage::Setup(const std::string& root) |
0 | 72 { |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
73 //root_ = boost::filesystem::absolute(root).string(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
74 root_ = root; |
0 | 75 |
2140 | 76 SystemToolbox::MakeDirectory(root); |
0 | 77 } |
78 | |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
79 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
80 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
81 static const char* GetDescriptionInternal(FileContentType content) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
82 { |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
83 // This function is for logging only (internal use), a more |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
84 // fully-featured version is available in ServerEnumerations.cpp |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
85 switch (content) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
86 { |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
87 case FileContentType_Unknown: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
88 return "Unknown"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
89 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
90 case FileContentType_Dicom: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
91 return "DICOM"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
92 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
93 case FileContentType_DicomAsJson: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
94 return "JSON summary of DICOM"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
95 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
96 default: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
97 return "User-defined"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
98 } |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
99 } |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
100 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
101 |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
102 void FilesystemStorage::Create(const std::string& uuid, |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
103 const void* content, |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
104 size_t size, |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
105 FileContentType type) |
0 | 106 { |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
107 LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
108 << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
109 |
0 | 110 boost::filesystem::path path; |
111 | |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
112 path = GetPath(uuid); |
0 | 113 |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
114 if (boost::filesystem::exists(path)) |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
115 { |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
116 // Extremely unlikely case: This Uuid has already been created |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
117 // in the past. |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
118 throw OrthancException(ErrorCode_InternalError); |
0 | 119 } |
120 | |
121 if (boost::filesystem::exists(path.parent_path())) | |
122 { | |
123 if (!boost::filesystem::is_directory(path.parent_path())) | |
124 { | |
1582
bd1889029cbb
encoding of exceptions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1487
diff
changeset
|
125 throw OrthancException(ErrorCode_DirectoryOverFile); |
0 | 126 } |
127 } | |
128 else | |
129 { | |
130 if (!boost::filesystem::create_directories(path.parent_path())) | |
131 { | |
1582
bd1889029cbb
encoding of exceptions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1487
diff
changeset
|
132 throw OrthancException(ErrorCode_FileStorageCannotWrite); |
0 | 133 } |
134 } | |
135 | |
4185
b289a1234822
giving a try to cross-platform compilation of SyncStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4119
diff
changeset
|
136 SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); |
0 | 137 } |
138 | |
139 | |
1123 | 140 void FilesystemStorage::Read(std::string& content, |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
141 const std::string& uuid, |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
142 FileContentType type) |
0 | 143 { |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
144 LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
145 << "\" content type"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
146 |
0 | 147 content.clear(); |
2140 | 148 SystemToolbox::ReadFile(content, GetPath(uuid).string()); |
0 | 149 } |
150 | |
151 | |
1123 | 152 uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const |
0 | 153 { |
154 boost::filesystem::path path = GetPath(uuid); | |
155 return boost::filesystem::file_size(path); | |
156 } | |
157 | |
158 | |
159 | |
1123 | 160 void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const |
0 | 161 { |
162 namespace fs = boost::filesystem; | |
163 | |
164 result.clear(); | |
165 | |
166 if (fs::exists(root_) && fs::is_directory(root_)) | |
167 { | |
168 for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) | |
169 { | |
2140 | 170 if (SystemToolbox::IsRegularFile(current->path().string())) |
0 | 171 { |
172 try | |
173 { | |
174 fs::path d = current->path(); | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
175 std::string uuid = ToString(d); |
0 | 176 if (Toolbox::IsUuid(uuid)) |
177 { | |
178 fs::path p0 = d.parent_path().parent_path().parent_path(); | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
179 std::string p1 = ToString(d.parent_path().parent_path()); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
180 std::string p2 = ToString(d.parent_path()); |
0 | 181 if (p1.length() == 2 && |
182 p2.length() == 2 && | |
183 p1 == uuid.substr(0, 2) && | |
184 p2 == uuid.substr(2, 2) && | |
185 p0 == root_) | |
186 { | |
187 result.insert(uuid); | |
188 } | |
189 } | |
190 } | |
2836
7133ad478eea
fix Debian warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
191 catch (fs::filesystem_error&) |
0 | 192 { |
193 } | |
194 } | |
195 } | |
196 } | |
197 } | |
198 | |
199 | |
1123 | 200 void FilesystemStorage::Clear() |
0 | 201 { |
202 namespace fs = boost::filesystem; | |
203 typedef std::set<std::string> List; | |
204 | |
205 List result; | |
206 ListAllFiles(result); | |
207 | |
656 | 208 for (List::const_iterator it = result.begin(); it != result.end(); ++it) |
0 | 209 { |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
210 Remove(*it, FileContentType_Unknown /*ignored in this class*/); |
0 | 211 } |
212 } | |
213 | |
214 | |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
215 void FilesystemStorage::Remove(const std::string& uuid, |
2129
0c09d1af22f3
"/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2087
diff
changeset
|
216 FileContentType type) |
0 | 217 { |
2129
0c09d1af22f3
"/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2087
diff
changeset
|
218 LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type); |
1397 | 219 |
0 | 220 namespace fs = boost::filesystem; |
221 | |
222 fs::path p = GetPath(uuid); | |
147 | 223 |
224 try | |
225 { | |
226 fs::remove(p); | |
227 } | |
148 | 228 catch (...) |
147 | 229 { |
230 // Ignore the error | |
231 } | |
0 | 232 |
233 // Remove the two parent directories, ignoring the error code if | |
234 // these directories are not empty | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
235 |
142 | 236 try |
237 { | |
147 | 238 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
239 boost::system::error_code err; | |
240 fs::remove(p.parent_path(), err); | |
241 fs::remove(p.parent_path().parent_path(), err); | |
242 #else | |
243 fs::remove(p.parent_path()); | |
244 fs::remove(p.parent_path().parent_path()); | |
245 #endif | |
142 | 246 } |
148 | 247 catch (...) |
142 | 248 { |
249 // Ignore the error | |
250 } | |
251 } | |
252 | |
253 | |
1123 | 254 uintmax_t FilesystemStorage::GetCapacity() const |
0 | 255 { |
256 return boost::filesystem::space(root_).capacity; | |
257 } | |
258 | |
1123 | 259 uintmax_t FilesystemStorage::GetAvailableSpace() const |
0 | 260 { |
261 return boost::filesystem::space(root_).available; | |
262 } | |
263 } |