00001
00002
00003
00004
00005
00006
00007
00008 #ifdef _WIN32
00009
00010 #include "libtorrent/utf8.hpp"
00011
00012 #include <io.h>
00013 #include <fcntl.h>
00014 #include <sys/stat.h>
00015 #include <sys/types.h>
00016
00017 #ifndef _MODE_T_
00018 typedef int mode_t;
00019 #endif
00020
00021 #ifdef UNICODE
00022 #include "libtorrent/storage.hpp"
00023 #endif
00024
00025 #else
00026
00027 #define _FILE_OFFSET_BITS 64
00028 #include <unistd.h>
00029 #include <fcntl.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #include <errno.h>
00033
00034 #include <boost/static_assert.hpp>
00035
00036 BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
00037
00038 #endif
00039
00040 #include <boost/filesystem/operations.hpp>
00041 #include "libtorrent/file.hpp"
00042 #include <sstream>
00043
00044 #ifndef O_BINARY
00045 #define O_BINARY 0
00046 #endif
00047
00048 #ifndef O_RANDOM
00049 #define O_RANDOM 0
00050 #endif
00051
00052 #ifdef UNICODE
00053 #include "libtorrent/storage.hpp"
00054 #endif
00055
00056 namespace fs = boost::filesystem;
00057
00058 namespace
00059 {
00060 enum { mode_in = 1, mode_out = 2 };
00061
00062 mode_t map_open_mode(int m)
00063 {
00064 if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
00065 if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
00066 if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
00067 assert(false);
00068 return 0;
00069 }
00070
00071 #ifdef WIN32
00072 std::string utf8_native(std::string const& s)
00073 {
00074 try
00075 {
00076 std::wstring ws;
00077 libtorrent::utf8_wchar(s, ws);
00078 std::size_t size = wcstombs(0, ws.c_str(), 0);
00079 if (size == std::size_t(-1)) return s;
00080 std::string ret;
00081 ret.resize(size);
00082 size = wcstombs(&ret[0], ws.c_str(), size + 1);
00083 if (size == wchar_t(-1)) return s;
00084 ret.resize(size);
00085 return ret;
00086 }
00087 catch(std::exception)
00088 {
00089 return s;
00090 }
00091 }
00092 #else
00093 std::string utf8_native(std::string const& s)
00094 {
00095 return s;
00096 }
00097 #endif
00098
00099 }
00100
00101 namespace libtorrent
00102 {
00103
00104 const file::open_mode file::in(mode_in);
00105 const file::open_mode file::out(mode_out);
00106
00107 const file::seek_mode file::begin(1);
00108 const file::seek_mode file::end(2);
00109
00110 struct file::impl
00111 {
00112 impl()
00113 : m_fd(-1)
00114 , m_open_mode(0)
00115 {}
00116
00117 impl(fs::path const& path, int mode)
00118 : m_fd(-1)
00119 , m_open_mode(0)
00120 {
00121 open(path, mode);
00122 }
00123
00124 ~impl()
00125 {
00126 close();
00127 }
00128
00129 void open(fs::path const& path, int mode)
00130 {
00131 assert(path.is_complete());
00132 close();
00133 #if defined(_WIN32) && defined(UNICODE)
00134 std::wstring wpath(safe_convert(path.native_file_string()));
00135 m_fd = ::_wopen(
00136 wpath.c_str()
00137 , map_open_mode(mode)
00138 , S_IREAD | S_IWRITE);
00139 #else
00140 #ifdef _WIN32
00141 m_fd = ::_open(
00142 #else
00143 m_fd = ::open(
00144 #endif
00145 utf8_native(path.native_file_string()).c_str()
00146 , map_open_mode(mode)
00147 #ifdef _WIN32
00148 , S_IREAD | S_IWRITE);
00149 #else
00150 , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00151 #endif
00152 #endif
00153 if (m_fd == -1)
00154 {
00155 std::stringstream msg;
00156 msg << "open failed: '" << path.native_file_string() << "'. "
00157 << strerror(errno);
00158 throw file_error(msg.str());
00159 }
00160 m_open_mode = mode;
00161 }
00162
00163 void close()
00164 {
00165 if (m_fd == -1) return;
00166
00167 #ifdef _WIN32
00168 ::_close(m_fd);
00169 #else
00170 ::close(m_fd);
00171 #endif
00172 m_fd = -1;
00173 m_open_mode = 0;
00174 }
00175
00176 size_type read(char* buf, size_type num_bytes)
00177 {
00178 assert(m_open_mode & mode_in);
00179 assert(m_fd != -1);
00180
00181 #ifdef _WIN32
00182 size_type ret = ::_read(m_fd, buf, num_bytes);
00183 #else
00184 size_type ret = ::read(m_fd, buf, num_bytes);
00185 #endif
00186 if (ret == -1)
00187 {
00188 std::stringstream msg;
00189 msg << "read failed: " << strerror(errno);
00190 throw file_error(msg.str());
00191 }
00192 return ret;
00193 }
00194
00195 size_type write(const char* buf, size_type num_bytes)
00196 {
00197 assert(m_open_mode & mode_out);
00198 assert(m_fd != -1);
00199
00200
00201
00202
00203 #ifdef _WIN32
00204 size_type ret = ::_write(m_fd, buf, num_bytes);
00205 #else
00206 size_type ret = ::write(m_fd, buf, num_bytes);
00207 #endif
00208 if (ret == -1)
00209 {
00210 std::stringstream msg;
00211 msg << "write failed: " << strerror(errno);
00212 throw file_error(msg.str());
00213 }
00214 return ret;
00215 }
00216
00217 size_type seek(size_type offset, int m)
00218 {
00219 assert(m_open_mode);
00220 assert(m_fd != -1);
00221
00222 int seekdir = (m == 1)?SEEK_SET:SEEK_END;
00223 #ifdef _WIN32
00224 size_type ret = _lseeki64(m_fd, offset, seekdir);
00225 #else
00226 size_type ret = lseek(m_fd, offset, seekdir);
00227 #endif
00228
00229
00230
00231
00232 if (ret == -1)
00233 {
00234 std::stringstream msg;
00235 msg << "seek failed: '" << strerror(errno)
00236 << "' fd: " << m_fd
00237 << " offset: " << offset
00238 << " seekdir: " << seekdir;
00239 throw file_error(msg.str());
00240 }
00241 return ret;
00242 }
00243
00244 size_type tell()
00245 {
00246 assert(m_open_mode);
00247 assert(m_fd != -1);
00248
00249 #ifdef _WIN32
00250 return _telli64(m_fd);
00251 #else
00252 return lseek(m_fd, 0, SEEK_CUR);
00253 #endif
00254 }
00255
00256 int m_fd;
00257 int m_open_mode;
00258 };
00259
00260
00261
00262 file::file() : m_impl(new impl()) {}
00263
00264 file::file(boost::filesystem::path const& p, file::open_mode m)
00265 : m_impl(new impl(p, m.m_mask))
00266 {}
00267
00268 file::~file() {}
00269
00270 void file::open(boost::filesystem::path const& p, file::open_mode m)
00271 {
00272 m_impl->open(p, m.m_mask);
00273 }
00274
00275 void file::close()
00276 {
00277 m_impl->close();
00278 }
00279
00280 size_type file::write(const char* buf, size_type num_bytes)
00281 {
00282 return m_impl->write(buf, num_bytes);
00283 }
00284
00285 size_type file::read(char* buf, size_type num_bytes)
00286 {
00287 return m_impl->read(buf, num_bytes);
00288 }
00289
00290 size_type file::seek(size_type pos, file::seek_mode m)
00291 {
00292 return m_impl->seek(pos, m.m_val);
00293 }
00294
00295 size_type file::tell()
00296 {
00297 return m_impl->tell();
00298 }
00299
00300 }