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
59 def delete_key(key, subkey_name, mode = KEY64)
60   reg_delete_key_ex(key, subkey_name, mode)
61 end
delete_value(key, subkey_name) click to toggle source
    # File lib/puppet/util/windows/registry.rb
107 def delete_value(key, subkey_name)
108   reg_delete_value(key, subkey_name)
109 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
43 def each_key(key, &block)
44   index = 0
45   subkey = nil
46 
47   subkey_max_len, _ = reg_query_info_key_max_lengths(key)
48 
49   loop do
50     subkey, filetime = reg_enum_key(key, index, subkey_max_len)
51     yield subkey, filetime if !subkey.nil?
52     index += 1
53     break if subkey.nil?
54   end
55 
56   index
57 end
each_value(key) { |subkey, type, data| ... } click to toggle source
    # File lib/puppet/util/windows/registry.rb
 91 def each_value(key, &block)
 92   index = 0
 93   subkey = nil
 94 
 95   _, value_max_len = reg_query_info_key_max_lengths(key)
 96 
 97   loop do
 98     subkey, type, data = reg_enum_value(key, index, value_max_len)
 99     yield subkey, type, data if !subkey.nil?
100     index += 1
101     break if subkey.nil?
102   end
103 
104   index
105 end
keys(key) click to toggle source
   # File lib/puppet/util/windows/registry.rb
35 def keys(key)
36   keys = {}
37   each_key(key) { |subkey, filetime| keys[subkey] = filetime }
38   keys
39 end
open(name, path, mode = KEY_READ | KEY64) { |subkey| ... } click to toggle source
   # File lib/puppet/util/windows/registry.rb
24 def open(name, path, mode = KEY_READ | KEY64, &block)
25   hkey = root(name)
26   begin
27     hkey.open(path, mode) do |subkey|
28       return yield subkey
29     end
30   rescue Win32::Registry::Error => error
31     raise Puppet::Util::Windows::Error.new(_("Failed to open registry key '%{key}\\%{path}'") % { key: hkey.keyname, path: path }, error.code, error)
32   end
33 end
root(name) click to toggle source
   # File lib/puppet/util/windows/registry.rb
18 def root(name)
19   Win32::Registry.const_get(name)
20 rescue NameError
21   raise Puppet::Error, _("Invalid registry key '%{name}'") % { name: name }, $!.backtrace
22 end
values(key) click to toggle source
   # File lib/puppet/util/windows/registry.rb
63 def values(key)
64   vals = {}
65   each_value(key) { |subkey, type, data| vals[subkey] = data }
66   vals
67 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
76 def values_by_name(key, names)
77   vals = {}
78   names.each do |name|
79     FFI::Pointer.from_string_to_wide_string(name) do |subkeyname_ptr|
80       begin
81         _, vals[name] = read(key, subkeyname_ptr)
82       rescue Puppet::Util::Windows::Error => e
83         # ignore missing names, but raise other errors
84         raise e unless e.code == Puppet::Util::Windows::Error::ERROR_FILE_NOT_FOUND
85       end
86     end
87   end
88   vals
89 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
267 def query_value_ex(key, name_ptr, &block)
268   FFI::MemoryPointer.new(:dword) do |type_ptr|
269     FFI::MemoryPointer.new(:dword) do |length_ptr|
270       result = RegQueryValueExW(key.hkey, name_ptr,
271         FFI::Pointer::NULL, type_ptr,
272         FFI::Pointer::NULL, length_ptr)
273 
274       FFI::MemoryPointer.new(:byte, length_ptr.read_dword) do |buffer_ptr|
275         result = RegQueryValueExW(key.hkey, name_ptr,
276           FFI::Pointer::NULL, type_ptr,
277           buffer_ptr, length_ptr)
278 
279         if result != FFI::ERROR_SUCCESS
280           # buffer is raw bytes, *not* chars - less a NULL terminator
281           name_length = (name_ptr.size / FFI.type_size(:wchar)) - 1 if name_ptr.size > 0
282           msg = _("Failed to read registry value %{value} at %{key}") % { value: name_ptr.read_wide_string(name_length), key: key.keyname }
283           raise Puppet::Util::Windows::Error.new(msg, result)
284         end
285 
286         # allows caller to use FFI MemoryPointer helpers to read / shape
287         yield [type_ptr.read_dword, buffer_ptr, length_ptr.read_dword]
288       end
289     end
290   end
291 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
228 def read(key, name_ptr, *rtype)
229   result = nil
230 
231   query_value_ex(key, name_ptr) do |type, data_ptr, byte_length|
232     unless rtype.empty? or rtype.include?(type)
233       raise TypeError, _("Type mismatch (expect %{rtype} but %{type} present)") % { rtype: rtype.inspect, type: type }
234     end
235 
236     string_length = 0
237     # buffer is raw bytes, *not* chars - less a NULL terminator
238     string_length = (byte_length / FFI.type_size(:wchar)) - 1 if byte_length > 0
239 
240     begin
241       case type
242         when Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ
243           result = [ type, data_ptr.read_wide_string(string_length, Encoding::UTF_8, true) ]
244         when Win32::Registry::REG_MULTI_SZ
245           result = [ type, data_ptr.read_wide_string(string_length).split(/\0/) ]
246         when Win32::Registry::REG_BINARY
247           result = [ type, data_ptr.read_bytes(byte_length) ]
248         when Win32::Registry::REG_DWORD
249           result = [ type, data_ptr.read_dword ]
250         when Win32::Registry::REG_DWORD_BIG_ENDIAN
251           result = [ type, data_ptr.order(:big).read_dword ]
252         when Win32::Registry::REG_QWORD
253           result = [ type, data_ptr.read_qword ]
254         else
255           raise TypeError, _("Type %{type} is not supported.") % { type: type }
256       end
257     rescue IndexError => ex
258       raise if (ex.message !~ /^Memory access .* is out of bounds$/i)
259       parent_key_name = key.parent ? "#{key.parent.keyname}\\" : ""
260       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 }
261     end
262   end
263 
264   result
265 end
reg_delete_key_ex(key, name, regsam = KEY64) click to toggle source
    # File lib/puppet/util/windows/registry.rb
