module Puppet::Util::Windows::Registry

Constants

ERROR_NO_MORE_ITEMS
KEY32
KEY64

msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx

KEY_ALL_ACCESS
KEY_READ
KEY_WRITE
MAX_KEY_CHAR_LENGTH

max number of wide characters including NULL terminator

MAX_VALUE_CHAR_LENGTH

max number of wide characters including NULL terminator

Public Instance Methods

delete_key(key, subkey_name, mode = KEY64) click to toggle source
   # File lib/puppet/util/windows/registry.rb
60 def delete_key(key, subkey_name, mode = KEY64)
61   reg_delete_key_ex(key, subkey_name, mode)
62 end
delete_value(key, subkey_name) click to toggle source
    # File lib/puppet/util/windows/registry.rb
108 def delete_value(key, subkey_name)
109   reg_delete_value(key, subkey_name)
110 end
each_key(key) { |subkey, filetime| ... } click to toggle source

subkey is String which contains name of subkey. wtime is last write time as FILETIME (64-bit integer). (see Registry.wtime2time)

   # File lib/puppet/util/windows/registry.rb
44 def each_key(key, &block)
45   index = 0
46   subkey = nil
47 
48   subkey_max_len, _ = reg_query_info_key_max_lengths(key)
49 
50   loop do
51     subkey, filetime = reg_enum_key(key, index, subkey_max_len)
52     yield subkey, filetime if !subkey.nil?
53     index += 1
54     break if subkey.nil?
55   end
56 
57   index
58 end
each_value(key) { |subkey, type, data| ... } click to toggle source
    # File lib/puppet/util/windows/registry.rb
 92 def each_value(key, &block)
 93   index = 0
 94   subkey = nil
 95 
 96   _, value_max_len = reg_query_info_key_max_lengths(key)
 97 
 98   loop do
 99     subkey, type, data = reg_enum_value(key, index, value_max_len)
100     yield subkey, type, data if !subkey.nil?
101     index += 1
102     break if subkey.nil?
103   end
104 
105   index
106 end
keys(key) click to toggle source
   # File lib/puppet/util/windows/registry.rb
36 def keys(key)
37   keys = {}
38   each_key(key) { |subkey, filetime| keys[subkey] = filetime }
39   keys
40 end
open(name, path, mode = KEY_READ | KEY64) { |subkey| ... } click to toggle source
   # File lib/puppet/util/windows/registry.rb
25 def open(name, path, mode = KEY_READ | KEY64, &block)
26   hkey = root(name)
27   begin
28     hkey.open(path, mode) do |subkey|
29       return yield subkey
30     end
31   rescue Win32::Registry::Error => error
32     raise Puppet::Util::Windows::Error.new(_("Failed to open registry key '%{key}\\%{path}'") % { key: hkey.keyname, path: path }, error.code, error)
33   end
34 end
root(name) click to toggle source
   # File lib/puppet/util/windows/registry.rb
19 def root(name)
20   Win32::Registry.const_get(name)
21 rescue NameError
22   raise Puppet::Error, _("Invalid registry key '%{name}'") % { name: name }, $!.backtrace
23 end
values(key) click to toggle source
   # File lib/puppet/util/windows/registry.rb
64 def values(key)
65   vals = {}
66   each_value(key) { |subkey, type, data| vals[subkey] = data }
67   vals
68 end
values_by_name(key, names) click to toggle source

Retrieve a set of values from a registry key given their names Value names listed but not found in the registry will not be added to the resultant Hashtable

