added some precautionary checks in bdecoder
[libtorrent.git] / src / mapped_storage.cpp
blobe5cf4647a7fe56fbe1717dd2da4c8d73bc1eb332
1 /*
3 Copyright (c) 2007, Arvid Norberg, Daniel Wallin
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include "libtorrent/pch.hpp"
35 #include "libtorrent/storage.hpp"
36 #include "libtorrent/size_type.hpp"
37 #include "libtorrent/file.hpp"
38 #include <set>
40 #ifdef _MSC_VER
41 #pragma warning(push, 1)
42 #endif
44 #include <boost/iostreams/device/mapped_file.hpp>
45 #include <boost/filesystem/path.hpp>
46 #include <boost/filesystem/operations.hpp>
47 #include <boost/utility.hpp>
48 #include <boost/bind.hpp>
49 #include <boost/lexical_cast.hpp>
50 #if BOOST_VERSION >= 103500
51 #include <boost/system/error_code.hpp>
52 #endif
54 #include <boost/version.hpp>
56 #ifdef _MSC_VER
57 #pragma warning(pop)
58 #endif
60 using boost::iostreams::mapped_file;
61 using boost::iostreams::mapped_file_params;
63 namespace libtorrent
65 namespace fs = boost::filesystem;
66 #if BOOST_VERSION >= 103500
67 typedef boost::system::error_code ec_t;
68 #else
69 typedef error_code ec_t;
70 #endif
72 struct mapped_file_pool
74 mapped_file_pool(int size = 40): m_size(size) {}
76 private:
78 enum { view_size = 100 * 1024 * 1024 };
79 int m_size;
81 struct file_entry
83 file_entry() : key(0), references(0) {}
84 bool open(fs::path const& path, std::ios::openmode openmode
85 , size_type start, size_type size, void* key_, size_type file_size = 0)
87 #ifndef NDEBUG
88 if (file_size > 0)
90 ec_t ec;
91 fs::file_status st = fs::status(path, ec);
92 TORRENT_ASSERT(!fs::exists(st));
94 #endif
95 key = key_;
96 last_use = time_now();
97 params.path = path.string();
98 params.mode = openmode;
99 params.offset = start;
100 params.length = size;
101 params.new_file_size = file_size;
102 file.open(params);
103 return file.is_open();
105 mapped_file_params params;
106 mapped_file file;
107 void* key;
108 ptime last_use;
109 int references;
112 typedef std::list<file_entry> files_t;
113 files_t m_files;
115 public:
117 struct file_view
119 explicit file_view(file_entry* e): m_entry(e) { ++m_entry->references; }
120 file_view(): m_entry(0) {}
121 file_view(file_view const& f): m_entry(f.m_entry)
122 { if (m_entry) ++m_entry->references; }
123 ~file_view()
125 TORRENT_ASSERT(m_entry == 0 || m_entry->references > 0);
126 if (m_entry) --m_entry->references;
128 file_view& operator=(file_view const& v)
130 TORRENT_ASSERT(m_entry == 0 || m_entry->references > 0);
131 if (m_entry) --m_entry->references;
132 m_entry = v.m_entry;
133 if (m_entry) ++m_entry->references;
134 return *this;
137 bool valid() const { return m_entry && m_entry->file.const_data(); }
139 char* addr() const
141 TORRENT_ASSERT(m_entry);
142 return m_entry->file.data();
145 char const* const_addr() const
147 TORRENT_ASSERT(m_entry);
148 return m_entry->file.const_data();
151 size_type offset() const
153 TORRENT_ASSERT(m_entry);
154 return m_entry->params.offset;
157 size_type size() const
159 TORRENT_ASSERT(m_entry);
160 return m_entry->params.length;
163 private:
164 file_entry* m_entry;
167 file_view open_file(fs::path const& p, std::ios::openmode mode
168 , size_type offset, size_type length, void* key
169 , size_type file_size)
171 TORRENT_ASSERT(file_size > 0);
172 files_t::iterator min = m_files.end();
173 for (std::list<file_entry>::iterator i = m_files.begin()
174 , end(m_files.end()); i != end; ++i)
176 if (i->params.path == p.string()
177 && i->params.offset <= offset
178 && i->params.offset + i->params.length >= offset + length)
180 if (i->key != key) return file_view();
181 if ((mode & std::ios::out) && (i->params.mode & std::ios::out) == 0)
183 TORRENT_ASSERT(i->references == 0);
184 i->file.close();
185 m_files.erase(i);
186 min = m_files.end();
187 break;
189 i->last_use = time_now();
190 return file_view(&(*i));
192 if ((min == m_files.end() || i->last_use < min->last_use)
193 && i->references == 0)
195 min = i;
199 if (int(m_files.size()) >= m_size && min != m_files.end())
201 TORRENT_ASSERT(min->references == 0);
202 min->file.close();
203 m_files.erase(min);
206 size_type start = (offset / view_size) * view_size;
207 TORRENT_ASSERT(start + view_size >= offset + length);
209 #if BOOST_VERSION < 103500
210 fs::system_error_type ec;
211 #else
212 ec_t ec;
213 #endif
214 fs::file_status st = fs::status(p, ec);
216 m_files.push_back(file_entry());
217 bool ret = false;
218 if (!exists(st))
220 ret = m_files.back().open(p, mode | std::ios::out, start, view_size, key, file_size);
222 else
224 if (is_directory(st)) return file_view();
225 size_type s = fs::file_size(p);
226 #ifdef WIN32
227 // TODO: SetFileSize()
228 if (s < file_size) {}
229 #else
230 if (s < file_size) truncate(p.string().c_str(), file_size);
231 #endif
232 ret = m_files.back().open(p, mode, start, view_size, key);
236 if (!ret)
238 m_files.erase(boost::prior(m_files.end()));
239 return file_view();
241 return file_view(&m_files.back());
244 void release(void* key)
246 for (std::list<file_entry>::iterator i = m_files.begin();
247 !m_files.empty() && i != m_files.end();)
249 if (i->key == key)
251 TORRENT_ASSERT(i->references == 0);
252 i->file.close();
253 m_files.erase(i++);
254 continue;
256 ++i;
263 struct mapped_storage: storage_interface
265 mapped_storage(file_storage const& fs, fs::path save_path)
266 : m_files(fs)
267 , m_save_path(save_path)
270 bool initialize(bool allocate_files) { return false; }
272 int read(char* buf, int slot, int offset, int size)
274 TORRENT_ASSERT(buf != 0);
275 TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
276 TORRENT_ASSERT(offset >= 0);
277 TORRENT_ASSERT(offset < m_files.piece_size(slot));
278 TORRENT_ASSERT(size > 0);
280 size_type result = -1;
284 #ifndef NDEBUG
285 std::vector<file_slice> slices
286 = files().map_block(slot, offset, size);
287 TORRENT_ASSERT(!slices.empty());
288 #endif
289 size_type start = slot * (size_type)m_files.piece_length() + offset;
290 TORRENT_ASSERT(start + size <= m_files.total_size());
292 // find the file iterator and file offset
293 size_type file_offset = start;
294 std::vector<file_entry>::const_iterator file_iter;
296 for (file_iter = files().begin();;)
298 if (file_offset < file_iter->size)
299 break;
301 file_offset -= file_iter->size;
302 ++file_iter;
305 TORRENT_ASSERT(file_iter->size > 0);
306 mapped_file_pool::file_view view = m_pool.open_file(
307 m_save_path / file_iter->path, std::ios::in
308 , file_offset + file_iter->file_base, size, this
309 , file_iter->size + file_iter->file_base);
311 if (!view.valid())
313 set_error((m_save_path / file_iter->path).string(), "failed to open file for reading");
314 return -1;
316 TORRENT_ASSERT(view.const_addr() != 0);
318 int left_to_read = size;
319 int buf_pos = 0;
320 result = left_to_read;
321 #ifndef NDEBUG
322 int counter = 0;
323 #endif
324 while (left_to_read > 0)
326 int read_bytes = left_to_read;
327 if (file_offset + read_bytes > file_iter->size)
328 read_bytes = static_cast<int>(file_iter->size - file_offset);
330 if (read_bytes > 0)
332 #ifndef NDEBUG
333 TORRENT_ASSERT(int(slices.size()) > counter);
334 size_type slice_size = slices[counter].size;
335 TORRENT_ASSERT(slice_size == read_bytes);
336 TORRENT_ASSERT(files().at(slices[counter].file_index).path
337 == file_iter->path);
338 #endif
340 TORRENT_ASSERT(file_offset + file_iter->file_base >= view.offset());
341 TORRENT_ASSERT(view.const_addr() != 0);
342 std::memcpy(buf + buf_pos
343 , view.const_addr() + (file_offset + file_iter->file_base - view.offset())
344 , read_bytes);
346 left_to_read -= read_bytes;
347 buf_pos += read_bytes;
348 TORRENT_ASSERT(buf_pos >= 0);
349 file_offset += read_bytes;
352 if (left_to_read > 0)
354 ++file_iter;
355 // skip empty files
356 while (file_iter != files().end() && file_iter->size == 0)
357 ++file_iter;
359 #ifndef NDEBUG
360 // empty files are not returned by map_block, so if
361 // this file was empty, don't increment the slice counter
362 if (read_bytes > 0) ++counter;
363 #endif
364 fs::path path = m_save_path / file_iter->path;
366 file_offset = 0;
368 view = m_pool.open_file(path, std::ios::in, file_offset + file_iter->file_base
369 , left_to_read, this
370 , file_iter->size + file_iter->file_base);
372 if (!view.valid())
374 set_error((m_save_path / file_iter->path).string(), "failed to open for reading");
375 return -1;
377 TORRENT_ASSERT(view.const_addr() != 0);
381 catch (std::exception& e)
383 set_error("", e.what());
384 return -1;
387 return result;
390 int write(const char* buf, int slot, int offset, int size)
392 TORRENT_ASSERT(buf != 0);
393 TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
394 TORRENT_ASSERT(offset >= 0);
395 TORRENT_ASSERT(offset < m_files.piece_size(slot));
396 TORRENT_ASSERT(size > 0);
398 #ifndef NDEBUG
399 std::vector<file_slice> slices
400 = files().map_block(slot, offset, size);
401 TORRENT_ASSERT(!slices.empty());
402 #endif
403 size_type start = slot * (size_type)m_files.piece_length() + offset;
404 TORRENT_ASSERT(start + size <= m_files.total_size());
406 // find the file iterator and file offset
407 size_type file_offset = start;
408 std::vector<file_entry>::const_iterator file_iter;
410 for (file_iter = files().begin();;)
412 if (file_offset < file_iter->size)
413 break;
415 file_offset -= file_iter->size;
416 ++file_iter;
419 TORRENT_ASSERT(file_iter->size > 0);
423 mapped_file_pool::file_view view = m_pool.open_file(
424 m_save_path / file_iter->path, std::ios::in | std::ios::out
425 , file_offset + file_iter->file_base, size, this
426 , file_iter->size + file_iter->file_base);
428 if (!view.valid())
430 set_error((m_save_path / file_iter->path).string(), "failed to open file for writing");
431 return -1;
433 TORRENT_ASSERT(view.addr() != 0);
435 int left_to_write = size;
436 int buf_pos = 0;
437 #ifndef NDEBUG
438 int counter = 0;
439 #endif
440 while (left_to_write > 0)
442 int write_bytes = left_to_write;
443 if (file_offset + write_bytes > file_iter->size)
444 write_bytes = static_cast<int>(file_iter->size - file_offset);
446 if (write_bytes > 0)
448 #ifndef NDEBUG
449 TORRENT_ASSERT(int(slices.size()) > counter);
450 size_type slice_size = slices[counter].size;
451 TORRENT_ASSERT(slice_size == write_bytes);
452 TORRENT_ASSERT(files().at(slices[counter].file_index).path
453 == file_iter->path);
454 #endif
456 TORRENT_ASSERT(file_offset + file_iter->file_base >= view.offset());
457 TORRENT_ASSERT(view.addr() != 0);
458 std::memcpy(view.addr() + (file_offset + file_iter->file_base - view.offset())
459 , buf + buf_pos
460 , write_bytes);
462 left_to_write -= write_bytes;
463 buf_pos += write_bytes;
464 TORRENT_ASSERT(buf_pos >= 0);
465 file_offset += write_bytes;
468 if (left_to_write > 0)
470 ++file_iter;
471 while (file_iter != files().end() && file_iter->size == 0)
472 ++file_iter;
473 #ifndef NDEBUG
474 // empty files are not returned by map_block, so if
475 // this file was empty, don't increment the slice counter
476 if (write_bytes > 0) ++counter;
477 #endif
478 fs::path path = m_save_path / file_iter->path;
480 file_offset = 0;
481 view = m_pool.open_file(path, std::ios::in | std::ios::out
482 , file_offset + file_iter->file_base, left_to_write, this
483 , file_iter->size + file_iter->file_base);
485 if (!view.valid())
487 set_error((m_save_path / file_iter->path).string(), "failed to open file for reading");
488 return -1;
490 TORRENT_ASSERT(view.addr() != 0);
494 catch (std::exception& e)
496 set_error((m_save_path / file_iter->path).string(), e.what());
497 return -1;
499 return size;
502 bool move_storage(fs::path save_path)
504 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
505 fs::wpath old_path;
506 fs::wpath new_path;
507 #else
508 fs::path old_path;
509 fs::path new_path;
510 #endif
512 save_path = complete(save_path);
514 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
515 std::wstring wsave_path(safe_convert(save_path.native_file_string()));
516 if (!exists_win(save_path))
517 CreateDirectory(wsave_path.c_str(), 0);
518 else if ((GetFileAttributes(wsave_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) == 0)
519 return false;
520 #elif defined(_WIN32) && defined(UNICODE)
521 fs::wpath wp = safe_convert(save_path.string());
522 if (!exists(wp))
523 create_directory(wp);
524 else if (!is_directory(wp))
525 return false;
526 #else
527 if (!exists(save_path))
528 create_directory(save_path);
529 else if (!is_directory(save_path))
530 return false;
531 #endif
533 m_pool.release(this);
535 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
536 old_path = safe_convert((m_save_path / files().name()).string());
537 new_path = safe_convert((save_path / files().name()).string());
538 #else
539 old_path = m_save_path / files().name();
540 new_path = save_path / files().name();
541 #endif
545 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
546 rename_win(old_path, new_path);
547 rename(old_path, new_path);
548 #else
549 rename(old_path, new_path);
550 #endif
551 m_save_path = save_path;
552 return true;
554 catch (std::exception& e)
556 #ifndef NDEBUG
557 std::cerr << "ERROR: " << e.what() << std::endl;
558 #endif
560 return false;
563 bool verify_resume_data(lazy_entry const& rd, std::string& error)
565 if (rd.type() != lazy_entry::dict_t)
567 error = "invalid fastresume file (not a dictionary)";
568 return true;
571 std::vector<std::pair<size_type, std::time_t> > file_sizes;
572 lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
573 if (file_sizes_ent == 0)
575 error = "missing or invalid 'file sizes' entry in resume data";
576 return false;
579 for (int i = 0; i < file_sizes_ent->list_size(); ++i)
581 lazy_entry const* e = file_sizes_ent->list_at(i);
582 if (e->type() != lazy_entry::list_t
583 || e->list_size() != 2
584 || e->list_at(0)->type() != lazy_entry::int_t
585 || e->list_at(1)->type() != lazy_entry::int_t)
586 continue;
587 file_sizes.push_back(std::pair<size_type, std::time_t>(
588 e->list_int_value_at(0), std::time_t(e->list_int_value_at(1))));
591 if (file_sizes.empty())
593 error = "the number of files in resume data is 0";
594 return false;
597 lazy_entry const* slots = rd.dict_find_list("slots");
598 if (slots == 0)
600 error = "missing or invalid 'slots' entry in resume data";
601 return false;
604 bool seed = false;
606 if (int(slots->list_size()) == m_files.num_pieces())
608 bool seed = true;
609 for (int i = 0; i < slots->list_size(); ++i)
611 lazy_entry const* e = slots->list_at(i);
612 if (e->list_int_value_at(i, -1) >= 0) continue;
613 seed = false;
614 break;
618 bool full_allocation_mode = false;
619 if (rd.dict_find_string_value("allocation") == "full")
620 full_allocation_mode = true;
622 if (seed)
624 if (files().num_files() != (int)file_sizes.size())
626 error = "the number of files does not match the torrent (num: "
627 + boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
628 + boost::lexical_cast<std::string>(files().num_files()) + ")";
629 return false;
632 std::vector<std::pair<size_type, std::time_t> >::iterator
633 fs = file_sizes.begin();
634 // the resume data says we have the entire torrent
635 // make sure the file sizes are the right ones
636 for (file_storage::iterator i = files().begin()
637 , end(files().end()); i != end; ++i, ++fs)
639 if (i->size != fs->first)
641 error = "file size for '" + i->path.native_file_string()
642 + "' was expected to be "
643 + boost::lexical_cast<std::string>(i->size) + " bytes";
644 return false;
649 return match_filesizes(files(), m_save_path, file_sizes
650 , !full_allocation_mode, &error);
653 bool write_resume_data(entry& rd) const
655 if (rd.type() != entry::dictionary_t)
657 set_error("", "invalid fastresume file");
658 return true;
660 std::vector<std::pair<size_type, std::time_t> > file_sizes
661 = get_filesizes(m_files, m_save_path);
663 entry::list_type& fl = rd["file sizes"].list();
664 for (std::vector<std::pair<size_type, std::time_t> >::iterator i
665 = file_sizes.begin(), end(file_sizes.end()); i != end; ++i)
667 entry::list_type p;
668 p.push_back(entry(i->first));
669 p.push_back(entry(i->second));
670 fl.push_back(entry(p));
672 return false;
675 bool move_slot(int src_slot, int dst_slot)
677 // TODO: this can be optimized by mapping both slots and do a straight memcpy
678 int piece_size = m_files.piece_size(dst_slot);
679 m_scratch_buffer.resize(piece_size);
680 size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, piece_size);
681 size_type ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
682 return ret1 != piece_size || ret2 != piece_size;
685 bool swap_slots(int slot1, int slot2)
687 // TODO: this can be optimized by mapping both slots and do a straight memcpy
688 // the size of the target slot is the size of the piece
689 int piece_size = m_files.piece_length();
690 int piece1_size = m_files.piece_size(slot2);
691 int piece2_size = m_files.piece_size(slot1);
692 m_scratch_buffer.resize(piece_size * 2);
693 size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
694 size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
695 size_type ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
696 size_type ret4 = write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size);
697 return ret1 != piece1_size || ret2 != piece2_size
698 || ret3 != piece1_size || ret4 != piece2_size;
701 bool swap_slots3(int slot1, int slot2, int slot3)
703 // TODO: this can be optimized by mapping both slots and do a straight memcpy
704 // the size of the target slot is the size of the piece
705 int piece_size = m_files.piece_length();
706 int piece1_size = m_files.piece_size(slot2);
707 int piece2_size = m_files.piece_size(slot3);
708 int piece3_size = m_files.piece_size(slot1);
709 m_scratch_buffer.resize(piece_size * 2);
710 size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
711 size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
712 size_type ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
713 size_type ret4 = read(&m_scratch_buffer[0], slot3, 0, piece3_size);
714 size_type ret5 = write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size);
715 size_type ret6 = write(&m_scratch_buffer[0], slot1, 0, piece3_size);
716 return ret1 != piece1_size || ret2 != piece2_size
717 || ret3 != piece1_size || ret4 != piece3_size
718 || ret5 != piece2_size || ret6 != piece3_size;
721 sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size)
723 #ifndef NDEBUG
724 hasher partial;
725 hasher whole;
726 int slot_size1 = piece_size;
727 m_scratch_buffer.resize(slot_size1);
728 read(&m_scratch_buffer[0], slot, 0, slot_size1);
729 if (ph.offset > 0)
730 partial.update(&m_scratch_buffer[0], ph.offset);
731 whole.update(&m_scratch_buffer[0], slot_size1);
732 hasher partial_copy = ph.h;
733 TORRENT_ASSERT(ph.offset == 0 || partial_copy.final() == partial.final());
734 #endif
735 int slot_size = piece_size - ph.offset;
736 if (slot_size > 0)
738 m_scratch_buffer.resize(slot_size);
739 read(&m_scratch_buffer[0], slot, ph.offset, slot_size);
740 ph.h.update(&m_scratch_buffer[0], slot_size);
742 #ifndef NDEBUG
743 sha1_hash ret = ph.h.final();
744 TORRENT_ASSERT(ret == whole.final());
745 return ret;
746 #else
747 return ph.h.final();
748 #endif
751 bool rename_file(int index, std::string const& new_filename)
753 if (index < 0 || index >= m_files.num_files()) return true;
754 fs::path old_name = m_save_path / files().at(index).path;
755 m_pool.release(this);
757 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
758 fs::wpath old_path = safe_convert(old_name.string());
759 fs::wpath new_path = safe_convert((m_save_path / new_filename).string());
760 #else
761 fs::path const& old_path = old_name;
762 fs::path new_path = m_save_path / new_filename;
763 #endif
765 #ifndef BOOST_NO_EXCEPTIONS
768 #endif
769 rename(old_path, new_path);
770 if (!m_mapped_files)
771 { m_mapped_files.reset(new file_storage(m_files)); }
772 m_mapped_files->rename_file(index, new_filename);
773 #ifndef BOOST_NO_EXCEPTIONS
775 catch (std::exception& e)
777 set_error(old_name.string(), e.what());
778 return true;
780 #endif
781 return false;
784 bool release_files()
786 m_pool.release(this);
787 return false;
790 bool delete_files()
792 // make sure we don't have the files open
793 m_pool.release(this);
794 buffer().swap(m_scratch_buffer);
796 int result = 0;
797 std::string error;
798 std::string error_file;
800 // delete the files from disk
801 std::set<std::string> directories;
802 typedef std::set<std::string>::iterator iter_t;
803 for (file_storage::iterator i = m_files.begin()
804 , end(m_files.end()); i != end; ++i)
806 std::string p = (m_save_path / i->path).string();
807 fs::path bp = i->path.branch_path();
808 std::pair<iter_t, bool> ret;
809 ret.second = true;
810 while (ret.second && !bp.empty())
812 std::pair<iter_t, bool> ret = directories.insert((m_save_path / bp).string());
813 bp = bp.branch_path();
815 if (std::remove(p.c_str()) != 0 && errno != ENOENT)
817 error = std::strerror(errno);
818 error_file = p;
819 result = errno;
823 // remove the directories. Reverse order to delete
824 // subdirectories first
826 for (std::set<std::string>::reverse_iterator i = directories.rbegin()
827 , end(directories.rend()); i != end; ++i)
829 if (std::remove(i->c_str()) != 0 && errno != ENOENT)
831 error = std::strerror(errno);
832 error_file = *i;
833 result = errno;
837 if (!error.empty()) set_error(error_file, error);
838 return result != 0;
841 private:
843 file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
845 boost::scoped_ptr<file_storage> m_mapped_files;
846 file_storage const& m_files;
847 fs::path m_save_path;
849 // temporary storage for moving pieces
850 buffer m_scratch_buffer;
852 static mapped_file_pool m_pool;
855 storage_interface* mapped_storage_constructor(file_storage const& fs
856 , fs::path const& path, file_pool& fp)
858 return new mapped_storage(fs, path);
861 mapped_file_pool mapped_storage::m_pool;