308 def reg_delete_key_ex(key, name, regsam = KEY64)
309   result = 0
310 
311   FFI::Pointer.from_string_to_wide_string(name) do |name_ptr|
312     result = RegDeleteKeyExW(key.hkey, name_ptr, regsam, 0)
313 
314     if result != FFI::ERROR_SUCCESS
315       msg = _("Failed to delete registry key %{name} at %{key}") % { name: name, key: key.keyname }
316       raise Puppet::Util::Windows::Error.new(msg, result)
317     end
318   end
319 
320   result
321 end
reg_delete_value(key, name) click to toggle source
    # File lib/puppet/util/windows/registry.rb
293 def reg_delete_value(key, name)
294   result = 0
295 
296   FFI::Pointer.from_string_to_wide_string(name) do |name_ptr|
297     result = RegDeleteValueW(key.hkey, name_ptr)
298 
299     if result != FFI::ERROR_SUCCESS
300       msg = _("Failed to delete registry value %{name} at %{key}") % { name: name, key: key.keyname }
301       raise Puppet::Util::Windows::Error.new(msg, result)
302     end
303   end
304 
305   result
306 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
116 def reg_enum_key(key, index, max_key_char_length = MAX_KEY_CHAR_LENGTH)
117   subkey, filetime = nil, nil
118 
119   FFI::MemoryPointer.new(:dword) do |subkey_length_ptr|
120     FFI::MemoryPointer.new(FFI::WIN32::FILETIME.size) do |filetime_ptr|
121       FFI::MemoryPointer.new(:wchar, max_key_char_length) do |subkey_ptr|
122         subkey_length_ptr.write_dword(max_key_char_length)
123 
124         # RegEnumKeyEx cannot be called twice to properly size the buffer
125         result = RegEnumKeyExW(key.hkey, index,
126           subkey_ptr, subkey_length_ptr,
127           FFI::Pointer::NULL, FFI::Pointer::NULL,
128           FFI::Pointer::NULL, filetime_ptr)
129 
130         break if result == ERROR_NO_MORE_ITEMS
131 
132         if result != FFI::ERROR_SUCCESS
133           msg = _("Failed to enumerate %{key} registry keys at index %{index}") % { key: key.keyname, index: index }
134           raise Puppet::Util::Windows::Error.new(msg, result)
135         end
136 
137         filetime = FFI::WIN32::FILETIME.new(filetime_ptr)
138         subkey_length = subkey_length_ptr.read_dword
139         subkey = subkey_ptr.read_wide_string(subkey_length)
140       end
141     end
142   end
143 
144   [subkey, filetime]
145 end
reg_enum_value(key, index, max_value_length = MAX_VALUE_CHAR_LENGTH) click to toggle source
    # File lib/puppet/util/windows/registry.rb
150 def reg_enum_value(key, index, max_value_length = MAX_VALUE_CHAR_LENGTH)
151   subkey, type, data = nil, nil, nil
152 
153   FFI::MemoryPointer.new(:dword) do |subkey_length_ptr|
154     FFI::MemoryPointer.new(:wchar, max_value_length) do |subkey_ptr|
155       # RegEnumValueW cannot be called twice to properly size the buffer
156       subkey_length_ptr.write_dword(max_value_length)
157 
158       result = RegEnumValueW(key.hkey, index,
159         subkey_ptr, subkey_length_ptr,
160         FFI::Pointer::NULL, FFI::Pointer::NULL,
161         FFI::Pointer::NULL, FFI::Pointer::NULL
162       )
163 
164       break if result == ERROR_NO_MORE_ITEMS
165 
166       if result != FFI::ERROR_SUCCESS
167         msg = _("Failed to enumerate %{key} registry values at index %{index}") % { key: key.keyname, index: index }
168         raise Puppet::Util::Windows::Error.new(msg, result)
169       end
170 
171       subkey_length = subkey_length_ptr.read_dword
172       subkey = subkey_ptr.read_wide_string(subkey_length)
173 
174       type, data = read(key, subkey_ptr)
175     end
176   end
177 
178   [subkey, type, data]
179 end
reg_query_info_key_max_lengths(key) click to toggle source
    # File lib/puppet/util/windows/registry.rb
181 def reg_query_info_key_max_lengths(key)
182   result = nil
183 
184   FFI::MemoryPointer.new(:dword) do |max_subkey_name_length_ptr|
185     FFI::MemoryPointer.new(:dword) do |max_value_name_length_ptr|
186 
187       status = RegQueryInfoKeyW(key.hkey,
188         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
189         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
190         max_subkey_name_length_ptr, FFI::MemoryPointer::NULL,
191         FFI::MemoryPointer::NULL, max_value_name_length_ptr,
192         FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL,
193         FFI::MemoryPointer::NULL
194       )
195 
196       if status != FFI::ERROR_SUCCESS
197         msg = _("Failed to query registry %{key} for sizes") % { key: key.keyname }
198         raise Puppet::Util::Windows::Error.new(msg, status)
199       end
200 
201       result = [
202         # Unicode characters *not* including trailing NULL
203         max_subkey_name_length_ptr.read_dword + 1,
204         max_value_name_length_ptr.read_dword + 1,
205       ]
206     end
207   end
208 
209   result
210 end