3 Copyright (c) 2003, Magnus Jonsson & 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/file.hpp"
34 #include "libtorrent/utf8.hpp"
35 #include "libtorrent/assert.hpp"
38 #include "libtorrent/storage.hpp"
44 #include <boost/scoped_ptr.hpp>
48 // must be used to not leak memory in case something would throw
52 auto_localfree(HLOCAL memory
)
65 std::string
utf8_native(std::string
const& s
)
70 libtorrent::utf8_wchar(s
, ws
);
71 std::size_t size
= wcstombs(0, ws
.c_str(), 0);
72 if (size
== std::size_t(-1)) return s
;
75 size
= wcstombs(&ret
[0], ws
.c_str(), size
+ 1);
76 if (size
== wchar_t(-1)) return s
;
90 struct file::impl
: boost::noncopyable
100 seek_begin
= FILE_BEGIN
,
101 seek_from_here
= FILE_CURRENT
,
105 void set_error(const char* thrower
)
107 DWORD err
= GetLastError();
110 wchar_t *wbuffer
= 0;
112 FORMAT_MESSAGE_FROM_SYSTEM
113 |FORMAT_MESSAGE_ALLOCATE_BUFFER
114 , 0, err
, 0, (LPWSTR
)&wbuffer
, 0, 0);
115 auto_localfree
auto_free(wbuffer
);
116 std::string tmp_utf8
;
117 libtorrent::wchar_utf8(wbuffer
, tmp_utf8
);
118 char const* buffer
= tmp_utf8
.c_str();
122 FORMAT_MESSAGE_FROM_SYSTEM
123 |FORMAT_MESSAGE_ALLOCATE_BUFFER
124 , 0, err
, 0, (LPSTR
)&buffer
, 0, 0);
125 auto_localfree
auto_free(buffer
);
129 s
<< (thrower
? thrower
: "NULL") << ": " << (buffer
? buffer
: "NULL");
131 if (!m_error
) m_error
.reset(new std::string
);
137 m_file_handle
= INVALID_HANDLE_VALUE
;
140 bool open(const char *file_name
, open_flags flags
)
142 TORRENT_ASSERT(file_name
);
143 TORRENT_ASSERT(flags
& (read_flag
| write_flag
));
145 DWORD access_mask
= 0;
146 if (flags
& read_flag
)
147 access_mask
|= GENERIC_READ
;
148 if (flags
& write_flag
)
149 access_mask
|= GENERIC_WRITE
;
151 TORRENT_ASSERT(access_mask
& (GENERIC_READ
| GENERIC_WRITE
));
154 std::wstring
wfile_name(safe_convert(file_name
));
155 HANDLE new_handle
= CreateFile(
160 , (flags
& write_flag
)?OPEN_ALWAYS
:OPEN_EXISTING
161 , FILE_ATTRIBUTE_NORMAL
164 HANDLE new_handle
= CreateFile(
165 utf8_native(file_name
).c_str()
169 , (flags
& write_flag
)?OPEN_ALWAYS
:OPEN_EXISTING
170 , FILE_ATTRIBUTE_NORMAL
174 if (new_handle
== INVALID_HANDLE_VALUE
)
176 set_error(file_name
);
179 // try to make the file sparse if supported
180 if (access_mask
& GENERIC_WRITE
)
183 ::DeviceIoControl(new_handle
, FSCTL_SET_SPARSE
, 0, 0
186 // will only close old file if the open succeeded
188 m_file_handle
= new_handle
;
194 if (m_file_handle
!= INVALID_HANDLE_VALUE
)
196 CloseHandle(m_file_handle
);
197 m_file_handle
= INVALID_HANDLE_VALUE
;
206 size_type
write(const char* buffer
, size_type num_bytes
)
208 TORRENT_ASSERT(buffer
);
209 TORRENT_ASSERT((DWORD
)num_bytes
== num_bytes
);
210 DWORD bytes_written
= 0;
213 if (FALSE
== WriteFile(
220 set_error("file::write");
224 return bytes_written
;
227 size_type
read(char* buffer
, size_type num_bytes
)
229 TORRENT_ASSERT(buffer
);
230 TORRENT_ASSERT(num_bytes
>= 0);
231 TORRENT_ASSERT((DWORD
)num_bytes
== num_bytes
);
233 DWORD bytes_read
= 0;
236 if (FALSE
== ReadFile(
243 set_error("file::set_size");
250 bool set_size(size_type s
)
252 size_type pos
= tell();
254 if (FALSE
== ::SetEndOfFile(m_file_handle
))
256 set_error("file::set_size");
262 size_type
seek(size_type pos
, seek_mode from_where
)
264 TORRENT_ASSERT(pos
>= 0 || from_where
!= seek_begin
);
265 TORRENT_ASSERT(pos
<= 0 || from_where
!= seek_end
);
268 if (FALSE
== SetFilePointerEx(
274 set_error("file::seek");
277 return offs
.QuadPart
;
285 // is there any other way to get offset?
286 if (FALSE
== SetFilePointerEx(
292 set_error("file::tell");
296 size_type pos
= offs
.QuadPart
;
297 TORRENT_ASSERT(pos
>= 0);
304 if (FALSE == GetFileSizeEx(m_file_handle, &s))
306 throw_exception("file::size");
309 size_type size = s.QuadPart;
310 TORRENT_ASSERT(size >= 0);
315 std::string
const& error() const
317 if (!m_error
) m_error
.reset(new std::string
);
323 HANDLE m_file_handle
;
324 mutable boost::scoped_ptr
<std::string
> m_error
;
332 const file::seek_mode
file::begin(file::impl::seek_begin
);
333 const file::seek_mode
file::end(file::impl::seek_end
);
335 const file::open_mode
file::in(file::impl::read_flag
);
336 const file::open_mode
file::out(file::impl::write_flag
);
339 : m_impl(new libtorrent::file::impl())
342 file::file(boost::filesystem::path
const& p
, open_mode m
)
343 : m_impl(new libtorrent::file::impl())
352 bool file::open(boost::filesystem::path
const& p
, open_mode m
)
354 TORRENT_ASSERT(p
.is_complete());
355 return m_impl
->open(p
.native_file_string().c_str(), impl::open_flags(m
.m_mask
));
363 size_type
file::write(const char* buffer
, size_type num_bytes
)
365 return m_impl
->write(buffer
, num_bytes
);
368 size_type
file::read(char* buffer
, size_type num_bytes
)
370 return m_impl
->read(buffer
, num_bytes
);
373 bool file::set_size(size_type s
)
375 return m_impl
->set_size(s
);
378 size_type
file::seek(size_type pos
, seek_mode m
)
380 return m_impl
->seek(pos
,impl::seek_mode(m
.m_val
));
383 size_type
file::tell()
385 return m_impl
->tell();
388 std::string
const& file::error() const
390 return m_impl
->error();