summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaire McQuin <claire@chef.io>2015-08-28 12:53:01 -0700
committerClaire McQuin <claire@chef.io>2015-08-28 12:53:01 -0700
commit948a74583a3e4e66df10d1c89b8856bdf36bffbe (patch)
tree6b824ef1d523d342fc770a645e16338df6d5d82c
parent71925f0b253c0dd1b0943029d5399c3e20641ced (diff)
downloadchef-mcquin/registry-ffi.tar.gz
sort of implement #get_values with ffimcquin/registry-ffi
-rw-r--r--lib/chef/win32/api/registry.rb38
-rw-r--r--lib/chef/win32/registry.rb54
-rw-r--r--lib/chef/win32/unicode.rb35
-rw-r--r--spec/functional/win32/registry_helper_spec.rb2
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"},