forked from premiere/premiere-libtorrent
merged file_win.cpp and file.cpp (removed the need for file_win.cpp). The file is no longer a pimpl
This commit is contained in:
parent
0433a32857
commit
417855848f
10
Jamfile
10
Jamfile
|
@ -173,15 +173,6 @@ rule building ( properties * )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if <target-os>windows in $(properties)
|
|
||||||
{
|
|
||||||
result += <source>src/file_win.cpp ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result += <source>src/file.cpp ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if <memdebug>on in $(properties)
|
if <memdebug>on in $(properties)
|
||||||
{
|
{
|
||||||
result += <source>src/memdebug.cpp ;
|
result += <source>src/memdebug.cpp ;
|
||||||
|
@ -291,6 +282,7 @@ SOURCES =
|
||||||
file_storage
|
file_storage
|
||||||
lazy_bdecode
|
lazy_bdecode
|
||||||
escape_string
|
escape_string
|
||||||
|
file
|
||||||
gzip
|
gzip
|
||||||
http_connection
|
http_connection
|
||||||
http_stream
|
http_stream
|
||||||
|
|
|
@ -32,7 +32,7 @@ docs/moopolice_thumb.gif \
|
||||||
docs/qbittorrent_thumb.jpg \
|
docs/qbittorrent_thumb.jpg \
|
||||||
docs/ziptorrent_thumb.gif \
|
docs/ziptorrent_thumb.gif \
|
||||||
docs/unicode_support.png docs/client_test.png docs/style.css Jamfile project-root.jam \
|
docs/unicode_support.png docs/client_test.png docs/style.css Jamfile project-root.jam \
|
||||||
src/file_win.cpp libtorrent-rasterbar.pc \
|
libtorrent-rasterbar.pc \
|
||||||
bindings/README.txt \
|
bindings/README.txt \
|
||||||
bindings/python/Jamfile \
|
bindings/python/Jamfile \
|
||||||
bindings/python/client.py \
|
bindings/python/client.py \
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace libtorrent
|
||||||
#if BOOST_VERSION < 103500
|
#if BOOST_VERSION < 103500
|
||||||
typedef asio::error_code error_code;
|
typedef asio::error_code error_code;
|
||||||
inline asio::error::error_category get_posix_category() { return asio::error::system_category; }
|
inline asio::error::error_category get_posix_category() { return asio::error::system_category; }
|
||||||
|
inline asio::error::error_category get_system_category() { return asio::error::system_category; }
|
||||||
#else
|
#else
|
||||||
|
|
||||||
struct libtorrent_error_category : boost::system::error_category
|
struct libtorrent_error_category : boost::system::error_category
|
||||||
|
@ -69,6 +70,8 @@ namespace libtorrent
|
||||||
extern libtorrent_error_category libtorrent_category;
|
extern libtorrent_error_category libtorrent_category;
|
||||||
|
|
||||||
using boost::system::error_code;
|
using boost::system::error_code;
|
||||||
|
inline boost::system::error_category const& get_system_category()
|
||||||
|
{ return boost::system::get_system_category(); }
|
||||||
inline boost::system::error_category const& get_posix_category()
|
inline boost::system::error_category const& get_posix_category()
|
||||||
{ return boost::system::get_posix_category(); }
|
{ return boost::system::get_posix_category(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -77,7 +77,6 @@ namespace libtorrent
|
||||||
public:
|
public:
|
||||||
|
|
||||||
open_mode(): m_mask(0) {}
|
open_mode(): m_mask(0) {}
|
||||||
|
|
||||||
open_mode operator|(open_mode m) const
|
open_mode operator|(open_mode m) const
|
||||||
{ return open_mode(m.m_mask | m_mask); }
|
{ return open_mode(m.m_mask | m_mask); }
|
||||||
|
|
||||||
|
@ -92,6 +91,7 @@ namespace libtorrent
|
||||||
|
|
||||||
bool operator==(open_mode m) const { return m_mask == m.m_mask; }
|
bool operator==(open_mode m) const { return m_mask == m.m_mask; }
|
||||||
bool operator!=(open_mode m) const { return m_mask != m.m_mask; }
|
bool operator!=(open_mode m) const { return m_mask != m.m_mask; }
|
||||||
|
operator bool() const { return m_mask != 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -107,6 +107,7 @@ namespace libtorrent
|
||||||
~file();
|
~file();
|
||||||
|
|
||||||
bool open(fs::path const& p, open_mode m, error_code& ec);
|
bool open(fs::path const& p, open_mode m, error_code& ec);
|
||||||
|
bool is_open() const;
|
||||||
void close();
|
void close();
|
||||||
bool set_size(size_type size, error_code& ec);
|
bool set_size(size_type size, error_code& ec);
|
||||||
|
|
||||||
|
@ -118,8 +119,14 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct impl;
|
#ifdef TORRENT_WINDOWS
|
||||||
const std::auto_ptr<impl> m_impl;
|
HANDLE m_file_handle;
|
||||||
|
#else
|
||||||
|
int m_fd;
|
||||||
|
#endif
|
||||||
|
#ifndef NDEBUG
|
||||||
|
open_mode m_open_mode;
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
421
src/file.cpp
421
src/file.cpp
|
@ -31,27 +31,22 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libtorrent/pch.hpp"
|
#include "libtorrent/pch.hpp"
|
||||||
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
#ifdef _WIN32
|
#ifdef TORRENT_WINDOWS
|
||||||
// windows part
|
// windows part
|
||||||
#include "libtorrent/utf8.hpp"
|
#include "libtorrent/utf8.hpp"
|
||||||
|
|
||||||
#include <io.h>
|
#include <windows.h>
|
||||||
#include <fcntl.h>
|
#include <winioctl.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#ifndef _MODE_T_
|
|
||||||
typedef int mode_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
#include "libtorrent/storage.hpp"
|
#include "libtorrent/storage.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// unix part
|
// posix part
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -88,18 +83,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
enum { mode_in = 1, mode_out = 2 };
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
mode_t map_open_mode(int m)
|
|
||||||
{
|
|
||||||
if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
|
|
||||||
if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
|
|
||||||
if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
|
|
||||||
TORRENT_ASSERT(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
std::string utf8_native(std::string const& s)
|
std::string utf8_native(std::string const& s)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -121,9 +105,16 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
std::string const& utf8_native(std::string const& s)
|
|
||||||
|
enum { mode_in = 1, mode_out = 2 };
|
||||||
|
|
||||||
|
mode_t map_open_mode(int m)
|
||||||
{
|
{
|
||||||
return s;
|
if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
|
||||||
|
if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
|
||||||
|
if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
|
||||||
|
TORRENT_ASSERT(false);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -133,206 +124,242 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
const file::open_mode file::in(GENERIC_READ);
|
||||||
|
const file::open_mode file::out(GENERIC_WRITE);
|
||||||
|
const file::seek_mode file::begin(FILE_BEGIN);
|
||||||
|
const file::seek_mode file::end(FILE_END);
|
||||||
|
#else
|
||||||
const file::open_mode file::in(mode_in);
|
const file::open_mode file::in(mode_in);
|
||||||
const file::open_mode file::out(mode_out);
|
const file::open_mode file::out(mode_out);
|
||||||
|
const file::seek_mode file::begin(SEEK_SET);
|
||||||
|
const file::seek_mode file::end(SEEK_END);
|
||||||
|
#endif
|
||||||
|
|
||||||
const file::seek_mode file::begin(1);
|
file::file()
|
||||||
const file::seek_mode file::end(2);
|
|
||||||
|
|
||||||
struct file::impl
|
|
||||||
{
|
|
||||||
impl()
|
|
||||||
: m_fd(-1)
|
|
||||||
, m_open_mode(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
impl(fs::path const& path, int mode, error_code& ec)
|
|
||||||
: m_fd(-1)
|
|
||||||
, m_open_mode(0)
|
|
||||||
{
|
|
||||||
open(path, mode, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
~impl()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(fs::path const& path, int mode, error_code& ec)
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
|
: m_file_handle(INVALID_HANDLE_VALUE)
|
||||||
const int permissions = _S_IREAD | _S_IWRITE;
|
|
||||||
|
|
||||||
#ifdef defined UNICODE
|
|
||||||
#define open _wopen
|
|
||||||
std::wstring file_path(safe_convert(path.native_file_string()));
|
|
||||||
#else
|
#else
|
||||||
#define open _open
|
: m_fd(-1)
|
||||||
std::string const& file_path = path.native_file_string();
|
|
||||||
#endif
|
#endif
|
||||||
#else // if not windows
|
#ifndef NDEBUG
|
||||||
// rely on default umask to filter x and w permissions
|
, m_open_mode(0)
|
||||||
// for group and others
|
|
||||||
const mode_t permissions = S_IRWXU | S_IRWXG | S_IRWXO;
|
|
||||||
std::string const& file_path = path.native_file_string();
|
|
||||||
#endif
|
#endif
|
||||||
m_fd = ::open(file_path.c_str(), map_open_mode(mode), permissions);
|
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
|
||||||
#undef open
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_fd == -1)
|
|
||||||
{
|
|
||||||
ec = error_code(errno, get_posix_category());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_open_mode = mode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
if (m_fd == -1) return;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
::_close(m_fd);
|
|
||||||
#else
|
|
||||||
::close(m_fd);
|
|
||||||
#endif
|
|
||||||
m_fd = -1;
|
|
||||||
m_open_mode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type read(char* buf, size_type num_bytes, error_code& ec)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(m_open_mode & mode_in);
|
|
||||||
TORRENT_ASSERT(m_fd != -1);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
size_type ret = ::_read(m_fd, buf, num_bytes);
|
|
||||||
#else
|
|
||||||
size_type ret = ::read(m_fd, buf, num_bytes);
|
|
||||||
#endif
|
|
||||||
if (ret == -1) ec = error_code(errno, get_posix_category());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type write(const char* buf, size_type num_bytes, error_code& ec)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(m_open_mode & mode_out);
|
|
||||||
TORRENT_ASSERT(m_fd != -1);
|
|
||||||
|
|
||||||
// TODO: Test this a bit more, what happens with random failures in
|
|
||||||
// the files?
|
|
||||||
// if ((rand() % 100) > 80)
|
|
||||||
// throw file_error("debug");
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
size_type ret = ::_write(m_fd, buf, num_bytes);
|
|
||||||
#else
|
|
||||||
size_type ret = ::write(m_fd, buf, num_bytes);
|
|
||||||
#endif
|
|
||||||
if (ret == -1) ec = error_code(errno, get_posix_category());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_size(size_type s, error_code& ec)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
#error file.cpp is for posix systems only. use file_win.cpp on windows
|
|
||||||
#else
|
|
||||||
if (ftruncate(m_fd, s) < 0)
|
|
||||||
{
|
|
||||||
ec = error_code(errno, get_posix_category());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type seek(size_type offset, int m, error_code& ec)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(m_open_mode);
|
|
||||||
TORRENT_ASSERT(m_fd != -1);
|
|
||||||
|
|
||||||
int seekdir = (m == 1)?SEEK_SET:SEEK_END;
|
|
||||||
#ifdef _WIN32
|
|
||||||
size_type ret = _lseeki64(m_fd, offset, seekdir);
|
|
||||||
#else
|
|
||||||
size_type ret = lseek(m_fd, offset, seekdir);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For some strange reason this fails
|
|
||||||
// on win32. Use windows specific file
|
|
||||||
// wrapper instead.
|
|
||||||
if (ret < 0) ec = error_code(errno, get_posix_category());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type tell(error_code& ec)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(m_open_mode);
|
|
||||||
TORRENT_ASSERT(m_fd != -1);
|
|
||||||
|
|
||||||
size_type ret;
|
|
||||||
#ifdef _WIN32
|
|
||||||
ret = _telli64(m_fd);
|
|
||||||
#else
|
|
||||||
ret = lseek(m_fd, 0, SEEK_CUR);
|
|
||||||
#endif
|
|
||||||
if (ret < 0) ec = error_code(errno, get_posix_category());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int m_fd;
|
|
||||||
int m_open_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
// pimpl forwardings
|
|
||||||
|
|
||||||
file::file() : m_impl(new impl()) {}
|
|
||||||
|
|
||||||
file::file(fs::path const& p, file::open_mode m, error_code& ec)
|
|
||||||
: m_impl(new impl(p, m.m_mask, ec))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
file::~file() {}
|
file::file(fs::path const& path, open_mode mode, error_code& ec)
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
bool file::open(fs::path const& p, file::open_mode m, error_code& ec)
|
: m_file_handle(INVALID_HANDLE_VALUE)
|
||||||
|
#else
|
||||||
|
: m_fd(-1)
|
||||||
|
#endif
|
||||||
|
#ifndef NDEBUG
|
||||||
|
, m_open_mode(0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
return m_impl->open(p, m.m_mask, ec);
|
open(path, mode, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
file::~file()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file::open(fs::path const& path, open_mode mode, error_code& ec)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
std::wstring file_path(safe_convert(path.native_file_string()));
|
||||||
|
#else
|
||||||
|
std::string file_path = utf8_native(path.native_file_string());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HANDLE m_file_handle = CreateFile(
|
||||||
|
file_path.c_str()
|
||||||
|
, mode.m_mask
|
||||||
|
, FILE_SHARE_READ
|
||||||
|
, 0
|
||||||
|
, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
|
||||||
|
, FILE_ATTRIBUTE_NORMAL
|
||||||
|
, 0);
|
||||||
|
|
||||||
|
if (m_file_handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to make the file sparse if supported
|
||||||
|
if (mode & out)
|
||||||
|
{
|
||||||
|
DWORD temp;
|
||||||
|
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
|
||||||
|
, 0, 0, &temp, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// rely on default umask to filter x and w permissions
|
||||||
|
// for group and others
|
||||||
|
m_fd = ::open(path.native_file_string().c_str()
|
||||||
|
, map_open_mode(mode.m_mask), S_IRWXU | S_IRWXG | S_IRWXO);
|
||||||
|
|
||||||
|
if (m_fd == -1)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, get_posix_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_open_mode = mode;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file::is_open() const
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
return m_file_handle != INVALID_HANDLE_VALUE;
|
||||||
|
#else
|
||||||
|
return m_fd != -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::close()
|
void file::close()
|
||||||
{
|
{
|
||||||
m_impl->close();
|
#ifdef TORRENT_WINDOWS
|
||||||
}
|
if (m_file_handle == INVALID_HANDLE_VALUE) return;
|
||||||
|
CloseHandle(m_file_handle);
|
||||||
size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
|
m_file_handle = INVALID_HANDLE_VALUE;
|
||||||
{
|
#else
|
||||||
return m_impl->write(buf, num_bytes, ec);
|
if (m_fd == -1) return;
|
||||||
|
::close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
#endif
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_open_mode = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type file::read(char* buf, size_type num_bytes, error_code& ec)
|
size_type file::read(char* buf, size_type num_bytes, error_code& ec)
|
||||||
{
|
{
|
||||||
return m_impl->read(buf, num_bytes, ec);
|
TORRENT_ASSERT((m_open_mode & in) == in);
|
||||||
|
TORRENT_ASSERT(buf);
|
||||||
|
TORRENT_ASSERT(num_bytes >= 0);
|
||||||
|
TORRENT_ASSERT(is_open());
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
|
TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
|
||||||
|
DWORD ret = 0;
|
||||||
|
if (num_bytes != 0)
|
||||||
|
{
|
||||||
|
if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
size_type ret = ::read(m_fd, buf, num_bytes);
|
||||||
|
if (ret == -1) ec = error_code(errno, get_posix_category());
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file::set_size(size_type s, error_code& ec)
|
size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
|
||||||
{
|
{
|
||||||
return m_impl->set_size(s, ec);
|
TORRENT_ASSERT((m_open_mode & out) == out);
|
||||||
|
TORRENT_ASSERT(buf);
|
||||||
|
TORRENT_ASSERT(num_bytes >= 0);
|
||||||
|
TORRENT_ASSERT(is_open());
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
|
DWORD ret = 0;
|
||||||
|
if (num_bytes != 0)
|
||||||
|
{
|
||||||
|
if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
size_type ret = ::write(m_fd, buf, num_bytes);
|
||||||
|
if (ret == -1) ec = error_code(errno, get_posix_category());
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type file::seek(size_type pos, file::seek_mode m, error_code& ec)
|
bool file::set_size(size_type s, error_code& ec)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(is_open());
|
||||||
|
TORRENT_ASSERT(s >= 0);
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
size_type pos = tell(ec);
|
||||||
|
if (ec) return false;
|
||||||
|
seek(s, begin, ec);
|
||||||
|
if (ec) return false;
|
||||||
|
if (::SetEndOfFile(m_file_handle) == FALSE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (ftruncate(m_fd, s) < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, get_posix_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type file::seek(size_type offset, seek_mode m, error_code& ec)
|
||||||
{
|
{
|
||||||
return m_impl->seek(pos, m.m_val, ec);
|
TORRENT_ASSERT(is_open());
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
LARGE_INTEGER offs;
|
||||||
|
offs.QuadPart = offset;
|
||||||
|
if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return offs.QuadPart;
|
||||||
|
#else
|
||||||
|
size_type ret = lseek(m_fd, offset, m.m_val);
|
||||||
|
if (ret < 0) ec = error_code(errno, get_posix_category());
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type file::tell(error_code& ec)
|
size_type file::tell(error_code& ec)
|
||||||
{
|
{
|
||||||
return m_impl->tell(ec);
|
TORRENT_ASSERT(is_open());
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
LARGE_INTEGER offs;
|
||||||
|
offs.QuadPart = 0;
|
||||||
|
|
||||||
|
// is there any other way to get offset?
|
||||||
|
if (SetFilePointerEx(m_file_handle, offs, &offs
|
||||||
|
, FILE_CURRENT) == FALSE)
|
||||||
|
{
|
||||||
|
ec = error_code(GetLastError(), get_system_category());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offs.QuadPart;
|
||||||
|
#else
|
||||||
|
size_type ret;
|
||||||
|
ret = lseek(m_fd, 0, SEEK_CUR);
|
||||||
|
if (ret < 0) ec = error_code(errno, get_posix_category());
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
392
src/file_win.cpp
392
src/file_win.cpp
|
@ -1,392 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the author nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/utf8.hpp"
|
|
||||||
#include "libtorrent/assert.hpp"
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
#include "libtorrent/storage.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winioctl.h>
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// must be used to not leak memory in case something would throw
|
|
||||||
class auto_localfree
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
auto_localfree(HLOCAL memory)
|
|
||||||
: m_memory(memory)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~auto_localfree()
|
|
||||||
{
|
|
||||||
if (m_memory)
|
|
||||||
LocalFree(m_memory);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
HLOCAL m_memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string utf8_native(std::string const& s)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::wstring ws;
|
|
||||||
libtorrent::utf8_wchar(s, ws);
|
|
||||||
std::size_t size = wcstombs(0, ws.c_str(), 0);
|
|
||||||
if (size == std::size_t(-1)) return s;
|
|
||||||
std::string ret;
|
|
||||||
ret.resize(size);
|
|
||||||
size = wcstombs(&ret[0], ws.c_str(), size + 1);
|
|
||||||
if (size == wchar_t(-1)) return s;
|
|
||||||
ret.resize(size);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
catch(std::exception)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace libtorrent
|
|
||||||
{
|
|
||||||
|
|
||||||
struct file::impl : boost::noncopyable
|
|
||||||
{
|
|
||||||
enum open_flags
|
|
||||||
{
|
|
||||||
read_flag = 1,
|
|
||||||
write_flag = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum seek_mode
|
|
||||||
{
|
|
||||||
seek_begin = FILE_BEGIN,
|
|
||||||
seek_from_here = FILE_CURRENT,
|
|
||||||
seek_end = FILE_END
|
|
||||||
};
|
|
||||||
|
|
||||||
void set_error(const char* thrower)
|
|
||||||
{
|
|
||||||
DWORD err = GetLastError();
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
wchar_t *wbuffer = 0;
|
|
||||||
FormatMessage(
|
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM
|
|
||||||
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
||||||
, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
|
|
||||||
auto_localfree auto_free(wbuffer);
|
|
||||||
std::string tmp_utf8;
|
|
||||||
libtorrent::wchar_utf8(wbuffer, tmp_utf8);
|
|
||||||
char const* buffer = tmp_utf8.c_str();
|
|
||||||
#else
|
|
||||||
char* buffer = 0;
|
|
||||||
FormatMessage(
|
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM
|
|
||||||
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
||||||
, 0, err, 0, (LPSTR)&buffer, 0, 0);
|
|
||||||
auto_localfree auto_free(buffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::stringstream s;
|
|
||||||
s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");
|
|
||||||
|
|
||||||
if (!m_error) m_error.reset(new std::string);
|
|
||||||
*m_error = s.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl()
|
|
||||||
{
|
|
||||||
m_file_handle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const char *file_name, open_flags flags)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(file_name);
|
|
||||||
TORRENT_ASSERT(flags & (read_flag | write_flag));
|
|
||||||
|
|
||||||
DWORD access_mask = 0;
|
|
||||||
if (flags & read_flag)
|
|
||||||
access_mask |= GENERIC_READ;
|
|
||||||
if (flags & write_flag)
|
|
||||||
access_mask |= GENERIC_WRITE;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(access_mask & (GENERIC_READ | GENERIC_WRITE));
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
std::wstring wfile_name(safe_convert(file_name));
|
|
||||||
HANDLE new_handle = CreateFile(
|
|
||||||
wfile_name.c_str()
|
|
||||||
, access_mask
|
|
||||||
, FILE_SHARE_READ
|
|
||||||
, 0
|
|
||||||
, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
|
|
||||||
, FILE_ATTRIBUTE_NORMAL
|
|
||||||
, 0);
|
|
||||||
#else
|
|
||||||
HANDLE new_handle = CreateFile(
|
|
||||||
utf8_native(file_name).c_str()
|
|
||||||
, access_mask
|
|
||||||
, FILE_SHARE_READ
|
|
||||||
, 0
|
|
||||||
, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
|
|
||||||
, FILE_ATTRIBUTE_NORMAL
|
|
||||||
, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (new_handle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
set_error(file_name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// try to make the file sparse if supported
|
|
||||||
if (access_mask & GENERIC_WRITE)
|
|
||||||
{
|
|
||||||
DWORD temp;
|
|
||||||
::DeviceIoControl(new_handle, FSCTL_SET_SPARSE, 0, 0
|
|
||||||
, 0, 0, &temp, 0);
|
|
||||||
}
|
|
||||||
// will only close old file if the open succeeded
|
|
||||||
close();
|
|
||||||
m_file_handle = new_handle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
if (m_file_handle != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CloseHandle(m_file_handle);
|
|
||||||
m_file_handle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~impl()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type write(const char* buffer, size_type num_bytes)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(buffer);
|
|
||||||
TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
|
|
||||||
DWORD bytes_written = 0;
|
|
||||||
if (num_bytes != 0)
|
|
||||||
{
|
|
||||||
if (FALSE == WriteFile(
|
|
||||||
m_file_handle
|
|
||||||
, buffer
|
|
||||||
, (DWORD)num_bytes
|
|
||||||
, &bytes_written
|
|
||||||
, 0))
|
|
||||||
{
|
|
||||||
set_error("file::write");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes_written;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type read(char* buffer, size_type num_bytes)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(buffer);
|
|
||||||
TORRENT_ASSERT(num_bytes >= 0);
|
|
||||||
TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
|
|
||||||
|
|
||||||
DWORD bytes_read = 0;
|
|
||||||
if (num_bytes != 0)
|
|
||||||
{
|
|
||||||
if (FALSE == ReadFile(
|
|
||||||
m_file_handle
|
|
||||||
, buffer
|
|
||||||
, (DWORD)num_bytes
|
|
||||||
, &bytes_read
|
|
||||||
, 0))
|
|
||||||
{
|
|
||||||
set_error("file::set_size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_size(size_type s)
|
|
||||||
{
|
|
||||||
size_type pos = tell();
|
|
||||||
seek(s, seek_begin);
|
|
||||||
if (FALSE == ::SetEndOfFile(m_file_handle))
|
|
||||||
{
|
|
||||||
set_error("file::set_size");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type seek(size_type pos, seek_mode from_where)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(pos >= 0 || from_where != seek_begin);
|
|
||||||
TORRENT_ASSERT(pos <= 0 || from_where != seek_end);
|
|
||||||
LARGE_INTEGER offs;
|
|
||||||
offs.QuadPart = pos;
|
|
||||||
if (FALSE == SetFilePointerEx(
|
|
||||||
m_file_handle
|
|
||||||
, offs
|
|
||||||
, &offs
|
|
||||||
, from_where))
|
|
||||||
{
|
|
||||||
set_error("file::seek");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return offs.QuadPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type tell()
|
|
||||||
{
|
|
||||||
LARGE_INTEGER offs;
|
|
||||||
offs.QuadPart = 0;
|
|
||||||
|
|
||||||
// is there any other way to get offset?
|
|
||||||
if (FALSE == SetFilePointerEx(
|
|
||||||
m_file_handle
|
|
||||||
, offs
|
|
||||||
, &offs
|
|
||||||
, FILE_CURRENT))
|
|
||||||
{
|
|
||||||
set_error("file::tell");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type pos = offs.QuadPart;
|
|
||||||
TORRENT_ASSERT(pos >= 0);
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
size_type size()
|
|
||||||
{
|
|
||||||
LARGE_INTEGER s;
|
|
||||||
if (FALSE == GetFileSizeEx(m_file_handle, &s))
|
|
||||||
{
|
|
||||||
throw_exception("file::size");
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type size = s.QuadPart;
|
|
||||||
TORRENT_ASSERT(size >= 0);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::string const& error() const
|
|
||||||
{
|
|
||||||
if (!m_error) m_error.reset(new std::string);
|
|
||||||
return *m_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
HANDLE m_file_handle;
|
|
||||||
mutable boost::scoped_ptr<std::string> m_error;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace libtorrent
|
|
||||||
{
|
|
||||||
|
|
||||||
const file::seek_mode file::begin(file::impl::seek_begin);
|
|
||||||
const file::seek_mode file::end(file::impl::seek_end);
|
|
||||||
|
|
||||||
const file::open_mode file::in(file::impl::read_flag);
|
|
||||||
const file::open_mode file::out(file::impl::write_flag);
|
|
||||||
|
|
||||||
file::file()
|
|
||||||
: m_impl(new libtorrent::file::impl())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
file::file(boost::filesystem::path const& p, open_mode m)
|
|
||||||
: m_impl(new libtorrent::file::impl())
|
|
||||||
{
|
|
||||||
open(p,m);
|
|
||||||
}
|
|
||||||
|
|
||||||
file::~file()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file::open(boost::filesystem::path const& p, open_mode m)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(p.is_complete());
|
|
||||||
return m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
|
|
||||||
}
|
|
||||||
|
|
||||||
void file::close()
|
|
||||||
{
|
|
||||||
m_impl->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type file::write(const char* buffer, size_type num_bytes)
|
|
||||||
{
|
|
||||||
return m_impl->write(buffer, num_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type file::read(char* buffer, size_type num_bytes)
|
|
||||||
{
|
|
||||||
return m_impl->read(buffer, num_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file::set_size(size_type s)
|
|
||||||
{
|
|
||||||
return m_impl->set_size(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type file::seek(size_type pos, seek_mode m)
|
|
||||||
{
|
|
||||||
return m_impl->seek(pos,impl::seek_mode(m.m_val));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type file::tell()
|
|
||||||
{
|
|
||||||
return m_impl->tell();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const& file::error() const
|
|
||||||
{
|
|
||||||
return m_impl->error();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue