// // Boost.Process // ~~~~~~~~~~~~~ // // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008, 2009 Boris Schaeling // // 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) // /** * \file boost/process/detail/file_handle.hpp * * Includes the declaration of the file_handle class. This file is for * internal usage only and must not be included by the library user. */ #ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP #define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP #include #if defined(BOOST_POSIX_API) # include # include #elif defined(BOOST_WINDOWS_API) # include #else # error "Unsupported platform." #endif #include #include #include namespace boost { namespace process { namespace detail { /** * Simple RAII model for system file handles. * * The \a file_handle class is a simple RAII model for native system file * handles. This class wraps one of such handles grabbing its ownership, * and automaticaly closes it upon destruction. It is basically used * inside the library to avoid leaking open file handles, shall an * unexpected execution trace occur. * * A \a file_handle object can be copied but doing so invalidates the * source object. There can only be a single valid \a file_handle object * for a given system file handle. This is similar to std::auto_ptr's * semantics. * * This class also provides some convenience methods to issue special file * operations under their respective platforms. */ class file_handle { public: #if defined(BOOST_PROCESS_DOXYGEN) /** * Opaque name for the native handle type. * * Each operating system identifies file handles using a specific type. * The \a handle_type type is used to transparently refer to file * handles regarless of the operating system in which this class is * used. * * If this class is used on a POSIX system, \a NativeSystemHandle is * an integer type while it is a \a HANDLE on a Windows system. */ typedef NativeSystemHandle handle_type; #elif defined(BOOST_POSIX_API) typedef int handle_type; #elif defined(BOOST_WINDOWS_API) typedef HANDLE handle_type; #endif /** * Constructs an invalid file handle. * * This constructor creates a new \a file_handle object that represents * an invalid file handle. An invalid file handle can be copied but * cannot be manipulated in any way (except checking for its validity). * * \see valid() */ file_handle() : handle_(invalid_value()) { } /** * Constructs a new file handle from a native file handle. * * This constructor creates a new \a file_handle object that takes * ownership of the given \a h native file handle. The user must not * close \a h on his own during the lifetime of the new object. * Ownership can be reclaimed using release(). * * \pre The native file handle must be valid; a close operation must * succeed on it. * \see release() */ file_handle(handle_type h) : handle_(h) { BOOST_ASSERT(handle_ != invalid_value()); } /** * Copy constructor; invalidates the source handle. * * This copy constructor creates a new file handle from a given one. * Ownership of the native file handle is transferred to the new * object, effectively invalidating the source file handle. This * avoids having two live \a file_handle objects referring to the * same native file handle. The source file handle needs not be * valid in the name of simplicity. * * \post The source file handle is invalid. * \post The new file handle owns the source's native file handle. */ file_handle(const file_handle &fh) : handle_(fh.handle_) { fh.handle_ = invalid_value(); } /** * Releases resources if the handle is valid. * * If the file handle is valid, the destructor closes it. * * \see valid() */ ~file_handle() { if (valid()) close(); } /** * Assignment operator; invalidates the source handle. * * This assignment operator transfers ownership of the RHS file * handle to the LHS one, effectively invalidating the source file * handle. This avoids having two live \a file_handle objects * referring to the same native file handle. The source file * handle needs not be valid in the name of simplicity. * * \post The RHS file handle is invalid. * \post The LHS file handle owns RHS' native file handle. * \return A reference to the LHS file handle. */ file_handle &operator=(const file_handle &fh) { handle_ = fh.handle_; fh.handle_ = invalid_value(); return *this; } /** * Checks whether the file handle is valid or not. * * Returns a boolean indicating whether the file handle is valid or * not. If the file handle is invalid, no other methods can be * executed other than the destructor. * * \return true if the file handle is valid; false otherwise. */ bool valid() const { return handle_ != invalid_value(); } /** * Closes the file handle. * * Explicitly closes the file handle, which must be valid. Upon * exit, the handle is not valid any more. * * \pre The file handle is valid. * \post The file handle is invalid. * \post The native file handle is closed. */ void close() { BOOST_ASSERT(valid()); #if defined(BOOST_POSIX_API) ::close(handle_); #elif defined(BOOST_WINDOWS_API) ::CloseHandle(handle_); #endif handle_ = invalid_value(); } /** * Reclaims ownership of the native file handle. * * Explicitly reclaims ownership of the native file handle contained * in the \a file_handle object, returning the native file handle. * The caller is responsible of closing it later on. * * \pre The file handle is valid. * \post The file handle is invalid. * \return The native file handle. */ handle_type release() { BOOST_ASSERT(valid()); handle_type h = handle_; handle_ = invalid_value(); return h; } /** * Gets the native file handle. * * Returns the native file handle for the \a file_handle object. * The caller can issue any operation on it except closing it. * If closing is required, release() shall be used. * * \pre The file handle is valid. * \post The file handle is valid. * \return The native file handle. */ handle_type get() const { BOOST_ASSERT(valid()); return handle_; } #if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) /** * Changes the native file handle to the given one. * * Given a new native file handle \a h, this operation assigns this * handle to the current object, closing its old native file handle. * In other words, it first calls dup2() to remap the old handle to * the new one and then closes the old handle. * * If \a h is open, it is automatically closed by dup2(). * * This operation is only available in POSIX systems. * * \pre The file handle is valid. * \pre The native file handle \a h is valid; i.e., it must be * closeable. * \post The file handle's native file handle is \a h. * \throw boost::system::system_error If the internal remapping * operation fails. */ void posix_remap(handle_type h) { BOOST_ASSERT(valid()); if (::dup2(handle_, h) == -1) boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed")); if (::close(handle_) == -1) { ::close(h); boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed")); } handle_ = h; } /** * Duplicates an open native file handle. * * Given a native file handle \a h1, this routine duplicates it so * that it ends up being identified by the native file handle \a h2 * and returns a new \a file_handle owning \a h2. * * This operation is only available in POSIX systems. * * \pre The native file handle \a h1 is open. * \pre The native file handle \a h2 is valid (non-negative). * \post The native file handle \a h1 is closed. * \post The native file handle \a h2 is the same as the old \a h1 * from the operating system's point of view. * \return A new \a file_handle object that owns \a h2. * \throw boost::system::system_error If dup2() fails. */ static file_handle posix_dup(int h1, int h2) { if (::dup2(h1, h2) == -1) boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed")); return file_handle(h2); } #endif #if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN) /** * Duplicates the \a h native file handle. * * Given a native file handle \a h, this routine constructs a new * \a file_handle object that owns a new duplicate of \a h. The * duplicate's inheritable flag is set to the value of \a inheritable. * * This operation is only available in Windows systems. * * \pre The native file handle \a h is valid. * \return A file handle owning a duplicate of \a h. * \throw boost::system::system_error If DuplicateHandle() fails. */ static file_handle win32_dup(HANDLE h, bool inheritable) { HANDLE h2; if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed")); return file_handle(h2); } /** * Creates a new duplicate of a standard file handle. * * Constructs a new \a file_handle object that owns a duplicate of a * standard file handle. The \a d parameter specifies which standard * file handle to duplicate and can be one of \a STD_INPUT_HANDLE, * \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's * inheritable flag is set to the value of \a inheritable. * * This operation is only available in Windows systems. * * \pre \a d refers to one of the standard handles as described above. * \return A file handle owning a duplicate of the standard handle * referred to by \a d. * \throw boost::system::system_error If GetStdHandle() or * DuplicateHandle() fails. */ static file_handle win32_std(DWORD d, bool inheritable) { BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE); HANDLE h = ::GetStdHandle(d); if (h == INVALID_HANDLE_VALUE) boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed")); return win32_dup(h, inheritable); } /** * Changes the file handle's inheritable flag. * * Changes the file handle's inheritable flag to \a i. It is not * necessary for the file handle's flag to be different than \a i. * * This operation is only available in Windows systems. * * \pre The file handle is valid. * \post The native file handle's inheritable flag is set to \a i. * \throw boost::system::system_error If the property change fails. */ void win32_set_inheritable(bool i) { BOOST_ASSERT(valid()); if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0)) boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed")); } #endif private: /** * Internal handle value. * * This variable holds the native handle value for the file handle * hold by this object. It is interesting to note that this needs * to be mutable because the copy constructor and the assignment * operator invalidate the source object. */ mutable handle_type handle_; /** * Constant function representing an invalid handle value. * * Returns the platform-specific handle value that represents an * invalid handle. This is a constant function rather than a regular * constant because, in the latter case, we cannot define it under * Windows due to the value being of a complex type. */ static const handle_type invalid_value() { #if defined(BOOST_POSIX_API) return -1; #elif defined(BOOST_WINDOWS_API) return INVALID_HANDLE_VALUE; #endif } }; } } } #endif