PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
| Dir : /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/ffi/windows/ |
| Server: Linux server1.ngambekcore.com 4.18.0-553.51.1.el8_10.x86_64 #1 SMP Wed Apr 30 04:00:07 EDT 2025 x86_64 IP: 159.198.77.92 |
| Dir : //opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/ffi/windows/api_types.rb |
require_relative '../../../puppet/ffi/windows'
require_relative '../../../puppet/util/windows/string'
module Puppet::FFI::Windows
module APITypes
module ::FFI
WIN32_FALSE = 0
# standard Win32 error codes
ERROR_SUCCESS = 0
end
module ::FFI::Library
# Wrapper method for attach_function + private
def attach_function_private(*args)
attach_function(*args)
private args[0]
end
end
class ::FFI::Pointer
NULL_HANDLE = 0
WCHAR_NULL = "\0\0".force_encoding('UTF-16LE').freeze
def self.from_string_to_wide_string(str, &block)
str = Puppet::Util::Windows::String.wide_string(str)
FFI::MemoryPointer.from_wide_string(str, &block)
# ptr has already had free called, so nothing to return
nil
end
def read_win32_bool
# BOOL is always a 32-bit integer in Win32
# some Win32 APIs return 1 for true, while others are non-0
read_int32 != FFI::WIN32_FALSE
end
alias_method :read_dword, :read_uint32
alias_method :read_win32_ulong, :read_uint32
alias_method :read_qword, :read_uint64
alias_method :read_hresult, :read_int32
def read_handle
type_size == 4 ? read_uint32 : read_uint64
end
alias_method :read_wchar, :read_uint16
alias_method :read_word, :read_uint16
alias_method :read_array_of_wchar, :read_array_of_uint16
def read_wide_string(char_length, dst_encoding = Encoding::UTF_8, strip = false, encode_options = {})
# char_length is number of wide chars (typically excluding NULLs), *not* bytes
str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
if strip
i = str.index(WCHAR_NULL)
str = str[0, i] if i
end
str.encode(dst_encoding, str.encoding, **encode_options)
rescue EncodingError => e
Puppet.debug { "Unable to convert value #{str.nil? ? 'nil' : str.dump} to encoding #{dst_encoding} due to #{e.inspect}" }
raise
end
# @param max_char_length [Integer] Maximum number of wide chars to return (typically excluding NULLs), *not* bytes
# @param null_terminator [Symbol] Number of number of null wchar characters, *not* bytes, that determine the end of the string
# null_terminator = :single_null, then the terminating sequence is two bytes of zero. This is UNIT16 = 0
# null_terminator = :double_null, then the terminating sequence is four bytes of zero. This is UNIT32 = 0
# @param encode_options [Hash] Accepts the same option hash that may be passed to String#encode in Ruby
def read_arbitrary_wide_string_up_to(max_char_length = 512, null_terminator = :single_null, encode_options = {})
idx = case null_terminator
when :single_null
# find index of wide null between 0 and max (exclusive)
(0...max_char_length).find do |i|
get_uint16(i * 2) == 0
end
when :double_null
# find index of double-wide null between 0 and max - 1 (exclusive)
(0...max_char_length - 1).find do |i|
get_uint32(i * 2) == 0
end
else
raise _("Unable to read wide strings with %{null_terminator} terminal nulls") % { null_terminator: null_terminator }
end
read_wide_string(idx || max_char_length, Encoding::UTF_8, false, encode_options)
end
def read_win32_local_pointer(&block)
ptr = read_pointer
begin
yield ptr
ensure
if !ptr.null? && FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
Puppet.debug "LocalFree memory leak"
end
end
# ptr has already had LocalFree called, so nothing to return
nil
end
def read_com_memory_pointer(&block)
ptr = read_pointer
begin
yield ptr
ensure
FFI::WIN32::CoTaskMemFree(ptr) unless ptr.null?
end
# ptr has already had CoTaskMemFree called, so nothing to return
nil
end
alias_method :write_dword, :write_uint32
alias_method :write_word, :write_uint16
end
class FFI::MemoryPointer
# Return a MemoryPointer that points to wide string. This is analogous to the
# FFI::MemoryPointer.from_string method.
def self.from_wide_string(wstr)
ptr = FFI::MemoryPointer.new(:uchar, wstr.bytesize + 2)
ptr.put_array_of_uchar(0, wstr.bytes.to_a)
ptr.put_uint16(wstr.bytesize, 0)
yield ptr if block_given?
ptr
end
end
# FFI Types
# https://github.com/ffi/ffi/wiki/Types
# Windows - Common Data Types
# https://msdn.microsoft.com/en-us/library/cc230309.aspx
# Windows Data Types
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
FFI.typedef :uint16, :word
FFI.typedef :uint32, :dword
# uintptr_t is defined in an FFI conf as platform specific, either
# ulong_long on x64 or just ulong on x86
FFI.typedef :uintptr_t, :handle
FFI.typedef :uintptr_t, :hwnd
# buffer_inout is similar to pointer (platform specific), but optimized for buffers
FFI.typedef :buffer_inout, :lpwstr
# buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
FFI.typedef :buffer_in, :lpcwstr
FFI.typedef :buffer_in, :lpcolestr
# string is also similar to pointer, but should be used for const char *
# NOTE that this is not wide, useful only for A suffixed functions
FFI.typedef :string, :lpcstr
# pointer in FFI is platform specific
# NOTE: for API calls with reserved lpvoid parameters, pass a FFI::Pointer::NULL
FFI.typedef :pointer, :lpcvoid
FFI.typedef :pointer, :lpvoid
FFI.typedef :pointer, :lpword
FFI.typedef :pointer, :lpbyte
FFI.typedef :pointer, :lpdword
FFI.typedef :pointer, :pdword
FFI.typedef :pointer, :phandle
FFI.typedef :pointer, :ulong_ptr
FFI.typedef :pointer, :pbool
FFI.typedef :pointer, :lpunknown
# any time LONG / ULONG is in a win32 API definition DO NOT USE platform specific width
# which is what FFI uses by default
# instead create new aliases for these very special cases
# NOTE: not a good idea to redefine FFI :ulong since other typedefs may rely on it
FFI.typedef :uint32, :win32_ulong
FFI.typedef :int32, :win32_long
# FFI bool can be only 1 byte at times,
# Win32 BOOL is a signed int, and is always 4 bytes, even on x64
# https://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
FFI.typedef :int32, :win32_bool
# BOOLEAN (unlike BOOL) is a BYTE - typedef unsigned char BYTE;
FFI.typedef :uchar, :boolean
# Same as a LONG, a 32-bit signed integer
FFI.typedef :int32, :hresult
# NOTE: FFI already defines (u)short as a 16-bit (un)signed like this:
# FFI.typedef :uint16, :ushort
# FFI.typedef :int16, :short
# 8 bits per byte
FFI.typedef :uchar, :byte
FFI.typedef :uint16, :wchar
# Definitions for data types used in LSA structures and functions
# https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/
# https://docs.microsoft.com/sr-latn-rs/windows/win32/secmgmt/management-data-types
FFI.typedef :pointer, :pwstr
FFI.typedef :pointer, :pulong
FFI.typedef :pointer, :lsa_handle
FFI.typedef :pointer, :plsa_handle
FFI.typedef :pointer, :psid
FFI.typedef :pointer, :pvoid
FFI.typedef :pointer, :plsa_unicode_string
FFI.typedef :pointer, :plsa_object_attributes
FFI.typedef :uint32, :ntstatus
FFI.typedef :dword, :access_mask
module ::FFI::WIN32
extend ::FFI::Library
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
# typedef struct _GUID {
# DWORD Data1;
# WORD Data2;
# WORD Data3;
# BYTE Data4[8];
# } GUID;
class GUID < FFI::Struct
layout :Data1, :dword,
:Data2, :word,
:Data3, :word,
:Data4, [:byte, 8]
def self.[](s)
raise _('Bad GUID format.') unless s =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
new.tap do |guid|
guid[:Data1] = s[0, 8].to_i(16)
guid[:Data2] = s[9, 4].to_i(16)
guid[:Data3] = s[14, 4].to_i(16)
guid[:Data4][0] = s[19, 2].to_i(16)
guid[:Data4][1] = s[21, 2].to_i(16)
s[24, 12].split('').each_slice(2).with_index do |a, i|
guid[:Data4][i + 2] = a.join('').to_i(16)
end
end
end
def ==(other) Windows.memcmp(other, self, size) == 0 end
end
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
# typedef struct _SYSTEMTIME {
# WORD wYear;
# WORD wMonth;
# WORD wDayOfWeek;
# WORD wDay;
# WORD wHour;
# WORD wMinute;
# WORD wSecond;
# WORD wMilliseconds;
# } SYSTEMTIME, *PSYSTEMTIME;
class SYSTEMTIME < FFI::Struct
layout :wYear, :word,
:wMonth, :word,
:wDayOfWeek, :word,
:wDay, :word,
:wHour, :word,
:wMinute, :word,
:wSecond, :word,
:wMilliseconds, :word
def to_local_time
Time.local(self[:wYear], self[:wMonth], self[:wDay],
self[:wHour], self[:wMinute], self[:wSecond], self[:wMilliseconds] * 1000)
end
end
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
# Contains a 64-bit value representing the number of 100-nanosecond
# intervals since January 1, 1601 (UTC).
# typedef struct _FILETIME {
# DWORD dwLowDateTime;
# DWORD dwHighDateTime;
# } FILETIME, *PFILETIME;
class FILETIME < FFI::Struct
layout :dwLowDateTime, :dword,
:dwHighDateTime, :dword
end
ffi_convention :stdcall
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa366730(v=vs.85).aspx
# HLOCAL WINAPI LocalFree(
# _In_ HLOCAL hMem
# );
ffi_lib :kernel32
attach_function :LocalFree, [:handle], :handle
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
# BOOL WINAPI CloseHandle(
# _In_ HANDLE hObject
# );
ffi_lib :kernel32
attach_function_private :CloseHandle, [:handle], :win32_bool
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680722(v=vs.85).aspx
# void CoTaskMemFree(
# _In_opt_ LPVOID pv
# );
ffi_lib :ole32
attach_function :CoTaskMemFree, [:lpvoid], :void
end
end
end