|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r61903 - sandbox/process/boost/process/detail
From: fotanus_at_[hidden]
Date: 2010-05-11 01:16:12
Author: fotanus
Date: 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
New Revision: 61903
URL: http://svn.boost.org/trac/boost/changeset/61903
Log:
Missing files from the last commit.
Snapshot from previous work
Added:
sandbox/process/boost/process/detail/
sandbox/process/boost/process/detail/file_handle.hpp (contents, props changed)
sandbox/process/boost/process/detail/pipe.hpp (contents, props changed)
sandbox/process/boost/process/detail/posix_ops.hpp (contents, props changed)
sandbox/process/boost/process/detail/stream_info.hpp (contents, props changed)
sandbox/process/boost/process/detail/systembuf.hpp (contents, props changed)
sandbox/process/boost/process/detail/win32_ops.hpp (contents, props changed)
Added: sandbox/process/boost/process/detail/file_handle.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/file_handle.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,406 @@
+//
+// 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 const handle_type invalid_value()
+ {
+#if defined(BOOST_POSIX_API)
+ return -1;
+#elif defined(BOOST_WINDOWS_API)
+ return INVALID_HANDLE_VALUE;
+#endif
+ }
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/pipe.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/pipe.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,187 @@
+//
+// 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/pipe.hpp
+ *
+ * Includes the declaration of the pipe class. This file is for
+ * internal usage only and must not be included by the library user.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP
+#define BOOST_PROCESS_DETAIL_PIPE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+# include <cerrno>
+#elif defined(BOOST_WINDOWS_API)
+# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
+# include <boost/lexical_cast.hpp>
+# include <string>
+# endif
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Simple RAII model for anonymous pipes.
+ *
+ * The pipe class is a simple RAII model for anonymous pipes. It
+ * provides a portable constructor that allocates a new %pipe and creates
+ * a pipe object that owns the two file handles associated to it: the
+ * read end and the write end.
+ *
+ * These handles can be retrieved for modification according to
+ * file_handle semantics. Optionally, their ownership can be transferred
+ * to external \a file_handle objects which comes handy when the two
+ * ends need to be used in different places (i.e. after a POSIX fork()
+ * system call).
+ *
+ * Pipes can be copied following the same semantics as file handles.
+ * In other words, copying a %pipe object invalidates the source one.
+ *
+ * \see file_handle
+ */
+class pipe
+{
+public:
+ /**
+ * Creates a new %pipe.
+ *
+ * The default pipe constructor allocates a new anonymous %pipe
+ * and assigns its ownership to the created pipe object. On Windows
+ * when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined
+ * a named pipe is created. This is required if asynchronous I/O
+ * should be used as asynchronous I/O is only supported by named
+ * pipes on Windows.
+ *
+ * \throw boost::system::system_error If the anonymous %pipe
+ * creation fails.
+ */
+ pipe()
+ {
+ file_handle::handle_type hs[2];
+
+#if defined(BOOST_POSIX_API)
+ if (::pipe(hs) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed"));
+#elif defined(BOOST_WINDOWS_API)
+ SECURITY_ATTRIBUTES sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = FALSE;
+
+# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
+ static unsigned int nextid = 0;
+ std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast<std::string>(::GetCurrentProcessId()) + "_" + boost::lexical_cast<std::string>(nextid++);
+ hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa);
+ if (hs[0] == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateNamedPipe failed"));
+ hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (hs[1] == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateFile failed"));
+
+ OVERLAPPED overlapped;
+ ZeroMemory(&overlapped, sizeof(overlapped));
+ overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!overlapped.hEvent)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateEvent failed"));
+ BOOL b = ::ConnectNamedPipe(hs[0], &overlapped);
+ if (!b)
+ {
+ if (::GetLastError() == ERROR_IO_PENDING)
+ {
+ if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED)
+ {
+ ::CloseHandle(overlapped.hEvent);
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: WaitForSingleObject failed"));
+ }
+ }
+ else if (::GetLastError() != ERROR_PIPE_CONNECTED)
+ {
+ ::CloseHandle(overlapped.hEvent);
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: ConnectNamedPipe failed"));
+ }
+ }
+ ::CloseHandle(overlapped.hEvent);
+# else
+ if (!::CreatePipe(&hs[0], &hs[1], &sa, 0))
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreatePipe failed"));
+# endif
+#endif
+
+ read_end_ = file_handle(hs[0]);
+ write_end_ = file_handle(hs[1]);
+ }
+
+ /**
+ * Returns the %pipe's read end file handle.
+ *
+ * Obtains a reference to the %pipe's read end file handle. Care
+ * should be taken to not duplicate the returned object if ownership
+ * shall remain to the %pipe.
+ *
+ * Duplicating the returned object invalidates its corresponding file
+ * handle in the %pipe.
+ *
+ * \return A reference to the %pipe's read end file handle.
+ */
+ file_handle &rend()
+ {
+ return read_end_;
+ }
+
+ /**
+ * Returns the %pipe's write end file handle.
+ *
+ * Obtains a reference to the %pipe's write end file handle. Care
+ * should be taken to not duplicate the returned object if ownership
+ * shall remain to the %pipe.
+ *
+ * Duplicating the returned object invalidates its corresponding file
+ * handle in the %pipe.
+ *
+ * \return A reference to the %pipe's write end file handle.
+ */
+ file_handle &wend()
+ {
+ return write_end_;
+ }
+
+private:
+ /**
+ * The %pipe's read end file handle.
+ */
+ file_handle read_end_;
+
+ /**
+ * The %pipe's write end file handle.
+ */
+ file_handle write_end_;
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/posix_ops.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/posix_ops.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,495 @@
+//
+// 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/posix_ops.hpp
+ *
+ * Provides some convenience functions to start processes under POSIX
+ * operating systems.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
+#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
+
+#include <boost/process/environment.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <map>
+#include <utility>
+#include <string>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts the command line to an array of C strings.
+ *
+ * Converts the command line's list of arguments to the format expected
+ * by the \a argv parameter in the POSIX execve() system call.
+ *
+ * This operation is only available on POSIX systems.
+ *
+ * \return The first argument of the pair is an integer that indicates
+ * how many strings are stored in the second argument. The
+ * second argument is a NULL-terminated, dynamically allocated
+ * array of dynamically allocated strings holding the arguments
+ * to the executable. The caller is responsible of freeing them.
+ */
+template <class Arguments>
+inline std::pair<std::size_t, char**> collection_to_posix_argv(const Arguments &args)
+{
+ std::size_t nargs = args.size();
+ BOOST_ASSERT(nargs > 0);
+
+ char **argv = new char*[nargs + 1];
+ typename Arguments::size_type i = 0;
+ for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
+ {
+ argv[i] = new char[it->size() + 1];
+ std::strncpy(argv[i], it->c_str(), it->size() + 1);
+ ++i;
+ }
+ argv[nargs] = 0;
+
+ return std::pair<std::size_t, char**>(nargs, argv);
+}
+
+/**
+ * Converts an environment to a char** table as used by execve().
+ *
+ * Converts the environment's contents to the format used by the
+ * execve() system call. The returned char** array is allocated
+ * in dynamic memory; the caller must free it when not used any
+ * more. Each entry is also allocated in dynamic memory and is a
+ * NULL-terminated string of the form var=value; these must also be
+ * released by the caller.
+ *
+ * \return A dynamically allocated char** array that represents
+ * the environment's content. Each array entry is a
+ * NULL-terminated string of the form var=value.
+ */
+inline char **environment_to_envp(const environment &env)
+{
+ char **envp = new char*[env.size() + 1];
+
+ environment::size_type i = 0;
+ for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
+ {
+ std::string s = it->first + "=" + it->second;
+ envp[i] = new char[s.size() + 1];
+ std::strncpy(envp[i], s.c_str(), s.size() + 1);
+ ++i;
+ }
+ envp[i] = 0;
+
+ return envp;
+}
+
+/**
+ * Holds a mapping between native file descriptors and their corresponding
+ * pipes to set up communication between the parent and the %child process.
+ */
+typedef std::map<int, stream_info> info_map;
+
+/**
+ * Helper class to configure a POSIX %child.
+ *
+ * This helper class is used to hold all the attributes that configure a
+ * new POSIX %child process and to centralize all the actions needed to
+ * make them effective.
+ *
+ * All its fields are public for simplicity. It is only intended for
+ * internal use and it is heavily coupled with the Context
+ * implementations.
+ */
+struct posix_setup
+{
+ /**
+ * The work directory.
+ *
+ * This string specifies the directory in which the %child process
+ * starts execution. It cannot be empty.
+ */
+ std::string work_directory;
+
+ /**
+ * The chroot directory, if any.
+ *
+ * Specifies the directory in which the %child process is chrooted
+ * before execution. Empty if this feature is not desired.
+ */
+ std::string chroot;
+
+ /**
+ * The user credentials.
+ *
+ * UID that specifies the user credentials to use to run the %child
+ * process. Defaults to the current UID.
+ */
+ uid_t uid;
+
+ /**
+ * The effective user credentials.
+ *
+ * EUID that specifies the effective user credentials to use to run
+ * the %child process. Defaults to the current EUID.
+ */
+ uid_t euid;
+
+ /**
+ * The group credentials.
+ *
+ * GID that specifies the group credentials to use to run the %child
+ * process. Defaults to the current GID.
+ */
+ gid_t gid;
+
+ /**
+ * The effective group credentials.
+ *
+ * EGID that specifies the effective group credentials to use to run
+ * the %child process. Defaults to the current EGID.
+ */
+ gid_t egid;
+
+ /**
+ * Creates a new properties set.
+ *
+ * Creates a new object that has sensible default values for all the
+ * properties.
+ */
+ posix_setup()
+ : uid(::getuid()),
+ euid(::geteuid()),
+ gid(::getgid()),
+ egid(::getegid())
+ {
+ }
+
+ /**
+ * Sets up the execution environment.
+ *
+ * Modifies the current execution environment (that of the %child) so
+ * that the properties become effective.
+ *
+ * \throw boost::system::system_error If any error ocurred during
+ * environment configuration. The child process should abort
+ * execution if this happens because its start conditions
+ * cannot be met.
+ */
+ void operator()() const
+ {
+ if (!chroot.empty() && ::chroot(chroot.c_str()) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed"));
+
+ if (gid != ::getgid() && ::setgid(gid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed"));
+
+ if (egid != ::getegid() && ::setegid(egid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed"));
+
+ if (uid != ::getuid() && ::setuid(uid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed"));
+
+ if (euid != ::geteuid() && ::seteuid(euid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed"));
+
+ BOOST_ASSERT(!work_directory.empty());
+ if (::chdir(work_directory.c_str()) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed"));
+ }
+};
+
+/**
+ * Configures child process' input streams.
+ *
+ * Sets up the current process' input streams to behave according to the
+ * information in the \a info map. \a closeflags is modified to reflect
+ * those descriptors that should not be closed because they where modified
+ * by the function.
+ *
+ * Modifies the current execution environment, so this should only be run
+ * on the child process after the fork(2) has happened.
+ *
+ * \throw boost::system::system_error If any error occurs during the
+ * configuration.
+ */
+inline void setup_input(info_map &info, bool *closeflags, int maxdescs)
+{
+ for (info_map::iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ stream_info &si = it->second;
+
+ BOOST_ASSERT(d < maxdescs);
+ closeflags[d] = false;
+
+ switch (si.type_)
+ {
+ case stream_info::use_file:
+ {
+ int fd = ::open(si.file_.c_str(), O_RDONLY);
+ if (fd == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed"));
+ if (fd != d)
+ {
+ file_handle h(fd);
+ h.posix_remap(d);
+ h.release();
+ }
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ if (si.handle_.get() != d)
+ si.handle_.posix_remap(d);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ si.pipe_->wend().close();
+ if (d != si.pipe_->rend().get())
+ si.pipe_->rend().posix_remap(d);
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(si.type_ == stream_info::inherit);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Configures child process' output streams.
+ *
+ * Sets up the current process' output streams to behave according to the
+ * information in the \a info map. \a closeflags is modified to reflect
+ * those descriptors that should not be closed because they where
+ * modified by the function.
+ *
+ * Modifies the current execution environment, so this should only be run
+ * on the child process after the fork(2) has happened.
+ *
+ * \throw boost::system::system_error If any error occurs during the
+ * configuration.
+ */
+inline void setup_output(info_map &info, bool *closeflags, int maxdescs)
+{
+ for (info_map::iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ stream_info &si = it->second;
+
+ BOOST_ASSERT(d < maxdescs);
+ closeflags[d] = false;
+
+ switch (si.type_)
+ {
+ case stream_info::redirect:
+ {
+ break;
+ }
+ case stream_info::use_file:
+ {
+ int fd = ::open(si.file_.c_str(), O_WRONLY);
+ if (fd == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed"));
+ if (fd != d)
+ {
+ file_handle h(fd);
+ h.posix_remap(d);
+ h.release();
+ }
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ if (si.handle_.get() != d)
+ si.handle_.posix_remap(d);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ si.pipe_->rend().close();
+ if (d != si.pipe_->wend().get())
+ si.pipe_->wend().posix_remap(d);
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(si.type_ == stream_info::inherit);
+ break;
+ }
+ }
+ }
+
+ for (info_map::const_iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ const stream_info &si = it->second;
+
+ if (si.type_ == stream_info::redirect)
+ file_handle::posix_dup(si.desc_to_, d).release();
+ }
+}
+
+/**
+ * Starts a new child process in a POSIX operating system.
+ *
+ * This helper functions is provided to simplify the Context's task when
+ * it comes to starting up a new process in a POSIX operating system.
+ * The function hides all the details of the fork/exec pair of calls as
+ * well as all the setup of communication pipes and execution environment.
+ *
+ * \param exe The executable to spawn the child process.
+ * \param args The arguments for the executable.
+ * \param env The environment variables that the new child process
+ * receives.
+ * \param infoin A map describing all input file descriptors to be
+ * redirected.
+ * \param infoout A map describing all output file descriptors to be
+ * redirected.
+ * \param setup A helper object used to configure the child's execution
+ * environment.
+ * \return The new process' PID. The caller is responsible of creating
+ * an appropriate Child representation for it.
+ */
+template <class Executable, class Arguments>
+inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup)
+{
+ pid_t pid = ::fork();
+ if (pid == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed"));
+ else if (pid == 0)
+ {
+#if defined(F_MAXFD)
+ int maxdescs = ::fcntl(-1, F_MAXFD, 0);
+ if (maxdescs == -1)
+ maxdescs = ::sysconf(_SC_OPEN_MAX);
+#else
+ int maxdescs = ::sysconf(_SC_OPEN_MAX);
+#endif
+ if (maxdescs == -1)
+ maxdescs = 1024;
+ try
+ {
+ boost::scoped_array<bool> closeflags(new bool[maxdescs]);
+ for (int i = 0; i < maxdescs; ++i)
+ closeflags[i] = true;
+
+ setup_input(infoin, closeflags.get(), maxdescs);
+ setup_output(infoout, closeflags.get(), maxdescs);
+
+ for (int i = 0; i < maxdescs; ++i)
+ {
+ if (closeflags[i])
+ ::close(i);
+ }
+
+ setup();
+ }
+ catch (const boost::system::system_error &e)
+ {
+ ::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
+ ::write(STDERR_FILENO, "\n", 1);
+ std::exit(EXIT_FAILURE);
+ }
+
+ std::pair<std::size_t, char**> argcv = collection_to_posix_argv(args);
+ char **envp = environment_to_envp(env);
+
+ ::execve(exe.c_str(), argcv.second, envp);
+ boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed");
+
+ for (std::size_t i = 0; i < argcv.first; ++i)
+ delete[] argcv.second[i];
+ delete[] argcv.second;
+
+ for (std::size_t i = 0; i < env.size(); ++i)
+ delete[] envp[i];
+ delete[] envp;
+
+ ::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
+ ::write(STDERR_FILENO, "\n", 1);
+ std::exit(EXIT_FAILURE);
+ }
+
+ BOOST_ASSERT(pid > 0);
+
+ for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ si.pipe_->rend().close();
+ }
+
+ for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ si.pipe_->wend().close();
+ }
+
+ return pid;
+}
+
+/**
+ * Locates a communication pipe and returns one of its endpoints.
+ *
+ * Given a \a info map, and a file descriptor \a desc, searches for its
+ * communicataion pipe in the map and returns one of its endpoints as
+ * indicated by the \a out flag. This is intended to be used by a
+ * parent process after a fork(2) call.
+ *
+ * \pre If the info map contains the given descriptor, it is configured
+ * to use a pipe.
+ * \post The info map does not contain the given descriptor.
+ * \return If the file descriptor is found in the map, returns the pipe's
+ * read end if out is true; otherwise its write end. If the
+ * descriptor is not found returns an invalid file handle.
+ */
+inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out)
+{
+ file_handle fh;
+
+ info_map::iterator it = info.find(desc);
+ if (it != info.end())
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ {
+ fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release();
+ BOOST_ASSERT(fh.valid());
+ }
+ info.erase(it);
+ }
+
+ return fh;
+}
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/stream_info.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/stream_info.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,176 @@
+//
+// 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/stream_info.hpp
+ *
+ * Provides the definition of the stream_info structure.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
+#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/optional.hpp>
+#include <boost/assert.hpp>
+#include <string>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Configuration data for a file descriptor.
+ *
+ * This convenience structure provides a compact way to pass information
+ * around on how to configure a file descriptor. It is a lower-level
+ * representation of stream_behavior, as it can hold the same information
+ * but in a way that can be used by the underlying operating system.
+ */
+struct stream_info
+{
+ /**
+ * Supported stream types.
+ */
+ enum type
+ {
+ /**
+ * Matches stream_behavior::close.
+ */
+ close,
+
+ /**
+ * Matches stream_behavior::inherit.
+ */
+ inherit,
+
+ /**
+ * Matches stream_behavior::redirect_to_stdout and
+ * stream_behavior::posix_redirect.
+ */
+ redirect,
+
+ /**
+ * Matches stream_behavior::silence.
+ */
+ use_file,
+
+ /**
+ * TODO: Matches nothing yet ...
+ */
+ use_handle,
+
+ /**
+ * Matches stream_behavior::capture.
+ */
+ use_pipe
+ };
+
+ /**
+ * Stream type.
+ */
+ type type_;
+
+ /**
+ * Descriptor to use when stream type is set to \a redirect.
+ */
+ int desc_to_;
+
+ /**
+ * File to use when stream type is set to \a use_file.
+ */
+ std::string file_;
+
+ /**
+ * Handle to use when stream type is set to \a use_handle.
+ */
+ file_handle handle_;
+
+ /**
+ * Pipe to use when stream type is set to \a use_pipe.
+ */
+ boost::optional<pipe> pipe_;
+
+ /**
+ * Constructs a new stream_info object.
+ */
+ stream_info(const stream_behavior &sb, bool out)
+ {
+ switch (sb.type_)
+ {
+ case stream_behavior::close:
+ {
+ type_ = close;
+ break;
+ }
+ case stream_behavior::inherit:
+ {
+ type_ = inherit;
+ break;
+ }
+ case stream_behavior::redirect_to_stdout:
+ {
+ type_ = redirect;
+#if defined(BOOST_POSIX_API)
+ desc_to_ = STDOUT_FILENO;
+#elif defined(BOOST_WINDOWS_API)
+ desc_to_ = 1;
+#endif
+ break;
+ }
+#if defined(BOOST_POSIX_API)
+ case stream_behavior::posix_redirect:
+ {
+ type_ = redirect;
+ desc_to_ = sb.desc_to_;
+ break;
+ }
+#endif
+ case stream_behavior::silence:
+ {
+ type_ = use_file;
+#if defined(BOOST_POSIX_API)
+ file_ = out ? "/dev/null" : "/dev/zero";
+#elif defined(BOOST_WINDOWS_API)
+ file_ = "NUL";
+#endif
+ break;
+ }
+ case stream_behavior::capture:
+ {
+ type_ = use_pipe;
+ pipe_ = pipe();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ }
+ }
+ }
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/systembuf.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/systembuf.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,231 @@
+//
+// 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/systembuf.hpp
+ *
+ * Includes the declaration of the systembuf class. This file is for
+ * internal usage only and must not be included by the library user.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/types.h>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <streambuf>
+#include <cstddef>
+
+namespace boost {
+namespace process {
+
+class postream;
+
+namespace detail {
+
+/**
+ * std::streambuf implementation for system file handles.
+ *
+ * systembuf provides a std::streambuf implementation for system file
+ * handles. Contrarywise to file_handle, this class does \b not take
+ * ownership of the native file handle; this should be taken care of
+ * somewhere else.
+ *
+ * This class follows the expected semantics of a std::streambuf object.
+ * However, it is not copyable to avoid introducing inconsistences with
+ * the on-disk file and the in-memory buffers.
+ */
+class systembuf : public std::streambuf, public boost::noncopyable
+{
+ friend class ::boost::process::postream;
+
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Opaque name for the native handle type.
+ */
+ typedef NativeHandleType handle_type;
+#elif defined(BOOST_POSIX_API)
+ typedef int handle_type;
+#elif defined(BOOST_WINDOWS_API)
+ typedef HANDLE handle_type;
+#endif
+
+ /**
+ * Constructs a new systembuf for the given file handle.
+ *
+ * This constructor creates a new systembuf object that reads or
+ * writes data from/to the \a h native file handle. This handle
+ * is \b not owned by the created systembuf object; the code
+ * should take care of it externally.
+ *
+ * This class buffers input and output; the buffer size may be
+ * tuned through the \a bufsize parameter, which defaults to 8192
+ * bytes.
+ *
+ * \see pistream and postream
+ */
+ explicit systembuf(handle_type h, std::size_t bufsize = 8192)
+ : handle_(h),
+ bufsize_(bufsize),
+ read_buf_(new char[bufsize]),
+ write_buf_(new char[bufsize])
+ {
+#if defined(BOOST_POSIX_API)
+ BOOST_ASSERT(handle_ >= 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE);
+#endif
+ BOOST_ASSERT(bufsize_ > 0);
+
+ setp(write_buf_.get(), write_buf_.get() + bufsize_);
+ }
+
+protected:
+ /**
+ * Reads new data from the native file handle.
+ *
+ * This operation is called by input methods when there is no more
+ * data in the input buffer. The function fills the buffer with new
+ * data, if available.
+ *
+ * \pre All input positions are exhausted (gptr() >= egptr()).
+ * \post The input buffer has new data, if available.
+ * \returns traits_type::eof() if a read error occurrs or there are
+ * no more data to be read. Otherwise returns
+ * traits_type::to_int_type(*gptr()).
+ */
+ virtual int_type underflow()
+ {
+ BOOST_ASSERT(gptr() >= egptr());
+
+ bool ok;
+#if defined(BOOST_POSIX_API)
+ ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_);
+ ok = (cnt != -1 && cnt != 0);
+#elif defined(BOOST_WINDOWS_API)
+ DWORD cnt;
+ BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL);
+ ok = (res && cnt > 0);
+#endif
+
+ if (!ok)
+ return traits_type::eof();
+ else
+ {
+ setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt);
+ return traits_type::to_int_type(*gptr());
+ }
+ }
+
+ /**
+ * Makes room in the write buffer for additional data.
+ *
+ * This operation is called by output methods when there is no more
+ * space in the output buffer to hold a new element. The function
+ * first flushes the buffer's contents to disk and then clears it to
+ * leave room for more characters. The given \a c character is
+ * stored at the beginning of the new space.
+ *
+ * \pre All output positions are exhausted (pptr() >= epptr()).
+ * \post The output buffer has more space if no errors occurred
+ * during the write to disk.
+ * \post *(pptr() - 1) is \a c.
+ * \returns traits_type::eof() if a write error occurrs. Otherwise
+ * returns traits_type::not_eof(c).
+ */
+ virtual int_type overflow(int c)
+ {
+ BOOST_ASSERT(pptr() >= epptr());
+
+ if (sync() == -1)
+ return traits_type::eof();
+
+ if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ traits_type::assign(*pptr(), c);
+ pbump(1);
+ }
+
+ return traits_type::not_eof(c);
+ }
+
+ /**
+ * Flushes the output buffer to disk.
+ *
+ * Synchronizes the systembuf buffers with the contents of the file
+ * associated to this object through the native file handle. The
+ * output buffer is flushed to disk and cleared to leave new room
+ * for more data.
+ *
+ * \returns 0 on success, -1 if an error occurred.
+ */
+ virtual int sync()
+ {
+#if defined(BOOST_POSIX_API)
+ ssize_t cnt = pptr() - pbase();
+#elif defined(BOOST_WINDOWS_API)
+ long cnt = pptr() - pbase();
+#endif
+
+ bool ok;
+#if defined(BOOST_POSIX_API)
+ ok = ::write(handle_, pbase(), cnt) == cnt;
+#elif defined(BOOST_WINDOWS_API)
+ DWORD rcnt;
+ BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL);
+ ok = (res && static_cast<long>(rcnt) == cnt);
+#endif
+
+ if (ok)
+ pbump(-cnt);
+ return ok ? 0 : -1;
+ }
+
+private:
+ /**
+ * Native file handle used by the systembuf object.
+ */
+ handle_type handle_;
+
+ /**
+ * Internal buffer size used during read and write operations.
+ */
+ std::size_t bufsize_;
+
+ /**
+ * Internal buffer used during read operations.
+ */
+ boost::scoped_array<char> read_buf_;
+
+ /**
+ * Internal buffer used during write operations.
+ */
+ boost::scoped_array<char> write_buf_;
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/win32_ops.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/win32_ops.hpp 2010-05-11 01:16:07 EDT (Tue, 11 May 2010)
@@ -0,0 +1,355 @@
+//
+// 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/win32_ops.hpp
+ *
+ * Provides some convenience functions to start processes under
+ * Windows-compatible operating systems.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
+#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
+
+#include <boost/process/environment.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <vector>
+#include <string>
+#include <cstddef>
+#include <string.h>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts the command line to a plain string. Converts the command line's
+ * list of arguments to the format expected by the \a lpCommandLine parameter
+ * in the CreateProcess() system call.
+ *
+ * This operation is only available on Windows systems.
+ *
+ * \return A dynamically allocated string holding the command line
+ * to be passed to the executable. It is returned in a
+ * shared_array object to ensure its release at some point.
+ */
+template <class Arguments>
+inline boost::shared_array<char> collection_to_win32_cmdline(const Arguments &args)
+{
+ typedef std::vector<std::string> arguments_t;
+ arguments_t args2;
+ typename Arguments::size_type i = 0;
+ std::size_t size = 0;
+ for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
+ {
+ std::string arg = *it;
+
+ std::string::size_type pos = 0;
+ while ( (pos = arg.find('"', pos)) != std::string::npos)
+ {
+ arg.replace(pos, 1, "\\\"");
+ pos += 2;
+ }
+
+ if (arg.find(' ') != std::string::npos)
+ arg = '\"' + arg + '\"';
+
+ if (i++ != args.size() - 1)
+ arg += ' ';
+
+ args2.push_back(arg);
+ size += arg.size() + 1;
+ }
+
+ boost::shared_array<char> cmdline(new char[size]);
+ cmdline.get()[0] = '\0';
+ for (arguments_t::size_type i = 0; i < args.size(); ++i)
+#if defined(__CYGWIN__) || defined(_SCL_SECURE_NO_DEPRECATE)
+ ::strncat(cmdline.get(), args2[i].c_str(), args2[i].size());
+#else
+ ::strcat_s(cmdline.get(), size, args2[i].c_str());
+#endif
+
+ return cmdline;
+}
+
+/**
+ * Converts an environment to a string used by CreateProcess().
+ *
+ * Converts the environment's contents to the format used by the
+ * CreateProcess() system call. The returned char* string is
+ * allocated in dynamic memory; the caller must free it when not
+ * used any more. This is enforced by the use of a shared pointer.
+ *
+ * \return A dynamically allocated char* string that represents
+ * the environment's content. This string is of the form
+ * var1=value1\\0var2=value2\\0\\0.
+ */
+inline boost::shared_array<char> environment_to_win32_strings(const environment &env)
+{
+ boost::shared_array<char> envp;
+
+ if (env.empty())
+ {
+ envp.reset(new char[2]);
+ ::ZeroMemory(envp.get(), 2);
+ }
+ else
+ {
+ std::string s;
+ for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
+ {
+ s += it->first + "=" + it->second;
+ s.push_back(0);
+ }
+
+ envp.reset(new char[s.size() + 1]);
+#if defined(__CYGWIN__) || defined(_SCL_SECURE_NO_DEPRECATE)
+ ::memcpy(envp.get(), s.c_str(), s.size() + 1);
+#else
+ ::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1);
+#endif
+ }
+
+ return envp;
+}
+
+/**
+ * Helper class to configure a Win32 %child.
+ *
+ * This helper class is used to hold all the attributes that configure a
+ * new Win32 %child process.
+ *
+ * All its fields are public for simplicity. It is only intended for
+ * internal use and it is heavily coupled with the Context
+ * implementations.
+ */
+struct win32_setup
+{
+ /**
+ * The work directory.
+ *
+ * This string specifies the directory in which the %child process
+ * starts execution. It cannot be empty.
+ */
+ std::string work_directory;
+
+ /**
+ * The process startup properties.
+ *
+ * This Win32-specific object holds a list of properties that describe
+ * how the new process should be started. The \a STARTF_USESTDHANDLES
+ * flag should not be set in it because it is automatically configured
+ * by win32_start().
+ */
+ STARTUPINFOA *startupinfo;
+};
+
+/**
+ * Starts a new child process in a Win32 operating system.
+ *
+ * This helper functions is provided to simplify the Context's task when
+ * it comes to starting up a new process in a Win32 operating system.
+ *
+ * \param exe The executable to spawn the child process.
+ * \param args The arguments for the executable.
+ * \param env The environment variables that the new child process
+ * receives.
+ * \param infoin Information that describes stdin's behavior.
+ * \param infoout Information that describes stdout's behavior.
+ * \param infoerr Information that describes stderr's behavior.
+ * \param setup A helper object holding extra child information.
+ * \return The new process' information as returned by the CreateProcess()
+ * system call. The caller is responsible of creating an
+ * appropriate Child representation for it.
+ * \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set
+ * in the \a dwFlags field.
+ */
+template <class Executable, class Arguments>
+inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup)
+{
+ file_handle chin, chout, cherr;
+
+ BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA));
+ BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES));
+
+ boost::scoped_ptr<STARTUPINFOA> si(new STARTUPINFOA);
+ ::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo));
+ si->dwFlags |= STARTF_USESTDHANDLES;
+
+ switch (infoin.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ chin = file_handle::win32_std(STD_INPUT_HANDLE, true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ 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::win32_start: CreateFile failed"));
+ chin = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ chin = infoin.handle_;
+ chin.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoin.pipe_->rend().win32_set_inheritable(true);
+ chin = infoin.pipe_->rend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE;
+
+ switch (infoout.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ 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::win32_start: CreateFile failed"));
+ chout = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ chout = infoout.handle_;
+ chout.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoout.pipe_->wend().win32_set_inheritable(true);
+ chout = infoout.pipe_->wend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE;
+
+ switch (infoerr.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ cherr = file_handle::win32_std(STD_ERROR_HANDLE, true);
+ break;
+ }
+ case stream_info::redirect:
+ {
+ BOOST_ASSERT(infoerr.desc_to_ == 1);
+ BOOST_ASSERT(chout.valid());
+ cherr = file_handle::win32_dup(chout.get(), true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ 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::win32_start: CreateFile failed"));
+ cherr = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ cherr = infoerr.handle_;
+ cherr.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoerr.pipe_->wend().win32_set_inheritable(true);
+ cherr = infoerr.pipe_->wend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE;
+
+ PROCESS_INFORMATION pi;
+ ::ZeroMemory(&pi, sizeof(pi));
+
+ boost::shared_array<char> cmdline = collection_to_win32_cmdline(args);
+
+ boost::scoped_array<char> executable(new char[exe.size() + 1]);
+#if defined(__CYGWIN__) || defined(_SCL_SECURE_NO_DEPRECATE)
+ ::strcpy(executable.get(), exe.c_str());
+#else
+ ::strcpy_s(executable.get(), exe.size() + 1, exe.c_str());
+#endif
+
+ boost::scoped_array<char> workdir(new char[setup.work_directory.size() + 1]);
+#if defined(__CYGWIN__) || defined(_SCL_SECURE_NO_DEPRECATE)
+ ::strcpy(workdir.get(), setup.work_directory.c_str());
+#else
+ ::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str());
+#endif
+
+ boost::shared_array<char> envstrs = environment_to_win32_strings(env);
+
+ if (!::CreateProcessA(executable.get(), cmdline.get(), NULL, NULL, TRUE, 0, envstrs.get(), workdir.get(), si.get(), &pi))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed"));
+
+ return pi;
+}
+
+}
+}
+}
+
+#endif
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk