~ubuntu-branches/ubuntu/wily/puppet/wily-proposed

« back to all changes in this revision

Viewing changes to lib/puppet/util/windows/api_types.rb

  • Committer: Package Import Robot
  • Author(s): Stig Sandbeck Mathisen
  • Date: 2014-10-24 13:47:15 UTC
  • mfrom: (3.1.64 sid)
  • Revision ID: package-import@ubuntu.com-20141024134715-6ig54u0c4gar36ss
Tags: 3.7.2-1
* Imported upstream release 3.7.2
* Declare compliance with Debian Policy 3.9.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'ffi'
 
2
require 'puppet/util/windows/string'
 
3
 
 
4
module Puppet::Util::Windows::APITypes
 
5
  module ::FFI
 
6
    WIN32_FALSE = 0
 
7
 
 
8
    # standard Win32 error codes
 
9
    ERROR_SUCCESS = 0
 
10
  end
 
11
 
 
12
  module ::FFI::Library
 
13
    # Wrapper method for attach_function + private
 
14
    def attach_function_private(*args)
 
15
      attach_function(*args)
 
16
      private args[0]
 
17
    end
 
18
  end
 
19
 
 
20
  class ::FFI::Pointer
 
21
    NULL_HANDLE = 0
 
22
    NULL_TERMINATOR_WCHAR = 0
 
23
 
 
24
    def self.from_string_to_wide_string(str, &block)
 
25
      str = Puppet::Util::Windows::String.wide_string(str)
 
26
      FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
 
27
        # uchar here is synonymous with byte
 
28
        ptr.put_array_of_uchar(0, str.bytes.to_a)
 
29
 
 
30
        yield ptr
 
31
      end
 
32
 
 
33
      # ptr has already had free called, so nothing to return
 
34
      nil
 
35
    end
 
36
 
 
37
    def read_win32_bool
 
38
      # BOOL is always a 32-bit integer in Win32
 
39
      # some Win32 APIs return 1 for true, while others are non-0
 
40
      read_int32 != FFI::WIN32_FALSE
 
41
    end
 
42
 
 
43
    alias_method :read_dword, :read_uint32
 
44
    alias_method :read_win32_ulong, :read_uint32
 
45
 
 
46
    alias_method :read_hresult, :read_int32
 
47
 
 
48
    def read_handle
 
49
      type_size == 4 ? read_uint32 : read_uint64
 
50
    end
 
51
 
 
52
    alias_method :read_wchar, :read_uint16
 
53
    alias_method :read_word,  :read_uint16
 
54
 
 
55
    def read_wide_string(char_length)
 
56
      # char_length is number of wide chars (typically excluding NULLs), *not* bytes
 
57
      str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
 
58
      str.encode(Encoding.default_external)
 
59
    end
 
60
 
 
61
    def read_arbitrary_wide_string_up_to(max_char_length = 512)
 
62
      # max_char_length is number of wide chars (typically excluding NULLs), *not* bytes
 
63
      # use a pointer to read one UTF-16LE char (2 bytes) at a time
 
64
      wchar_ptr = FFI::Pointer.new(:wchar, address)
 
65
 
 
66
      # now iterate 2 bytes at a time until an offset lower than max_char_length is found
 
67
      0.upto(max_char_length - 1) do |i|
 
68
        if wchar_ptr[i].read_wchar == NULL_TERMINATOR_WCHAR
 
69
          return read_wide_string(i)
 
70
        end
 
71
      end
 
72
 
 
73
      read_wide_string(max_char_length)
 
74
    end
 
75
 
 
76
    def read_win32_local_pointer(&block)
 
77
      ptr = nil
 
78
      begin
 
79
        ptr = read_pointer
 
80
        yield ptr
 
81
      ensure
 
82
        if ptr && ! ptr.null?
 
83
          if FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
 
84
            Puppet.debug "LocalFree memory leak"
 
85
          end
 
86
        end
 
87
      end
 
88
 
 
89
      # ptr has already had LocalFree called, so nothing to return
 
90
      nil
 
91
    end
 
92
 
 
93
    def read_com_memory_pointer(&block)
 
94
      ptr = nil
 
95
      begin
 
96
        ptr = read_pointer
 
97
        yield ptr
 
98
      ensure
 
99
        FFI::WIN32::CoTaskMemFree(ptr) if ptr && ! ptr.null?
 
100
      end
 
101
 
 
102
      # ptr has already had CoTaskMemFree called, so nothing to return
 
103
      nil
 
104
    end
 
105
 
 
106
 
 
107
    alias_method :write_dword, :write_uint32
 
108
    alias_method :write_word, :write_uint16
 
109
  end
 
110
 
 
111
  # FFI Types
 
112
  # https://github.com/ffi/ffi/wiki/Types
 
113
 
 
114
  # Windows - Common Data Types
 
115
  # http://msdn.microsoft.com/en-us/library/cc230309.aspx
 
116
 
 
117
  # Windows Data Types
 
118
  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
 
119
 
 
120
  FFI.typedef :uint16, :word
 
121
  FFI.typedef :uint32, :dword
 
122
  # uintptr_t is defined in an FFI conf as platform specific, either
 
123
  # ulong_long on x64 or just ulong on x86
 
124
  FFI.typedef :uintptr_t, :handle
 
125
  FFI.typedef :uintptr_t, :hwnd
 
126
 
 
127
  # buffer_inout is similar to pointer (platform specific), but optimized for buffers
 
128
  FFI.typedef :buffer_inout, :lpwstr
 
129
  # buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
 
130
  FFI.typedef :buffer_in, :lpcwstr
 
