| // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) |
| // (C) Copyright 2003-2007 Jonathan Turkanis |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
| |
| // See http://www.boost.org/libs/iostreams for documentation. |
| |
| // Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp> |
| // knows that we are building the library (possibly exporting code), rather |
| // than using it (possibly importing code). |
| #define BOOST_IOSTREAMS_SOURCE |
| |
| #include <cassert> |
| #include <cerrno> |
| #include <cstdio> // SEEK_SET, etc. |
| #include <boost/config.hpp> // BOOST_JOIN |
| #include <boost/iostreams/detail/error.hpp> |
| #include <boost/iostreams/detail/config/dyn_link.hpp> |
| #include <boost/iostreams/detail/config/rtl.hpp> // BOOST_IOSTREAMS_FD_XXX |
| #include <boost/iostreams/detail/config/windows_posix.hpp> |
| #include <boost/iostreams/detail/system_failure.hpp> |
| #include <boost/iostreams/detail/ios.hpp> // openmodes, failure. |
| #include <boost/iostreams/device/file_descriptor.hpp> |
| #include <boost/integer_traits.hpp> |
| #include <boost/throw_exception.hpp> |
| |
| // OS-specific headers for low-level i/o. |
| |
| #include <fcntl.h> // file opening flags. |
| #include <sys/stat.h> // file access permissions. |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| # include <io.h> // low-level file i/o. |
| # define WINDOWS_LEAN_AND_MEAN |
| # include <windows.h> |
| # ifndef INVALID_SET_FILE_POINTER |
| # define INVALID_SET_FILE_POINTER ((DWORD)-1) |
| # endif |
| #else |
| # include <sys/types.h> // mode_t. |
| # include <unistd.h> // low-level file i/o. |
| #endif |
| |
| namespace boost { namespace iostreams { |
| |
| //------------------Definition of file_descriptor_impl------------------------// |
| |
| namespace detail { |
| |
| // Contains the platform dependant implementation |
| struct file_descriptor_impl { |
| // Note: These need to match file_desciptor_flags |
| enum flags { |
| never_close = 0, |
| close_on_exit = 1, |
| close_on_close = 2, |
| close_always = 3 |
| }; |
| |
| file_descriptor_impl(); |
| ~file_descriptor_impl(); |
| void open(file_handle fd, flags); |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| void open(int fd, flags); |
| #endif |
| void open(const detail::path&, BOOST_IOS::openmode); |
| bool is_open() const; |
| void close(); |
| void close_impl(bool close_flag, bool throw_); |
| std::streamsize read(char* s, std::streamsize n); |
| std::streamsize write(const char* s, std::streamsize n); |
| std::streampos seek(stream_offset off, BOOST_IOS::seekdir way); |
| static file_handle invalid_handle(); |
| file_handle handle_; |
| int flags_; |
| }; |
| |
| //------------------Implementation of file_descriptor_impl--------------------// |
| |
| file_descriptor_impl::file_descriptor_impl() |
| : handle_(invalid_handle()), flags_(0) |
| { } |
| |
| file_descriptor_impl::~file_descriptor_impl() |
| { |
| close_impl(flags_ & close_on_exit, false); |
| } |
| |
| void file_descriptor_impl::open(file_handle fd, flags f) |
| { |
| // Using 'close' to close the existing handle so that it will throw an |
| // exception if it fails. |
| // |
| // Only closing after assigning the new handle, so that the class will |
| // take ownership of the handle regardless of whether close throws. |
| |
| file_descriptor_impl tmp; |
| tmp.handle_ = handle_; |
| tmp.flags_ = flags_ & close_on_exit ? close_on_close : never_close; |
| |
| handle_ = fd; |
| flags_ = f; |
| |
| tmp.close(); |
| } |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| void file_descriptor_impl::open(int fd, flags f) |
| { open(reinterpret_cast<file_handle>(_get_osfhandle(fd)), f); } |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| void file_descriptor_impl::open(const detail::path& p, BOOST_IOS::openmode mode) |
| { |
| close_impl(flags_ & close_on_exit, true); |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| DWORD dwDesiredAccess; |
| DWORD dwCreationDisposition; |
| if ( (mode & (BOOST_IOS::in | BOOST_IOS::out)) |
| == |
| (BOOST_IOS::in | BOOST_IOS::out) ) |
| { |
| if (mode & BOOST_IOS::app) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; |
| dwCreationDisposition = |
| (mode & BOOST_IOS::trunc) ? |
| CREATE_ALWAYS : |
| OPEN_EXISTING; |
| } else if (mode & BOOST_IOS::in) { |
| if (mode & (BOOST_IOS::app | BOOST_IOS::trunc)) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| dwDesiredAccess = GENERIC_READ; |
| dwCreationDisposition = OPEN_EXISTING; |
| } else if (mode & BOOST_IOS::out) { |
| if ( (mode & (BOOST_IOS::app | BOOST_IOS::trunc)) |
| == |
| (BOOST_IOS::app | BOOST_IOS::trunc) ) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| if (mode & BOOST_IOS::app) { |
| dwCreationDisposition = OPEN_ALWAYS; |
| dwDesiredAccess = |
| FILE_APPEND_DATA | |
| FILE_WRITE_ATTRIBUTES | |
| FILE_WRITE_EA | |
| STANDARD_RIGHTS_WRITE | |
| SYNCHRONIZE; |
| } else { |
| dwDesiredAccess = GENERIC_WRITE; |
| dwCreationDisposition = CREATE_ALWAYS; |
| } |
| } else { |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| } |
| |
| HANDLE handle = p.is_wide() ? |
| ::CreateFileW( p.c_wstr(), |
| dwDesiredAccess, |
| FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, // lpSecurityAttributes |
| dwCreationDisposition, |
| FILE_ATTRIBUTE_NORMAL, |
| NULL ) : // hTemplateFile |
| ::CreateFileA( p.c_str(), |
| dwDesiredAccess, |
| FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, // lpSecurityAttributes |
| dwCreationDisposition, |
| FILE_ATTRIBUTE_NORMAL, |
| NULL ); // hTemplateFile |
| if (handle != INVALID_HANDLE_VALUE) { |
| handle_ = handle; |
| flags_ = close_always; |
| } else { |
| flags_ = 0; |
| throw_system_failure("failed opening file"); |
| } |
| #else // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------// |
| |
| // Calculate oflag argument to open. |
| |
| int oflag = 0; |
| if ( (mode & (BOOST_IOS::in | BOOST_IOS::out)) |
| == |
| (BOOST_IOS::in | BOOST_IOS::out) ) |
| { |
| if( mode & BOOST_IOS::app ) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| oflag |= O_RDWR; |
| if( mode & BOOST_IOS::trunc ) { |
| oflag |= O_TRUNC; |
| oflag |= O_CREAT; |
| } |
| } else if (mode & BOOST_IOS::in) { |
| if( mode & (BOOST_IOS::app | BOOST_IOS::trunc) ) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| oflag |= O_RDONLY; |
| } else if (mode & BOOST_IOS::out) { |
| if( (mode & (BOOST_IOS::app | BOOST_IOS::trunc)) |
| == |
| (BOOST_IOS::app | BOOST_IOS::trunc) ) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| oflag |= O_WRONLY; |
| if (mode & BOOST_IOS::app) |
| oflag |= O_APPEND; |
| else { |
| oflag |= O_CREAT; |
| oflag |= O_TRUNC; |
| } |
| } else { |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode")); |
| } |
| #ifdef _LARGEFILE64_SOURCE |
| oflag |= O_LARGEFILE; |
| #endif |
| |
| // Calculate pmode argument to open. |
| |
| mode_t pmode = S_IRUSR | S_IWUSR | |
| S_IRGRP | S_IWGRP | |
| S_IROTH | S_IWOTH; |
| |
| // Open file. |
| |
| int fd = BOOST_IOSTREAMS_FD_OPEN(p.c_str(), oflag, pmode); |
| if (fd == -1) { |
| boost::throw_exception(system_failure("failed opening file")); |
| } else { |
| handle_ = fd; |
| flags_ = close_always; |
| } |
| #endif // #ifndef BOOST_IOSTREAMS_WINDOWS //----------------------------------// |
| } |
| |
| bool file_descriptor_impl::is_open() const |
| { return handle_ != invalid_handle(); } |
| |
| void file_descriptor_impl::close() |
| { |
| close_impl(flags_ & close_on_close, true); |
| } |
| |
| void file_descriptor_impl::close_impl(bool close_flag, bool throw_) { |
| if (handle_ != invalid_handle()) { |
| if (close_flag) { |
| bool success = |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| ::CloseHandle(handle_) == 1; |
| #else |
| BOOST_IOSTREAMS_FD_CLOSE(handle_) != -1; |
| #endif |
| if (!success && throw_) |
| throw_system_failure("failed closing file"); |
| } |
| handle_ = invalid_handle(); |
| flags_ = 0; |
| } |
| } |
| |
| std::streamsize file_descriptor_impl::read(char* s, std::streamsize n) |
| { |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| DWORD result; |
| if (!::ReadFile(handle_, s, n, &result, NULL)) |
| throw_system_failure("failed reading"); |
| return result == 0 ? -1 : static_cast<std::streamsize>(result); |
| #else // #ifdef BOOST_IOSTREAMS_WINDOWS |
| errno = 0; |
| std::streamsize result = BOOST_IOSTREAMS_FD_READ(handle_, s, n); |
| if (errno != 0) |
| throw_system_failure("failed reading"); |
| return result == 0 ? -1 : result; |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS |
| } |
| |
| std::streamsize file_descriptor_impl::write(const char* s, std::streamsize n) |
| { |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| DWORD ignore; |
| if (!::WriteFile(handle_, s, n, &ignore, NULL)) |
| throw_system_failure("failed writing"); |
| return n; |
| #else // #ifdef BOOST_IOSTREAMS_WINDOWS |
| int amt = BOOST_IOSTREAMS_FD_WRITE(handle_, s, n); |
| if (amt < n) // Handles blocking fd's only. |
| throw_system_failure("failed writing"); |
| return n; |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS |
| } |
| |
| std::streampos file_descriptor_impl::seek |
| (stream_offset off, BOOST_IOS::seekdir way) |
| { |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| LONG lDistanceToMove = static_cast<LONG>(off & 0xffffffff); |
| LONG lDistanceToMoveHigh = static_cast<LONG>(off >> 32); |
| DWORD dwResultLow = |
| ::SetFilePointer( handle_, |
| lDistanceToMove, |
| &lDistanceToMoveHigh, |
| way == BOOST_IOS::beg ? |
| FILE_BEGIN : |
| way == BOOST_IOS::cur ? |
| FILE_CURRENT : |
| FILE_END ); |
| if ( dwResultLow == INVALID_SET_FILE_POINTER && |
| ::GetLastError() != NO_ERROR ) |
| { |
| boost::throw_exception(system_failure("failed seeking")); |
| } else { |
| return offset_to_position( |
| (stream_offset(lDistanceToMoveHigh) << 32) + dwResultLow |
| ); |
| } |
| #else // #ifdef BOOST_IOSTREAMS_WINDOWS |
| if ( off > integer_traits<BOOST_IOSTREAMS_FD_OFFSET>::const_max || |
| off < integer_traits<BOOST_IOSTREAMS_FD_OFFSET>::const_min ) |
| { |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad offset")); |
| } |
| stream_offset result = |
| BOOST_IOSTREAMS_FD_SEEK( |
| handle_, |
| static_cast<BOOST_IOSTREAMS_FD_OFFSET>(off), |
| ( way == BOOST_IOS::beg ? |
| SEEK_SET : |
| way == BOOST_IOS::cur ? |
| SEEK_CUR : |
| SEEK_END ) |
| ); |
| if (result == -1) |
| boost::throw_exception(system_failure("failed seeking")); |
| return offset_to_position(result); |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS |
| } |
| |
| // Returns the value stored in a file_handle variable when no file is open |
| file_handle file_descriptor_impl::invalid_handle() |
| { |
| #ifdef BOOST_IOSTREAMS_WINDOWS |
| return INVALID_HANDLE_VALUE; |
| #else |
| return -1; |
| #endif |
| } |
| |
| } // End namespace detail. |
| |
| //------------------Implementation of file_descriptor-------------------------// |
| |
| file_descriptor::file_descriptor() : pimpl_(new impl_type) { } |
| |
| file_descriptor::file_descriptor(handle_type fd, file_descriptor_flags f) |
| : pimpl_(new impl_type) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor::file_descriptor(handle_type fd, bool close_on_exit) |
| : pimpl_(new impl_type) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| file_descriptor::file_descriptor(int fd, file_descriptor_flags f) |
| : pimpl_(new impl_type) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor::file_descriptor(int fd, bool close_on_exit) |
| : pimpl_(new impl_type) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| file_descriptor::file_descriptor( const std::string& path, |
| BOOST_IOS::openmode mode ) |
| : pimpl_(new impl_type) |
| { open(path, mode); } |
| |
| file_descriptor::file_descriptor( const char* path, |
| BOOST_IOS::openmode mode ) |
| : pimpl_(new impl_type) |
| { open(path, mode); } |
| |
| file_descriptor::file_descriptor(const file_descriptor& other) |
| : pimpl_(other.pimpl_) |
| { } |
| |
| void file_descriptor::open(handle_type fd, file_descriptor_flags f) |
| { pimpl_->open(fd, static_cast<detail::file_descriptor_impl::flags>(f)); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor::open(handle_type fd, bool close_on_exit) |
| { pimpl_->open(fd, close_on_exit ? |
| detail::file_descriptor_impl::close_always : |
| detail::file_descriptor_impl::close_on_close); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| void file_descriptor::open(int fd, file_descriptor_flags f) |
| { pimpl_->open(fd, static_cast<detail::file_descriptor_impl::flags>(f)); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor::open(int fd, bool close_on_exit) |
| { pimpl_->open(fd, close_on_exit ? |
| detail::file_descriptor_impl::close_always : |
| detail::file_descriptor_impl::close_on_close); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| void file_descriptor::open(const std::string& path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| void file_descriptor::open(const char* path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| bool file_descriptor::is_open() const { return pimpl_->is_open(); } |
| |
| void file_descriptor::close() { pimpl_->close(); } |
| |
| std::streamsize file_descriptor::read(char_type* s, std::streamsize n) |
| { return pimpl_->read(s, n); } |
| |
| std::streamsize file_descriptor::write(const char_type* s, std::streamsize n) |
| { return pimpl_->write(s, n); } |
| |
| std::streampos file_descriptor::seek(stream_offset off, BOOST_IOS::seekdir way) |
| { return pimpl_->seek(off, way); } |
| |
| detail::file_handle file_descriptor::handle() const { return pimpl_->handle_; } |
| |
| void file_descriptor::init() { pimpl_.reset(new impl_type); } |
| |
| void file_descriptor::open( |
| const detail::path& path, |
| BOOST_IOS::openmode mode, |
| BOOST_IOS::openmode base ) |
| { |
| mode |= base; |
| pimpl_->open(path, mode); |
| } |
| |
| //------------------Implementation of file_descriptor_source------------------// |
| |
| file_descriptor_source::file_descriptor_source( |
| handle_type fd, file_descriptor_flags f) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor_source::file_descriptor_source( |
| handle_type fd, bool close_on_exit) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| file_descriptor_source::file_descriptor_source(int fd, file_descriptor_flags f) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor_source::file_descriptor_source(int fd, bool close_on_exit) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| file_descriptor_source::file_descriptor_source( |
| const std::string& path, BOOST_IOS::openmode mode) |
| { open(path, mode); } |
| |
| file_descriptor_source::file_descriptor_source( |
| const char* path, BOOST_IOS::openmode mode) |
| { open(path, mode); } |
| |
| file_descriptor_source::file_descriptor_source( |
| const file_descriptor_source& other) |
| : file_descriptor(static_cast<const file_descriptor&>(other)) |
| { } |
| |
| void file_descriptor_source::open(handle_type fd, file_descriptor_flags f) |
| { file_descriptor::open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor_source::open(handle_type fd, bool close_on_exit) |
| { file_descriptor::open(fd, close_on_exit); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| void file_descriptor_source::open(int fd, file_descriptor_flags f) |
| { file_descriptor::open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor_source::open(int fd, bool close_on_exit) |
| { file_descriptor::open(fd, close_on_exit); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| void file_descriptor_source::open( |
| const std::string& path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| void file_descriptor_source::open( |
| const char* path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| void file_descriptor_source::open( |
| const detail::path& path, BOOST_IOS::openmode mode) |
| { |
| if (mode & (BOOST_IOS::out | BOOST_IOS::app | BOOST_IOS::trunc)) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode")); |
| file_descriptor::open(path, mode, BOOST_IOS::in); |
| } |
| |
| //------------------Implementation of file_descriptor_sink--------------------// |
| |
| file_descriptor_sink::file_descriptor_sink( |
| handle_type fd, file_descriptor_flags f) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor_sink::file_descriptor_sink( |
| handle_type fd, bool close_on_exit) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| file_descriptor_sink::file_descriptor_sink(int fd, file_descriptor_flags f) |
| { open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| file_descriptor_sink::file_descriptor_sink(int fd, bool close_on_exit) |
| { open(fd, close_on_exit); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| file_descriptor_sink::file_descriptor_sink( |
| const std::string& path, BOOST_IOS::openmode mode) |
| { open(path, mode); } |
| |
| file_descriptor_sink::file_descriptor_sink( |
| const char* path, BOOST_IOS::openmode mode) |
| { open(path, mode); } |
| |
| file_descriptor_sink::file_descriptor_sink(const file_descriptor_sink& other) |
| : file_descriptor(static_cast<const file_descriptor&>(other)) |
| { } |
| |
| void file_descriptor_sink::open(handle_type fd, file_descriptor_flags f) |
| { file_descriptor::open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor_sink::open(handle_type fd, bool close_on_exit) |
| { file_descriptor::open(fd, close_on_exit); } |
| #endif |
| |
| #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------// |
| |
| void file_descriptor_sink::open(int fd, file_descriptor_flags f) |
| { file_descriptor::open(fd, f); } |
| |
| #if defined(BOOST_IOSTREAMS_USE_DEPRECATED) |
| void file_descriptor_sink::open(int fd, bool close_on_exit) |
| { file_descriptor::open(fd, close_on_exit); } |
| #endif |
| |
| #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------// |
| |
| void file_descriptor_sink::open( |
| const std::string& path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| void file_descriptor_sink::open( |
| const char* path, BOOST_IOS::openmode mode) |
| { open(detail::path(path), mode); } |
| |
| void file_descriptor_sink::open( |
| const detail::path& path, BOOST_IOS::openmode mode) |
| { |
| if (mode & BOOST_IOS::in) |
| boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode")); |
| file_descriptor::open(path, mode, BOOST_IOS::out); |
| } |
| |
| } } // End namespaces iostreams, boost. |