// (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 // knows that we are building the library (possibly exporting code), rather // than using it (possibly importing code). #define BOOST_IOSTREAMS_SOURCE #include #include #include // SEEK_SET, etc. #include // BOOST_JOIN #include #include #include // BOOST_IOSTREAMS_FD_XXX #include #include #include // openmodes, failure. #include #include #include // OS-specific headers for low-level i/o. #include // file opening flags. #include // file access permissions. #ifdef BOOST_IOSTREAMS_WINDOWS # include // low-level file i/o. # define WINDOWS_LEAN_AND_MEAN # include # ifndef INVALID_SET_FILE_POINTER # define INVALID_SET_FILE_POINTER ((DWORD)-1) # endif #else # include // mode_t. # include // 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(_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(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(off & 0xffffffff); LONG lDistanceToMoveHigh = static_cast(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::const_max || off < integer_traits::const_min ) { boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad offset")); } stream_offset result = BOOST_IOSTREAMS_FD_SEEK( handle_, static_cast(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(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(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(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(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.