diff options
author | Claire McQuin <claire@chef.io> | 2015-08-28 12:53:01 -0700 |
---|---|---|
committer | Claire McQuin <claire@chef.io> | 2015-08-28 12:53:01 -0700 |
commit | 948a74583a3e4e66df10d1c89b8856bdf36bffbe (patch) | |
tree | 6b824ef1d523d342fc770a645e16338df6d5d82c | |
parent | 71925f0b253c0dd1b0943029d5399c3e20641ced (diff) | |
download | chef-mcquin/registry-ffi.tar.gz |
sort of implement #get_values with ffimcquin/registry-ffi
-rw-r--r-- | lib/chef/win32/api/registry.rb | 38 | ||||
-rw-r--r-- | lib/chef/win32/registry.rb | 54 | ||||
-rw-r--r-- | lib/chef/win32/unicode.rb | 35 | ||||
-rw-r--r-- | spec/functional/win32/registry_helper_spec.rb | 2 |
4 files changed, 116 insertions, 13 deletions
diff --git a/lib/chef/win32/api/registry.rb b/lib/chef/win32/api/registry.rb index 8a123c37cd..be7e1ec8df 100644 --- a/lib/chef/win32/api/registry.rb +++ b/lib/chef/win32/api/registry.rb @@ -38,7 +38,43 @@ class Chef # ); safe_attach_function :RegDeleteKeyExW, [ :HKEY, :LPCTSTR, :LONG, :DWORD ], :LONG safe_attach_function :RegDeleteKeyExA, [ :HKEY, :LPCTSTR, :LONG, :DWORD ], :LONG - + + # LONG WINAPI RegOpenKeyEx( + # _In_ HKEY hKey, + # _In_opt_ LPCTSTR lpSubKey, + # _In_ DWORD ulOptions, + # _In_ REGSAM samDesired, + # _Out_ PHKEY phkResult + # ); + safe_attach_function :RegOpenKeyExW, [ :HKEY, :LPCTSTR, :DWORD, :ULONG, :PHKEY ], :LONG + + # LONG WINAPI RegEnumValue( + # _In_ HKEY hKey, + # _In_ DWORD dwIndex, + # _Out_ LPTSTR lpValueName, + # _Inout_ LPDWORD lpcchValueName, + # _Reserved_ LPDWORD lpReserved, + # _Out_opt_ LPDWORD lpType, + # _Out_opt_ LPBYTE lpData, + # _Inout_opt_ LPDWORD lpcbData + # ); + safe_attach_function :RegEnumValueW, [ :HKEY, :DWORD, :LPTSTR, :LPDWORD, :LPDWORD, :LPDWORD, :LPBYTE, :LPDWORD ], :LONG + + # LONG WINAPI RegQueryInfoKey( + # _In_ HKEY hKey, + # _Out_opt_ LPTSTR lpClass, + # _Inout_opt_ LPDWORD lpcClass, + # _Reserved_ LPDWORD lpReserved, + # _Out_opt_ LPDWORD lpcSubKeys, + # _Out_opt_ LPDWORD lpcMaxSubKeyLen, + # _Out_opt_ LPDWORD lpcMaxClassLen, + # _Out_opt_ LPDWORD lpcValues, + # _Out_opt_ LPDWORD lpcMaxValueNameLen, + # _Out_opt_ LPDWORD lpcMaxValueLen, + # _Out_opt_ LPDWORD lpcbSecurityDescriptor, + # _Out_opt_ PFILETIME lpftLastWriteTime + # ); + safe_attach_function :RegQueryInfoKeyW, [ :HKEY, :LPTSTR, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :LPDWORD, :pointer ], :LONG end end end diff --git a/lib/chef/win32/registry.rb b/lib/chef/win32/registry.rb index 64cc18f038..7674abf08c 100644 --- a/lib/chef/win32/registry.rb +++ b/lib/chef/win32/registry.rb @@ -22,12 +22,20 @@ require 'win32/api' require 'chef/win32/api/registry' require 'chef/mixin/wstring' +if RUBY_PLATFORM =~ /mswin|mingw32|windows/ + require 'win32/registry' + require 'win32/api' +end + class Chef class Win32 class Registry include Chef::ReservedNames::Win32::API::Registry extend Chef::ReservedNames::Win32::API::Registry + + include Chef::Mixin::WideString + extend Chef::Mixin::WideString include Chef::Mixin::WideString extend Chef::Mixin::WideString @@ -48,9 +56,51 @@ class Chef def get_values(key_path) hive, key = get_hive_and_key(key_path) key_exists!(key_path) - values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| - reg.map { |name, type, data| {:name=>name, :type=>get_name_from_type(type), :data=>data} } + + phkey = FFI::MemoryPointer.new(:ulong) + result = RegOpenKeyExW(hive.hkey, wstring(key), 0, ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture, phkey) + # do something if result != 0 + + hkey = phkey.read_ulong + values_ptr = FFI::MemoryPointer.new(:uint32) + max_value_name_len_ptr = FFI::MemoryPointer.new(:uint32) + max_value_len_ptr = FFI::MemoryPointer.new(:uint32) + RegQueryInfoKeyW(hkey, nil, nil, nil, nil, nil, nil, values_ptr, max_value_name_len_ptr, max_value_len_ptr, nil, nil) + + values = [ ] + + max_value_name_len = max_value_name_len_ptr.read_uint32 # characters w/o null terminater + max_value_len = max_value_len_ptr.read_uint32 # bytes, incl terminaters + name_ptr = FFI::MemoryPointer.new(:uint16, max_value_name_len + 1) + name_size_ptr = FFI::MemoryPointer.new(:uint32) + type_ptr = FFI::MemoryPointer.new(:uint32) + data_ptr = FFI::MemoryPointer.new(:uint32, max_value_len) + data_size_ptr = FFI::MemoryPointer.new(:uint32) + values_ptr.read_uint32.times do |index| + name_size_ptr.write_uint32(max_value_name_len + 1) + data_size_ptr.write_uint32(max_value_len) + + RegEnumValueW(hkey, index, name_ptr, name_size_ptr, nil, type_ptr, data_ptr, data_size_ptr) + + name = name_ptr.read_wstring(name_size_ptr.read_uint32) + type = get_name_from_type(type_ptr.read_uint32) + data = case type + when :string + data_ptr.read_wstring + when :multi_string + data_ptr.read_array_of_wstring + else + data_ptr.read_bytes(data_size_ptr.read_uint32) + end + + values << { :name => name, :type => type, :data => data } end + + values + + # values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| + # reg.map { |name, type, data| {:name=>name, :type=>get_name_from_type(type), :data=>data} } + # end end def set_value(key_path, value) diff --git a/lib/chef/win32/unicode.rb b/lib/chef/win32/unicode.rb index e7399d5255..ed8227ccfd 100644 --- a/lib/chef/win32/unicode.rb +++ b/lib/chef/win32/unicode.rb @@ -32,19 +32,36 @@ module FFI class Pointer def read_wstring(num_wchars = nil) if num_wchars.nil? - # Find the length of the string - length = 0 - last_char = nil - while last_char != "\000\000" do - length += 1 - last_char = self.get_bytes(0,length * 2)[-2..-1] - end - - num_wchars = length + num_wchars = get_wstring_len end Chef::ReservedNames::Win32::Unicode.wide_to_utf8(self.get_bytes(0, num_wchars*2)) end + + def read_array_of_wstring + result = [] + read_head_ptr = Pointer.new(address) + num_wchars = read_head_ptr.get_wstring_len + # read until we hit the final null terminating character + while num_wchars > 1 + result << read_head_ptr.read_wstring(num_wchars) + read_head_ptr = read_head_ptr + (num_wchars * 2) + num_wchars = read_head_ptr.get_wstring_len + end + result + end + + def get_wstring_len + # Find the length of the string + length = 0 + last_char = nil + while last_char != "\000\000" do + length += 1 + last_char = self.get_bytes(0,length * 2)[-2..-1] + end + + length + end end end diff --git a/spec/functional/win32/registry_helper_spec.rb b/spec/functional/win32/registry_helper_spec.rb index 9ef6fd006f..43733557ba 100644 --- a/spec/functional/win32/registry_helper_spec.rb +++ b/spec/functional/win32/registry_helper_spec.rb @@ -205,7 +205,7 @@ describe 'Chef::Win32::Registry', :windows_only do end describe "get_values" do - it "returns all values for a key if it exists" do + it "returns all values for a key if it exists", :focus => true do values = @registry.get_values("HKCU\\Software\\Root") expect(values).to be_an_instance_of Array expect(values).to eq([{:name=>"RootType1", :type=>:string, :data=>"fibrous"}, |