3 Copyright (c) 2003, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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"
34 #include "libtorrent/config.hpp"
36 #include <boost/scoped_ptr.hpp>
37 #ifdef TORRENT_WINDOWS
39 #include "libtorrent/utf8.hpp"
45 #include "libtorrent/storage.hpp"
50 #define _FILE_OFFSET_BITS 64
54 #include <sys/types.h>
57 #include <boost/static_assert.hpp>
58 // make sure the _FILE_OFFSET_BITS define worked
60 BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
64 #include <boost/filesystem/operations.hpp>
65 #include "libtorrent/file.hpp"
79 #include "libtorrent/storage.hpp"
82 #include "libtorrent/assert.hpp"
86 #ifdef TORRENT_WINDOWS
87 std::string
utf8_native(std::string
const& s
)
92 libtorrent::utf8_wchar(s
, ws
);
93 std::size_t size
= wcstombs(0, ws
.c_str(), 0);
94 if (size
== std::size_t(-1)) return s
;
97 size
= wcstombs(&ret
[0], ws
.c_str(), size
+ 1);
98 if (size
== wchar_t(-1)) return s
;
102 catch(std::exception
)
109 enum { mode_in
= 1, mode_out
= 2 };
111 mode_t
map_open_mode(int m
)
113 if (m
== (mode_in
| mode_out
)) return O_RDWR
| O_CREAT
| O_BINARY
| O_RANDOM
;
114 if (m
== mode_out
) return O_WRONLY
| O_CREAT
| O_BINARY
| O_RANDOM
;
115 if (m
== mode_in
) return O_RDONLY
| O_BINARY
| O_RANDOM
;
116 TORRENT_ASSERT(false);
125 namespace fs
= boost::filesystem
;
127 #ifdef TORRENT_WINDOWS
128 const file::open_mode
file::in(GENERIC_READ
);
129 const file::open_mode
file::out(GENERIC_WRITE
);
130 const file::seek_mode
file::begin(FILE_BEGIN
);
131 const file::seek_mode
file::end(FILE_END
);
133 const file::open_mode
file::in(mode_in
);
134 const file::open_mode
file::out(mode_out
);
135 const file::seek_mode
file::begin(SEEK_SET
);
136 const file::seek_mode
file::end(SEEK_END
);
140 #ifdef TORRENT_WINDOWS
141 : m_file_handle(INVALID_HANDLE_VALUE
)
150 file::file(fs::path
const& path
, open_mode mode
, error_code
& ec
)
151 #ifdef TORRENT_WINDOWS
152 : m_file_handle(INVALID_HANDLE_VALUE
)
160 open(path
, mode
, ec
);
168 bool file::open(fs::path
const& path
, open_mode mode
, error_code
& ec
)
171 #ifdef TORRENT_WINDOWS
174 std::wstring
file_path(safe_convert(path
.native_file_string()));
176 std::string file_path
= utf8_native(path
.native_file_string());
179 m_file_handle
= CreateFile(
184 , (mode
& out
)?OPEN_ALWAYS
:OPEN_EXISTING
185 , FILE_ATTRIBUTE_NORMAL
188 if (m_file_handle
== INVALID_HANDLE_VALUE
)
190 ec
= error_code(GetLastError(), get_system_category());
194 // try to make the file sparse if supported
198 ::DeviceIoControl(m_file_handle
, FSCTL_SET_SPARSE
, 0, 0
202 // rely on default umask to filter x and w permissions
203 // for group and others
204 m_fd
= ::open(path
.native_file_string().c_str()
205 , map_open_mode(mode
.m_mask
), S_IRWXU
| S_IRWXG
| S_IRWXO
);
209 ec
= error_code(errno
, get_posix_category());
216 TORRENT_ASSERT(is_open());
220 bool file::is_open() const
222 #ifdef TORRENT_WINDOWS
223 return m_file_handle
!= INVALID_HANDLE_VALUE
;
231 #ifdef TORRENT_WINDOWS
232 if (m_file_handle
== INVALID_HANDLE_VALUE
) return;
233 CloseHandle(m_file_handle
);
234 m_file_handle
= INVALID_HANDLE_VALUE
;
236 if (m_fd
== -1) return;
245 size_type
file::read(char* buf
, size_type num_bytes
, error_code
& ec
)
247 TORRENT_ASSERT((m_open_mode
& in
) == in
);
249 TORRENT_ASSERT(num_bytes
>= 0);
250 TORRENT_ASSERT(is_open());
252 #ifdef TORRENT_WINDOWS
254 TORRENT_ASSERT(DWORD(num_bytes
) == num_bytes
);
258 if (ReadFile(m_file_handle
, buf
, (DWORD
)num_bytes
, &ret
, 0) == FALSE
)
260 ec
= error_code(GetLastError(), get_system_category());
265 size_type ret
= ::read(m_fd
, buf
, num_bytes
);
266 if (ret
== -1) ec
= error_code(errno
, get_posix_category());
271 size_type
file::write(const char* buf
, size_type num_bytes
, error_code
& ec
)
273 TORRENT_ASSERT((m_open_mode
& out
) == out
);
275 TORRENT_ASSERT(num_bytes
>= 0);
276 TORRENT_ASSERT(is_open());
278 #ifdef TORRENT_WINDOWS
283 if (WriteFile(m_file_handle
, buf
, (DWORD
)num_bytes
, &ret
, 0) == FALSE
)
285 ec
= error_code(GetLastError(), get_system_category());
290 size_type ret
= ::write(m_fd
, buf
, num_bytes
);
291 if (ret
== -1) ec
= error_code(errno
, get_posix_category());
296 bool file::set_size(size_type s
, error_code
& ec
)
298 TORRENT_ASSERT(is_open());
299 TORRENT_ASSERT(s
>= 0);
301 #ifdef TORRENT_WINDOWS
302 size_type pos
= tell(ec
);
303 if (ec
) return false;
305 if (ec
) return false;
306 if (::SetEndOfFile(m_file_handle
) == FALSE
)
308 ec
= error_code(GetLastError(), get_system_category());
312 if (ftruncate(m_fd
, s
) < 0)
314 ec
= error_code(errno
, get_posix_category());
321 size_type
file::seek(size_type offset
, seek_mode m
, error_code
& ec
)
323 TORRENT_ASSERT(is_open());
325 #ifdef TORRENT_WINDOWS
327 offs
.QuadPart
= offset
;
328 if (SetFilePointerEx(m_file_handle
, offs
, &offs
, m
.m_val
) == FALSE
)
330 ec
= error_code(GetLastError(), get_system_category());
333 return offs
.QuadPart
;
335 size_type ret
= lseek(m_fd
, offset
, m
.m_val
);
336 if (ret
< 0) ec
= error_code(errno
, get_posix_category());
341 size_type
file::tell(error_code
& ec
)
343 TORRENT_ASSERT(is_open());
345 #ifdef TORRENT_WINDOWS
349 // is there any other way to get offset?
350 if (SetFilePointerEx(m_file_handle
, offs
, &offs
351 , FILE_CURRENT
) == FALSE
)
353 ec
= error_code(GetLastError(), get_system_category());
357 return offs
.QuadPart
;
360 ret
= lseek(m_fd
, 0, SEEK_CUR
);
361 if (ret
< 0) ec
= error_code(errno
, get_posix_category());