You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
14 KiB
406 lines
14 KiB
//
|
|
// 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 <boost/process/config.hpp>
|
|
|
|
#if defined(BOOST_POSIX_API)
|
|
# include <cerrno>
|
|
# include <unistd.h>
|
|
#elif defined(BOOST_WINDOWS_API)
|
|
# include <windows.h>
|
|
#else
|
|
# error "Unsupported platform."
|
|
#endif
|
|
|
|
#include <boost/assert.hpp>
|
|
#include <boost/system/system_error.hpp>
|
|
#include <boost/throw_exception.hpp>
|
|
|
|
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 handle_type invalid_value()
|
|
{
|
|
#if defined(BOOST_POSIX_API)
|
|
return -1;
|
|
#elif defined(BOOST_WINDOWS_API)
|
|
return INVALID_HANDLE_VALUE;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|