file_progress fix
[libtorrent.git] / src / file.cpp
blob050ec11c9eb9b350d8c1e397bbb820246364faeb
1 /*
3 Copyright (c) 2003, 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 "libtorrent/pch.hpp"
35 #include <boost/scoped_ptr.hpp>
36 #ifdef _WIN32
37 // windows part
38 #include "libtorrent/utf8.hpp"
40 #include <io.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
45 #ifndef _MODE_T_
46 typedef int mode_t;
47 #endif
49 #ifdef UNICODE
50 #include "libtorrent/storage.hpp"
51 #endif
53 #else
54 // unix part
55 #define _FILE_OFFSET_BITS 64
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #include <errno.h>
62 #include <boost/static_assert.hpp>
63 // make sure the _FILE_OFFSET_BITS define worked
64 // on this platform
65 BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
67 #endif
69 #include <boost/filesystem/operations.hpp>
70 #include "libtorrent/file.hpp"
71 #include <sstream>
72 #include <cstring>
73 #include <vector>
75 #ifndef O_BINARY
76 #define O_BINARY 0
77 #endif
79 #ifndef O_RANDOM
80 #define O_RANDOM 0
81 #endif
83 #ifdef UNICODE
84 #include "libtorrent/storage.hpp"
85 #endif
87 #include "libtorrent/assert.hpp"
89 namespace
91 enum { mode_in = 1, mode_out = 2 };
93 mode_t map_open_mode(int m)
95 if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
96 if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
97 if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
98 TORRENT_ASSERT(false);
99 return 0;
102 #ifdef WIN32
103 std::string utf8_native(std::string const& s)
107 std::wstring ws;
108 libtorrent::utf8_wchar(s, ws);
109 std::size_t size = wcstombs(0, ws.c_str(), 0);
110 if (size == std::size_t(-1)) return s;
111 std::string ret;
112 ret.resize(size);
113 size = wcstombs(&ret[0], ws.c_str(), size + 1);
114 if (size == wchar_t(-1)) return s;
115 ret.resize(size);
116 return ret;
118 catch(std::exception)
120 return s;
123 #else
124 std::string utf8_native(std::string const& s)
126 return s;
128 #endif
132 namespace libtorrent
134 namespace fs = boost::filesystem;
136 const file::open_mode file::in(mode_in);
137 const file::open_mode file::out(mode_out);
139 const file::seek_mode file::begin(1);
140 const file::seek_mode file::end(2);
142 struct file::impl
144 impl()
145 : m_fd(-1)
146 , m_open_mode(0)
149 impl(fs::path const& path, int mode)
150 : m_fd(-1)
151 , m_open_mode(0)
153 open(path, mode);
156 ~impl()
158 close();
161 bool open(fs::path const& path, int mode)
163 close();
164 #if defined _WIN32 && defined UNICODE
165 std::wstring wpath(safe_convert(path.native_file_string()));
166 m_fd = ::_wopen(
167 wpath.c_str()
168 , map_open_mode(mode));
169 #elif defined _WIN32
170 m_fd = ::_open(
171 utf8_native(path.native_file_string()).c_str()
172 , map_open_mode(mode));
173 #else
174 m_fd = ::open(
175 utf8_native(path.native_file_string()).c_str()
176 , map_open_mode(mode));
177 #endif
178 if (m_fd == -1)
180 std::stringstream msg;
181 msg << "open failed: '" << path.native_file_string() << "'. "
182 << std::strerror(errno);
183 if (!m_error) m_error.reset(new std::string);
184 *m_error = msg.str();
185 return false;
187 m_open_mode = mode;
188 return true;
191 void close()
193 if (m_fd == -1) return;
195 #ifdef _WIN32
196 ::_close(m_fd);
197 #else
198 ::close(m_fd);
199 #endif
200 m_fd = -1;
201 m_open_mode = 0;
204 size_type read(char* buf, size_type num_bytes)
206 TORRENT_ASSERT(m_open_mode & mode_in);
207 TORRENT_ASSERT(m_fd != -1);
209 #ifdef _WIN32
210 size_type ret = ::_read(m_fd, buf, num_bytes);
211 #else
212 size_type ret = ::read(m_fd, buf, num_bytes);
213 #endif
214 if (ret == -1)
216 std::stringstream msg;
217 msg << "read failed: " << std::strerror(errno);
218 if (!m_error) m_error.reset(new std::string);
219 *m_error = msg.str();
221 return ret;
224 size_type write(const char* buf, size_type num_bytes)
226 TORRENT_ASSERT(m_open_mode & mode_out);
227 TORRENT_ASSERT(m_fd != -1);
229 // TODO: Test this a bit more, what happens with random failures in
230 // the files?
231 // if ((rand() % 100) > 80)
232 // throw file_error("debug");
234 #ifdef _WIN32
235 size_type ret = ::_write(m_fd, buf, num_bytes);
236 #else
237 size_type ret = ::write(m_fd, buf, num_bytes);
238 #endif
239 if (ret == -1)
241 std::stringstream msg;
242 msg << "write failed: " << std::strerror(errno);
243 if (!m_error) m_error.reset(new std::string);
244 *m_error = msg.str();
246 return ret;
249 bool set_size(size_type s)
251 #ifdef _WIN32
252 #error file.cpp is for posix systems only. use file_win.cpp on windows
253 #else
254 if (ftruncate(m_fd, s) < 0)
256 std::stringstream msg;
257 msg << "ftruncate failed: '" << std::strerror(errno);
258 if (!m_error) m_error.reset(new std::string);
259 *m_error = msg.str();
260 return false;
262 return true;
263 #endif
266 size_type seek(size_type offset, int m = 1)
268 TORRENT_ASSERT(m_open_mode);
269 TORRENT_ASSERT(m_fd != -1);
271 int seekdir = (m == 1)?SEEK_SET:SEEK_END;
272 #ifdef _WIN32
273 size_type ret = _lseeki64(m_fd, offset, seekdir);
274 #else
275 size_type ret = lseek(m_fd, offset, seekdir);
276 #endif
278 // For some strange reason this fails
279 // on win32. Use windows specific file
280 // wrapper instead.
281 if (ret == -1)
283 std::stringstream msg;
284 msg << "seek failed: '" << std::strerror(errno)
285 << "' fd: " << m_fd
286 << " offset: " << offset
287 << " seekdir: " << seekdir;
288 if (!m_error) m_error.reset(new std::string);
289 *m_error = msg.str();
290 return -1;
292 return ret;
295 size_type tell()
297 TORRENT_ASSERT(m_open_mode);
298 TORRENT_ASSERT(m_fd != -1);
300 #ifdef _WIN32
301 return _telli64(m_fd);
302 #else
303 return lseek(m_fd, 0, SEEK_CUR);
304 #endif
307 std::string const& error() const
309 if (!m_error) m_error.reset(new std::string);
310 return *m_error;
313 int m_fd;
314 int m_open_mode;
315 mutable boost::scoped_ptr<std::string> m_error;
318 // pimpl forwardings
320 file::file() : m_impl(new impl()) {}
322 file::file(fs::path const& p, file::open_mode m)
323 : m_impl(new impl(p, m.m_mask))
326 file::~file() {}
328 bool file::open(fs::path const& p, file::open_mode m)
330 return m_impl->open(p, m.m_mask);
333 void file::close()
335 m_impl->close();
338 size_type file::write(const char* buf, size_type num_bytes)
340 return m_impl->write(buf, num_bytes);
343 size_type file::read(char* buf, size_type num_bytes)
345 return m_impl->read(buf, num_bytes);
348 bool file::set_size(size_type s)
350 return m_impl->set_size(s);
353 size_type file::seek(size_type pos, file::seek_mode m)
355 return m_impl->seek(pos, m.m_val);
358 size_type file::tell()
360 return m_impl->tell();
363 std::string const& file::error() const
365 return m_impl->error();