]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Copyright (c) 2019 Klemens D. Morgenstern |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_ | |
7 | #define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_ | |
8 | ||
9 | #include <vector> | |
10 | #include <system_error> | |
11 | #include <boost/process/detail/windows/handle_workaround.hpp> | |
12 | #include <boost/process/detail/windows/handler.hpp> | |
13 | #include <boost/winapi/get_current_process_id.hpp> | |
14 | ||
15 | namespace boost { namespace process { namespace detail { | |
16 | ||
17 | ||
18 | template<typename Executor, typename Function> | |
19 | void foreach_used_handle(Executor &exec, Function &&func); | |
20 | ||
21 | ||
22 | namespace windows { | |
23 | ||
24 | ||
25 | using native_handle_type = ::boost::winapi::HANDLE_ ; | |
26 | ||
27 | inline std::vector<native_handle_type> get_handles(std::error_code & ec) | |
28 | { | |
29 | auto pid = ::boost::winapi::GetCurrentProcessId(); | |
30 | ||
31 | std::vector<char> buffer(2048); | |
32 | constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l); | |
33 | auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); | |
34 | ||
35 | ::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_; | |
36 | ||
f67539c2 | 37 | for (; |
92f5a8d4 TL |
38 | nt_status == STATUS_INFO_LENGTH_MISMATCH_; |
39 | nt_status = workaround::nt_system_query_information( | |
40 | workaround::SystemHandleInformation_, | |
f67539c2 TL |
41 | info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()), |
42 | nullptr)) | |
92f5a8d4 TL |
43 | { |
44 | buffer.resize(buffer.size() * 2); | |
45 | info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); | |
46 | } | |
47 | ||
48 | ||
49 | if (nt_status < 0 || nt_status > 0x7FFFFFFF) | |
50 | { | |
51 | ec = ::boost::process::detail::get_last_error(); | |
52 | return {}; | |
53 | } | |
54 | else | |
55 | ec.clear(); | |
56 | ||
57 | std::vector<native_handle_type> res; | |
58 | for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++) | |
59 | { | |
60 | if (itr->OwnerPid == pid) | |
61 | res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue))); | |
62 | } | |
63 | ||
64 | return res; | |
65 | } | |
66 | ||
67 | inline std::vector<native_handle_type> get_handles() | |
68 | { | |
69 | std::error_code ec; | |
70 | ||
71 | auto res = get_handles(ec); | |
72 | if (ec) | |
73 | boost::process::detail::throw_error(ec, "NtQuerySystemInformation failed"); | |
74 | ||
75 | return res; | |
76 | } | |
77 | ||
78 | ||
79 | inline bool is_stream_handle(native_handle_type handle, std::error_code & ec) | |
80 | { | |
81 | ::boost::winapi::ULONG_ actual_size; | |
82 | auto nt_status = workaround::nt_query_object( | |
83 | handle, | |
84 | workaround::ObjectTypeInformation, | |
85 | NULL, | |
86 | 0, &actual_size); | |
87 | ||
88 | std::vector<char> vec; | |
89 | vec.resize(actual_size); | |
90 | ||
91 | workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data()); | |
92 | nt_status = workaround::nt_query_object( | |
93 | handle, | |
94 | workaround::ObjectTypeInformation, | |
95 | type_info_p, | |
96 | actual_size, &actual_size); | |
97 | ||
98 | if (nt_status < 0 || nt_status > 0x7FFFFFFF) | |
99 | { | |
100 | ec = ::boost::process::detail::get_last_error(); | |
101 | return false; | |
102 | } | |
103 | else | |
104 | ec.clear(); | |
105 | ||
106 | auto &nm = type_info_p->TypeName.Buffer; | |
107 | return type_info_p->TypeName.Length >= 5 && | |
108 | nm[0] == L'F' && | |
109 | nm[1] == L'i' && | |
110 | nm[2] == L'l' && | |
111 | nm[3] == L'e' && | |
112 | nm[4] == L'\0'; | |
113 | } | |
114 | ||
115 | ||
116 | inline bool is_stream_handle(native_handle_type handle) | |
117 | { | |
118 | std::error_code ec; | |
119 | auto res = is_stream_handle(handle, ec); | |
120 | if (ec) | |
121 | boost::process::detail::throw_error(ec, "NtQueryObject failed"); | |
122 | ||
123 | return res; | |
124 | } | |
125 | ||
126 | ||
127 | struct limit_handles_ : handler_base_ext | |
128 | { | |
129 | mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag; | |
130 | ||
131 | template<typename Executor> | |
132 | void on_setup(Executor & exec) const | |
133 | { | |
134 | auto all_handles = get_handles(); | |
135 | foreach_used_handle(exec, | |
136 | [&](::boost::winapi::HANDLE_ handle) | |
137 | { | |
138 | auto itr = std::find(all_handles.begin(), all_handles .end(), handle); | |
1e59de90 | 139 | ::boost::winapi::DWORD_ flags = 0u; |
92f5a8d4 TL |
140 | if (itr != all_handles.end()) |
141 | *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; | |
142 | else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0) | |
143 | &&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too | |
144 | *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; | |
145 | }); | |
146 | ||
147 | auto part_itr = std::partition(all_handles.begin(), all_handles.end(), | |
148 | [](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;}); | |
149 | ||
150 | all_handles.erase(part_itr, all_handles.end()); //remove invalid handles | |
151 | handles_with_inherit_flag = std::move(all_handles); | |
152 | ||
153 | for (auto handle : handles_with_inherit_flag) | |
154 | ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0); | |
155 | } | |
156 | ||
157 | template<typename Executor> | |
158 | void on_error(Executor & exec, const std::error_code & ec) const | |
159 | { | |
160 | for (auto handle : handles_with_inherit_flag) | |
161 | ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); | |
162 | } | |
163 | ||
164 | template<typename Executor> | |
165 | void on_sucess(Executor & exec) const | |
166 | { | |
167 | for (auto handle : handles_with_inherit_flag) | |
168 | ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); | |
169 | } | |
170 | ||
171 | }; | |
172 | ||
173 | ||
174 | }}}} | |
175 | ||
176 | #endif //PROCESS_HANDLES_HPP |