comparison Core/FileStorage/FileStorage.cpp @ 234:7c1faef915a4

cleaning room
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 30 Nov 2012 14:34:42 +0100
parents Core/FileStorage.cpp@bee20e978835
children bdd72233b105
comparison
equal deleted inserted replaced
233:c11273198cef 234:7c1faef915a4
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012 Medical Physics Department, CHU of Liege,
4 * Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "FileStorage.h"
34
35 // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system
36 // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images
37
38 #include "../OrthancException.h"
39 #include "../Toolbox.h"
40 #include "../Uuid.h"
41
42 #include <boost/filesystem/fstream.hpp>
43 #include <glog/logging.h>
44
45 static std::string ToString(const boost::filesystem::path& p)
46 {
47 #if BOOST_HAS_FILESYSTEM_V3 == 1
48 return p.filename().string();
49 #else
50 return p.filename();
51 #endif
52 }
53
54
55 namespace Orthanc
56 {
57 boost::filesystem::path FileStorage::GetPath(const std::string& uuid) const
58 {
59 namespace fs = boost::filesystem;
60
61 if (!Toolbox::IsUuid(uuid))
62 {
63 throw OrthancException(ErrorCode_ParameterOutOfRange);
64 }
65
66 fs::path path = root_;
67
68 path /= std::string(&uuid[0], &uuid[2]);
69 path /= std::string(&uuid[2], &uuid[4]);
70 path /= uuid;
71
72 #if BOOST_HAS_FILESYSTEM_V3 == 1
73 path.make_preferred();
74 #endif
75
76 return path;
77 }
78
79 FileStorage::FileStorage(std::string root)
80 {
81 namespace fs = boost::filesystem;
82
83 //root_ = boost::filesystem::absolute(root).string();
84 root_ = root;
85
86 if (fs::exists(root))
87 {
88 if (!fs::is_directory(root))
89 {
90 throw OrthancException("The file storage root directory is a file");
91 }
92 }
93 else
94 {
95 if (!fs::create_directories(root))
96 {
97 throw OrthancException("Unable to create the file storage root directory");
98 }
99 }
100 }
101
102 std::string FileStorage::CreateFileWithoutCompression(const void* content, size_t size)
103 {
104 std::string uuid;
105 boost::filesystem::path path;
106
107 for (;;)
108 {
109 uuid = Toolbox::GenerateUuid();
110 path = GetPath(uuid);
111
112 if (!boost::filesystem::exists(path))
113 {
114 // OK, this is indeed a new file
115 break;
116 }
117
118 // Extremely improbable case: This Uuid has already been created
119 // in the past. Try again.
120 }
121
122 if (boost::filesystem::exists(path.parent_path()))
123 {
124 if (!boost::filesystem::is_directory(path.parent_path()))
125 {
126 throw OrthancException("The subdirectory to be created is already occupied by a regular file");
127 }
128 }
129 else
130 {
131 if (!boost::filesystem::create_directories(path.parent_path()))
132 {
133 throw OrthancException("Unable to create a subdirectory in the file storage");
134 }
135 }
136
137 boost::filesystem::ofstream f;
138 f.open(path, std::ofstream::out | std::ios::binary);
139 if (!f.good())
140 {
141 throw OrthancException("Unable to create a new file in the file storage");
142 }
143
144 if (size != 0)
145 {
146 f.write(static_cast<const char*>(content), size);
147 if (!f.good())
148 {
149 f.close();
150 throw OrthancException("Unable to write to the new file in the file storage");
151 }
152 }
153
154 f.close();
155
156 return uuid;
157 }
158
159
160 std::string FileStorage::Create(const void* content, size_t size)
161 {
162 if (!HasBufferCompressor() || size == 0)
163 {
164 return CreateFileWithoutCompression(content, size);
165 }
166 else
167 {
168 std::string compressed;
169 compressor_->Compress(compressed, content, size);
170 assert(compressed.size() > 0);
171 return CreateFileWithoutCompression(&compressed[0], compressed.size());
172 }
173 }
174
175
176 std::string FileStorage::Create(const std::vector<uint8_t>& content)
177 {
178 if (content.size() == 0)
179 return Create(NULL, 0);
180 else
181 return Create(&content[0], content.size());
182 }
183
184 std::string FileStorage::Create(const std::string& content)
185 {
186 if (content.size() == 0)
187 return Create(NULL, 0);
188 else
189 return Create(&content[0], content.size());
190 }
191
192 void FileStorage::ReadFile(std::string& content,
193 const std::string& uuid) const
194 {
195 content.clear();
196
197 if (HasBufferCompressor())
198 {
199 std::string compressed;
200 Toolbox::ReadFile(compressed, ToString(GetPath(uuid)));
201
202 if (compressed.size() != 0)
203 {
204 compressor_->Uncompress(content, compressed);
205 }
206 }
207 else
208 {
209 Toolbox::ReadFile(content, GetPath(uuid).string());
210 }
211 }
212
213
214 uintmax_t FileStorage::GetCompressedSize(const std::string& uuid) const
215 {
216 boost::filesystem::path path = GetPath(uuid);
217 return boost::filesystem::file_size(path);
218 }
219
220
221
222 void FileStorage::ListAllFiles(std::set<std::string>& result) const
223 {
224 namespace fs = boost::filesystem;
225
226 result.clear();
227
228 if (fs::exists(root_) && fs::is_directory(root_))
229 {
230 for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current)
231 {
232 if (fs::is_regular_file(current->status()))
233 {
234 try
235 {
236 fs::path d = current->path();
237 std::string uuid = ToString(d);
238 if (Toolbox::IsUuid(uuid))
239 {
240 fs::path p0 = d.parent_path().parent_path().parent_path();
241 std::string p1 = ToString(d.parent_path().parent_path());
242 std::string p2 = ToString(d.parent_path());
243 if (p1.length() == 2 &&
244 p2.length() == 2 &&
245 p1 == uuid.substr(0, 2) &&
246 p2 == uuid.substr(2, 2) &&
247 p0 == root_)
248 {
249 result.insert(uuid);
250 }
251 }
252 }
253 catch (fs::filesystem_error)
254 {
255 }
256 }
257 }
258 }
259 }
260
261
262 void FileStorage::Clear()
263 {
264 namespace fs = boost::filesystem;
265 typedef std::set<std::string> List;
266
267 List result;
268 ListAllFiles(result);
269
270 for (List::const_iterator it = result.begin(); it != result.end(); it++)
271 {
272 Remove(*it);
273 }
274 }
275
276
277 void FileStorage::Remove(const std::string& uuid)
278 {
279 LOG(INFO) << "Deleting file " << uuid;
280 namespace fs = boost::filesystem;
281
282 fs::path p = GetPath(uuid);
283
284 try
285 {
286 fs::remove(p);
287 }
288 catch (...)
289 {
290 // Ignore the error
291 }
292
293 // Remove the two parent directories, ignoring the error code if
294 // these directories are not empty
295
296 try
297 {
298 #if BOOST_HAS_FILESYSTEM_V3 == 1
299 boost::system::error_code err;
300 fs::remove(p.parent_path(), err);
301 fs::remove(p.parent_path().parent_path(), err);
302 #else
303 fs::remove(p.parent_path());
304 fs::remove(p.parent_path().parent_path());
305 #endif
306 }
307 catch (...)
308 {
309 // Ignore the error
310 }
311 }
312
313
314 uintmax_t FileStorage::GetCapacity() const
315 {
316 return boost::filesystem::space(root_).capacity;
317 }
318
319 uintmax_t FileStorage::GetAvailableSpace() const
320 {
321 return boost::filesystem::space(root_).available;
322 }
323 }