2 * Copyright Andrey Semashev 2016.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
8 * \file windows/object_name.cpp
9 * \author Andrey Semashev
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
16 #include <boost/log/detail/config.hpp>
22 #include <boost/memory_order.hpp>
23 #include <boost/atomic/atomic.hpp>
24 #include <boost/move/utility_core.hpp>
25 #include <boost/log/exceptions.hpp>
26 #include <boost/log/utility/ipc/object_name.hpp>
27 #include <boost/winapi/get_last_error.hpp>
31 #include "windows/auto_handle.hpp"
32 #include "windows/utf_code_conversion.hpp"
33 #include <boost/log/detail/header.hpp>
37 BOOST_LOG_OPEN_NAMESPACE
41 BOOST_LOG_ANONYMOUS_NAMESPACE
{
43 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
45 class auto_boundary_descriptor
51 explicit auto_boundary_descriptor(HANDLE h
= NULL
) BOOST_NOEXCEPT
: m_handle(h
)
55 ~auto_boundary_descriptor() BOOST_NOEXCEPT
58 DeleteBoundaryDescriptor(m_handle
);
61 void init(HANDLE h
) BOOST_NOEXCEPT
63 BOOST_ASSERT(m_handle
== NULL
);
67 HANDLE
get() const BOOST_NOEXCEPT
{ return m_handle
; }
68 HANDLE
* get_ptr() BOOST_NOEXCEPT
{ return &m_handle
; }
70 void swap(auto_boundary_descriptor
& that
) BOOST_NOEXCEPT
73 m_handle
= that
.m_handle
;
77 BOOST_DELETED_FUNCTION(auto_boundary_descriptor(auto_boundary_descriptor
const&))
78 BOOST_DELETED_FUNCTION(auto_boundary_descriptor
& operator=(auto_boundary_descriptor
const&))
81 //! Handle for the private namespace for \c user scope
82 static boost::atomic
< HANDLE
> g_user_private_namespace
;
84 //! Closes the private namespace on process exit
85 void close_user_namespace()
87 HANDLE h
= g_user_private_namespace
.load(boost::memory_order_acquire
);
90 ClosePrivateNamespace(h
, 0);
91 g_user_private_namespace
.store((HANDLE
)NULL
, boost::memory_order_release
);
95 //! Attempts to create or open the private namespace
96 bool init_user_namespace()
98 HANDLE h
= g_user_private_namespace
.load(boost::memory_order_acquire
);
99 if (BOOST_UNLIKELY(!h
))
101 // Obtain the current user SID
102 boost::log::ipc::aux::auto_handle h_process_token
;
103 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, h_process_token
.get_ptr()))
106 DWORD token_user_size
= 0;
107 GetTokenInformation(h_process_token
.get(), TokenUser
, NULL
, 0u, &token_user_size
);
108 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
|| token_user_size
< sizeof(TOKEN_USER
))
110 std::vector
< unsigned char > token_user_storage(static_cast< std::size_t >(token_user_size
), static_cast< unsigned char >(0u));
111 if (!GetTokenInformation(h_process_token
.get(), TokenUser
, &token_user_storage
[0], token_user_size
, &token_user_size
))
114 TOKEN_USER
const& token_user
= *reinterpret_cast< const TOKEN_USER
* >(&token_user_storage
[0]);
115 if (!token_user
.User
.Sid
)
118 // Create a boundary descriptor with the user's SID
119 auto_boundary_descriptor
h_boundary(CreateBoundaryDescriptorW(L
"User", 0));
120 if (!h_boundary
.get())
123 if (!AddSIDToBoundaryDescriptor(h_boundary
.get_ptr(), token_user
.User
.Sid
))
126 // Create or open a namespace for kernel objects
127 h
= CreatePrivateNamespaceW(NULL
, h_boundary
.get(), L
"User");
129 h
= OpenPrivateNamespaceW(h_boundary
.get(), L
"User");
133 HANDLE expected
= NULL
;
134 if (g_user_private_namespace
.compare_exchange_strong(expected
, h
, boost::memory_order_acq_rel
, boost::memory_order_acquire
))
136 std::atexit(&close_user_namespace
);
140 // Another thread must have opened the namespace
141 ClosePrivateNamespace(h
, 0);
150 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
152 //! Returns a prefix string for a shared resource according to the scope
153 std::string
get_scope_prefix(object_name::scope ns
)
158 case object_name::process_group
:
160 // For now consider all processes as members of the common process group. It may change if there is found
161 // a way to get a process group id (i.e. id of the closest parent process that was created with the CREATE_NEW_PROCESS_GROUP flag).
162 prefix
= "Local\\boost.log.process_group";
166 case object_name::session
:
168 prefix
= "Local\\boost.log.session";
172 case object_name::user
:
174 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
175 if (init_user_namespace())
177 prefix
= "User\\boost.log.user";
180 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
182 wchar_t buf
[UNLEN
+ 1u];
183 ULONG len
= sizeof(buf
) / sizeof(*buf
);
184 if (BOOST_UNLIKELY(!GetUserNameExW(NameSamCompatible
, buf
, &len
)))
186 const boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
187 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to obtain the current user name", (err
));
190 std::replace(buf
, buf
+ len
, L
'\\', L
'.');
192 prefix
= "Local\\boost.log.user." + boost::log::aux::utf16_to_utf8(buf
);
198 prefix
= "Global\\boost.log.global";
202 prefix
.push_back('.');
204 return BOOST_LOG_NRVO_RESULT(prefix
);
209 //! Constructor from the object name
210 BOOST_LOG_API
object_name::object_name(scope ns
, const char* str
) :
211 m_name(get_scope_prefix(ns
) + str
)
215 //! Constructor from the object name
216 BOOST_LOG_API
object_name::object_name(scope ns
, std::string
const& str
) :
217 m_name(get_scope_prefix(ns
) + str
)
223 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
227 #include <boost/log/detail/footer.hpp>