@param key [RegistryKey] An open handle to a Registry Key @param names [String An array of names of registry values to return if they exist @return [Hashtable<String, Object>] A hashtable of all of the found values in the registry key

   # File lib/puppet/util/windows/registry.rb
77 def values_by_name(key, names)
78   vals = {}
79   names.each do |name|
80     FFI::Pointer.from_string_to_wide_string(name) do |subkeyname_ptr|
81       begin
82         _, vals[name] = read(key, subkeyname_ptr)
83       rescue Puppet::Util::Windows::Error => e
84         # ignore missing names, but raise other errors
85         raise e unless e.code == Puppet::Util::Windows::Error::ERROR_FILE_NOT_FOUND
86       end
87     end
88   end
89   vals
90 end

Private Instance Methods

query_value_ex(key, name_ptr) { |read_dword, buffer_ptr, read_dword| ... } click to toggle source
    # File lib/puppet/util/windows/registry.rb
268 def query_value_ex(key, name_ptr, &block)
269   FFI::MemoryPointer.new(:dword) do |type_ptr|
270     FFI::MemoryPointer.new(:dword) do |length_ptr|
271       result = RegQueryValueExW(key.hkey, name_ptr,
272         FFI::Pointer::NULL, type_ptr,
273         FFI::Pointer::NULL, length_ptr)
274 
275       FFI::MemoryPointer.new(:byte, length_ptr.read_dword) do |buffer_ptr|
276         result = RegQueryValueExW(key.hkey, name_ptr,
277           FFI::Pointer::NULL, type_ptr,
278           buffer_ptr, length_ptr)
279 
280         if result != FFI::ERROR_SUCCESS
281           # buffer is raw bytes, *not* chars - less a NULL terminator
282           name_length = (name_ptr.size / FFI.type_size(:wchar)) - 1 if name_ptr.size > 0
283           msg = _("Failed to read registry value %{value} at %{key}") % { value: name_ptr.read_wide_string(name_length), key: key.keyname }
284           raise Puppet::Util::Windows::Error.new(msg, result)
285         end
286 
287         # allows caller to use FFI MemoryPointer helpers to read / shape
288         yield [type_ptr.read_dword, buffer_ptr, length_ptr.read_dword]
289       end
290     end
291   end
292 end
read(key, name_ptr, *rtype) click to toggle source

Read a registry value named name and return array of [ type, data ]. When name is nil, the `default' value is read. type is value type. (see Win32::Registry::Constants module) data is value data, its class is: :REG_SZ, REG_EXPAND_SZ

String

:REG_MULTI_SZ

Array of String

:REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD

Integer

:REG_BINARY

String (contains binary data)

When rtype is specified, the value type must be included by rtype array, or TypeError is raised.

    # File lib/puppet/util/windows/registry.rb
229 def read(key, name_ptr, *rtype)
230   result = nil
231 
232   query_value_ex(key, name_ptr) do |type, data_ptr, byte_length|
233     unless rtype.empty? or rtype.include?(type)
234       raise TypeError, _("Type mismatch (expect %{rtype} but %{type} present)") % { rtype: rtype.inspect, type: type }
235     end
236 
237     string_length = 0
238     # buffer is raw bytes, *not* chars - less a NULL terminator
239     string_length = (byte_length / FFI.type_size(:wchar)) - 1 if byte_length > 0
240 
241     begin
242       case type
243         when Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ
244           result = [ type, data_ptr.read_wide_string(string_length, Encoding::UTF_8, true) ]
245         when Win32::Registry::REG_MULTI_SZ
246           result = [ type, data_ptr.read_wide_string(string_length).split(/\0/) ]
247         when Win32::Registry::REG_BINARY
248           result = [ type, data_ptr.read_bytes(byte_length) ]
249         when Win32::Registry::REG_DWORD
250           result = [ type, data_ptr.read_dword ]
251         when Win32::Registry::REG_DWORD_BIG_ENDIAN
252           result = [ type, data_ptr.order(:big).read_dword ]
253         when Win32::Registry::REG_QWORD
254           result = [ type, data_ptr.read_qword ]
255         else
256           raise TypeError, _("Type %{type} is not supported.") % { type: type }
257       end
258     rescue IndexError => ex
259       raise if (ex.message !~ /^Memory access .* is out of bounds$/i)
260       parent_key_name = key.parent ? "#{key.parent.keyname}\\" : ""
261       Puppet.warning _("A value in the registry key %{parent_key_name}%{key} is corrupt or invalid") % { parent_key_name: parent_key_name, key: key.keyname }
262     end
263   end
264 
265   result
266 end
reg_delete_key_ex(key, name, regsam = KEY64) click to toggle source
    # File lib/puppet/util/windows/registry.rb
309 def reg_delete_key_ex(key, name, regsam = KEY64)
310   result = 0
311 
312   FFI::Pointer.from_string_to_wide_string(name) do |name_ptr|
313     result = RegDeleteKeyExW(key.hkey, name_ptr, regsam, 0)
314 
315     if result != FFI::ERROR_SUCCESS
316       msg = _("Failed to delete registry key %{name} at %{key}") % { name: name, key: key.keyname }
317       raise Puppet::Util::Windows::Error.new(msg, result)
318     end
319   end
320 
321   result
322 end
reg_delete_value(key, name) click to toggle source
    # File lib/puppet/util/windows/registry.rb
294 def reg_delete_value(key, name)
295   result = 0
296 
297   FFI::Pointer.from_string_to_wide_string(name) do |name_ptr|
298     result = RegDeleteValueW(key.hkey, name_ptr)
299 
300     if result != FFI::ERROR_SUCCESS
301       msg = _("Failed to delete registry value %{name} at %{key}") % { name: name, key: key.keyname }
302       raise Puppet::Util::Windows::Error.new(msg, result)
303     end
304   end
305 
306   result
307 end
reg_enum_key(key, index, max_key_char_length = MAX_KEY_CHAR_LENGTH) click to toggle source
    # File lib/puppet/util/windows/registry.rb
117 def reg_enum_key(key, index, max_key_char_length = MAX_KEY_CHAR_LENGTH)
118   subkey, filetime = nil, nil
119 
120   FFI::MemoryPointer.new(:dword) do |subkey_length_ptr|
121     FFI::MemoryPointer.new(FFI::WIN32::FILETIME.size) do |filetime_ptr|
122       FFI::MemoryPointer.new(:wchar, max_key_char_length) do |subkey_ptr|
123         subkey_length_ptr.write_dword(max_key_char_length)
124 
125         # RegEnumKeyEx cannot be called twice to properly size the buffer
126         result = RegEnumKeyExW(key.hkey, index,
127           subkey_ptr, subkey_length_ptr,
128           FFI::Pointer::NULL, FFI::Pointer::NULL,
129           FFI::Pointer::NULL, filetime_ptr)
130 
131         break if result == ERROR_NO_MORE_ITEMS
132 
133         if result != FFI::ERROR_SUCCESS
134           msg = _("Failed to enumerate %{key} registry keys at index %{index}") % { key: key.keyname, index: index }
135           raise Puppet::Util::Windows::Error.new(msg, result)
136         end
137 
138         filetime = FFI::WIN32::FILETIME.new(filetime_ptr)
139         subkey_length = subkey_length_ptr.read_dword
140         subkey = subkey_ptr.read_wide_string(subkey_length)
141       end
142     end
143   end
144 
145   [subkey, filetime]
146 end
reg_enum_value(key, index, max_value_length = MAX_VALUE_CHAR_LENGTH) click to toggle source
    # File lib/puppet/util/windows/registry.rb
151 def reg_enum_value(key, index, max_value_length = MAX_VALUE_CHAR_LENGTH)
152   subkey, type, data = nil, nil, nil
153 
154   FFI::MemoryPointer.new(:dword) do |subkey_length_ptr|
155     FFI::MemoryPointer.new(:wchar, max_value_length) do |subkey_ptr|
156       # RegEnumValueW cannot be called twice to properly size the buffer
157       subkey_length_ptr.write_dword(max_value_length)
158 
159       result = RegEnumValueW(key.hkey, index,
160         subkey_ptr, subkey_length_ptr,
161         FFI::Pointer::NULL, FFI::Pointer::NULL,
162         FFI::Pointer::NULL, FFI::Pointer::NULL
163       )
164 
165       break if result == ERROR_NO_MORE_ITEMS
166 
167       if result != FFI::ERROR_SUCCESS
168         msg = _("Failed to enumerate %{key} registry values at index %{index}") % { key: key.keyname, index: index }
169         raise Puppet::Util::Windows::Error.new(msg, result)
170       end
171 
172       subkey_length = subkey_length_ptr.read_dword
173       subkey = subkey_ptr.read_wide_string(subkey_length)
174 
175       type, data = read(key, subkey_ptr)
176     end
177   end
178 
179   [subkey, type, data]
180 end
reg_query_info_key_max_lengths(key) click to toggle source
    # File lib/puppet/util/windows/registry.rb
182 def reg_query_info_key_max_lengths(key)
183   result = nil
184 
185   FFI::MemoryPointer.new(:dword) do |max_subkey_name_length_ptr|
186     FFI::MemoryPointer.new(:dword) do |max_value_name_length_ptr|
187 
188       status = RegQueryInfoKeyW(key.hkey,
189         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
190         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
191         max_subkey_name_length_ptr, FFI::MemoryPointer::NULL,
192         FFI::MemoryPointer::NULL, max_value_name_length_ptr,
193         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
194         FFI::MemoryPointer::NULL
195       )
196 
197       if status != FFI::ERROR_SUCCESS
198         msg = _("Failed to query registry %{key} for sizes") % { key: key.keyname }
199         raise Puppet::Util::Windows::Error.new(msg, status)
200       end
201 
202       result = [
203         # Unicode characters *not* including trailing NULL
204         max_subkey_name_length_ptr.read_dword + 1,
205         max_value_name_length_ptr.read_dword + 1,
206       ]
207     end
208   end
209 
210   result
211 end