improved error reporting of file errors (uses boost.system's error_code). Now permiss...
[libtorrent.git] / src / file_pool.cpp
blobde914c70c00f17c2d93f188afe89c034e2cff0ec
1 /*
3 Copyright (c) 2006, Arvid Norberg
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 <boost/version.hpp>
34 #include "libtorrent/pch.hpp"
35 #include "libtorrent/file_pool.hpp"
36 #include "libtorrent/error_code.hpp"
38 #include <iostream>
40 namespace libtorrent
42 using boost::multi_index::nth_index;
43 using boost::multi_index::get;
45 #if BOOST_VERSION >= 103500
46 struct file_pool_error_category : boost::system::error_category
48 virtual const char* name() const { return "file pool error"; }
49 virtual std::string message(int ev) const
51 static char const* msgs[] =
52 { "no error", "torrent file collides with file from another torrent" };
53 if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0]))
54 return "Unknown error";
55 return msgs[ev];
57 virtual boost::system::error_condition default_error_condition(int ev) const
59 return boost::system::error_condition(ev, *this);
61 virtual bool equivalent(int code, boost::system::error_condition const& condition) const
63 return default_error_condition(code) == condition;
65 virtual bool equivalent(boost::system::error_code const& code, int condition ) const
67 return *this == code.category() && code.value() == condition;
71 file_pool_error_category file_pool_category;
73 #endif
75 boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p
76 , file::open_mode m, error_code& ec)
78 TORRENT_ASSERT(st != 0);
79 TORRENT_ASSERT(p.is_complete());
80 TORRENT_ASSERT(m == file::in || m == (file::in | file::out));
81 boost::mutex::scoped_lock l(m_mutex);
82 typedef nth_index<file_set, 0>::type path_view;
83 path_view& pt = get<0>(m_files);
84 path_view::iterator i = pt.find(p);
85 if (i != pt.end())
87 lru_file_entry e = *i;
88 e.last_use = time_now();
90 if (e.key != st)
92 // this means that another instance of the storage
93 // is using the exact same file.
94 #if BOOST_VERSION >= 103500
95 ec = error_code(1, file_pool_category);
96 #endif
97 return boost::shared_ptr<file>();
100 e.key = st;
101 if ((e.mode & m) != m)
103 // close the file before we open it with
104 // the new read/write privilages
105 i->file_ptr.reset();
106 TORRENT_ASSERT(e.file_ptr.unique());
107 e.file_ptr->close();
108 if (!e.file_ptr->open(p, m, ec))
110 m_files.erase(i);
111 return boost::shared_ptr<file>();
113 e.mode = m;
115 pt.replace(i, e);
116 return e.file_ptr;
118 // the file is not in our cache
119 if ((int)m_files.size() >= m_size)
121 // the file cache is at its maximum size, close
122 // the least recently used (lru) file from it
123 typedef nth_index<file_set, 1>::type lru_view;
124 lru_view& lt = get<1>(m_files);
125 lru_view::iterator i = lt.begin();
126 // the first entry in this view is the least recently used
127 TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
128 lt.erase(i);
130 lru_file_entry e;
131 e.file_ptr.reset(new (std::nothrow)file);
132 if (!e.file_ptr)
134 ec = error_code(ENOMEM, get_posix_category());
135 return e.file_ptr;
137 if (!e.file_ptr->open(p, m, ec))
138 return boost::shared_ptr<file>();
139 e.mode = m;
140 e.key = st;
141 e.file_path = p;
142 pt.insert(e);
143 return e.file_ptr;
146 void file_pool::release(fs::path const& p)
148 boost::mutex::scoped_lock l(m_mutex);
150 typedef nth_index<file_set, 0>::type path_view;
151 path_view& pt = get<0>(m_files);
152 path_view::iterator i = pt.find(p);
153 if (i != pt.end()) pt.erase(i);
156 void file_pool::release(void* st)
158 boost::mutex::scoped_lock l(m_mutex);
159 TORRENT_ASSERT(st != 0);
160 using boost::tie;
162 typedef nth_index<file_set, 2>::type key_view;
163 key_view& kt = get<2>(m_files);
165 key_view::iterator start, end;
166 tie(start, end) = kt.equal_range(st);
167 kt.erase(start, end);
170 void file_pool::resize(int size)
172 TORRENT_ASSERT(size > 0);
173 if (size == m_size) return;
174 boost::mutex::scoped_lock l(m_mutex);
175 m_size = size;
176 if (int(m_files.size()) <= m_size) return;
178 // close the least recently used files
179 typedef nth_index<file_set, 1>::type lru_view;
180 lru_view& lt = get<1>(m_files);
181 lru_view::iterator i = lt.begin();
182 while (int(m_files.size()) > m_size)
184 // the first entry in this view is the least recently used
185 TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
186 lt.erase(i++);