131
  FFI.typedef :buffer_in, :lpcolestr
 
132
 
 
133
  # string is also similar to pointer, but should be used for const char *
 
134
  # NOTE that this is not wide, useful only for A suffixed functions
 
135
  FFI.typedef :string, :lpcstr
 
136
 
 
137
  # pointer in FFI is platform specific
 
138
  # NOTE: for API calls with reserved lpvoid parameters, pass a FFI::Pointer::NULL
 
139
  FFI.typedef :pointer, :lpcvoid
 
140
  FFI.typedef :pointer, :lpvoid
 
141
  FFI.typedef :pointer, :lpword
 
142
  FFI.typedef :pointer, :lpdword
 
143
  FFI.typedef :pointer, :pdword
 
144
  FFI.typedef :pointer, :phandle
 
145
  FFI.typedef :pointer, :ulong_ptr
 
146
  FFI.typedef :pointer, :pbool
 
147
  FFI.typedef :pointer, :lpunknown
 
148
 
 
149
  # any time LONG / ULONG is in a win32 API definition DO NOT USE platform specific width
 
150
  # which is what FFI uses by default
 
151
  # instead create new aliases for these very special cases
 
152
  # NOTE: not a good idea to redefine FFI :ulong since other typedefs may rely on it
 
153
  FFI.typedef :uint32, :win32_ulong
 
154
  FFI.typedef :int32, :win32_long
 
155
  # FFI bool can be only 1 byte at times,
 
156
  # Win32 BOOL is a signed int, and is always 4 bytes, even on x64
 
157
  # http://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
 
158
  FFI.typedef :int32, :win32_bool
 
159
 
 
160
  # Same as a LONG, a 32-bit signed integer
 
161
  FFI.typedef :int32, :hresult
 
162
 
 
163
  # NOTE: FFI already defines (u)short as a 16-bit (un)signed like this:
 
164
  # FFI.typedef :uint16, :ushort
 
165
  # FFI.typedef :int16, :short
 
166
 
 
167
  # 8 bits per byte
 
168
  FFI.typedef :uchar, :byte
 
169
  FFI.typedef :uint16, :wchar
 
170
 
 
171
  module ::FFI::WIN32
 
172
    extend ::FFI::Library
 
173
 
 
174
    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
 
175
    # typedef struct _GUID {
 
176
    #   DWORD Data1;
 
177
    #   WORD  Data2;
 
178
    #   WORD  Data3;
 
179
    #   BYTE  Data4[8];
 
180
    # } GUID;
 
181
    class GUID < FFI::Struct
 
182
      layout :Data1, :dword,
 
183
             :Data2, :word,
 
184
             :Data3, :word,
 
185
             :Data4, [:byte, 8]
 
186
 
 
187
      def self.[](s)
 
188
        raise 'Bad GUID format.' unless s =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
 
189
 
 
190
        new.tap do |guid|
 
191
          guid[:Data1] = s[0, 8].to_i(16)
 
192
          guid[:Data2] = s[9, 4].to_i(16)
 
193
          guid[:Data3] = s[14, 4].to_i(16)
 
194
          guid[:Data4][0] = s[19, 2].to_i(16)
 
195
          guid[:Data4][1] = s[21, 2].to_i(16)
 
196
          s[24, 12].split('').each_slice(2).with_index do |a, i|
 
197
            guid[:Data4][i + 2] = a.join('').to_i(16)
 
198
          end
 
199
        end
 
200
      end
 
201
 
 
202
      def ==(other) Windows.memcmp(other, self, size) == 0 end
 
203
    end
 
204
 
 
205
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
 
206
    # typedef struct _SYSTEMTIME {
 
207
    #   WORD wYear;
 
208
    #   WORD wMonth;
 
209
    #   WORD wDayOfWeek;
 
210
    #   WORD wDay;
 
211
    #   WORD wHour;
 
212
    #   WORD wMinute;
 
213
    #   WORD wSecond;
 
214
    #   WORD wMilliseconds;
 
215
    # } SYSTEMTIME, *PSYSTEMTIME;
 
216
    class SYSTEMTIME < FFI::Struct
 
217
      layout :wYear, :word,
 
218
             :wMonth, :word,
 
219
             :wDayOfWeek, :word,
 
220
             :wDay, :word,
 
221
             :wHour, :word,
 
222
             :wMinute, :word,
 
223
             :wSecond, :word,
 
224
             :wMilliseconds, :word
 
225
 
 
226
      def to_local_time
 
227
        Time.local(self[:wYear], self[:wMonth], self[:wDay],
 
228
          self[:wHour], self[:wMinute], self[:wSecond], self[:wMilliseconds] * 1000)
 
229
      end
 
230
    end
 
231
 
 
232
    ffi_convention :stdcall
 
233
 
 
234
    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366730(v=vs.85).aspx
 
235
    # HLOCAL WINAPI LocalFree(
 
236
    #   _In_  HLOCAL hMem
 
237
    # );
 
238
    ffi_lib :kernel32
 
239
    attach_function :LocalFree, [:handle], :handle
 
240
 
 
241
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
 
242
    # BOOL WINAPI CloseHandle(
 
243
    #   _In_  HANDLE hObject
 
244
    # );
 
245
    ffi_lib :kernel32
 
246
    attach_function_private :CloseHandle, [:handle], :win32_bool
 
247
 
 
248
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680722(v=vs.85).aspx
 
249
    # void CoTaskMemFree(
 
250
    #   _In_opt_  LPVOID pv
 
251
    # );
 
252
    ffi_lib :ole32
 
253
    attach_function :CoTaskMemFree, [:lpvoid], :void
 
254
  end
 
255
end