puppet 5.5.20-universal-darwin → 5.5.21-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +19 -19
  3. data/lib/puppet/agent.rb +3 -3
  4. data/lib/puppet/application/agent.rb +3 -1
  5. data/lib/puppet/daemon.rb +1 -1
  6. data/lib/puppet/defaults.rb +2 -2
  7. data/lib/puppet/file_system/uniquefile.rb +4 -0
  8. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  9. data/lib/puppet/network/http/api/master/v3/environment.rb +3 -0
  10. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +2 -0
  11. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +2 -0
  12. data/lib/puppet/parser/environment_compiler.rb +3 -0
  13. data/lib/puppet/parser/resource.rb +3 -2
  14. data/lib/puppet/parser/resource/param.rb +6 -0
  15. data/lib/puppet/pops/issues.rb +5 -0
  16. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -0
  17. data/lib/puppet/pops/validation/checker4_0.rb +10 -0
  18. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  19. data/lib/puppet/provider/package/dnfmodule.rb +24 -4
  20. data/lib/puppet/provider/package/pip.rb +6 -4
  21. data/lib/puppet/provider/package/zypper.rb +1 -0
  22. data/lib/puppet/provider/service/systemd.rb +22 -4
  23. data/lib/puppet/provider/user/useradd.rb +16 -5
  24. data/lib/puppet/resource/type.rb +8 -0
  25. data/lib/puppet/test/test_helper.rb +8 -10
  26. data/lib/puppet/type.rb +6 -0
  27. data/lib/puppet/type/package.rb +16 -1
  28. data/lib/puppet/type/service.rb +1 -7
  29. data/lib/puppet/type/user.rb +1 -7
  30. data/lib/puppet/util.rb +12 -13
  31. data/lib/puppet/util/log/destinations.rb +1 -10
  32. data/lib/puppet/util/windows/api_types.rb +45 -32
  33. data/lib/puppet/util/windows/eventlog.rb +1 -6
  34. data/lib/puppet/util/windows/principal.rb +8 -6
  35. data/lib/puppet/util/windows/registry.rb +11 -11
  36. data/lib/puppet/version.rb +1 -1
  37. data/locales/puppet.pot +97 -93
  38. data/man/man5/puppet.conf.5 +2 -2
  39. data/man/man8/puppet-agent.8 +2 -2
  40. data/man/man8/puppet-apply.8 +1 -1
  41. data/man/man8/puppet-ca.8 +1 -1
  42. data/man/man8/puppet-catalog.8 +1 -1
  43. data/man/man8/puppet-cert.8 +1 -1
  44. data/man/man8/puppet-certificate.8 +1 -1
  45. data/man/man8/puppet-certificate_request.8 +1 -1
  46. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  47. data/man/man8/puppet-config.8 +1 -1
  48. data/man/man8/puppet-describe.8 +1 -1
  49. data/man/man8/puppet-device.8 +1 -1
  50. data/man/man8/puppet-doc.8 +1 -1
  51. data/man/man8/puppet-epp.8 +1 -1
  52. data/man/man8/puppet-facts.8 +1 -1
  53. data/man/man8/puppet-filebucket.8 +1 -1
  54. data/man/man8/puppet-generate.8 +1 -1
  55. data/man/man8/puppet-help.8 +1 -1
  56. data/man/man8/puppet-key.8 +1 -1
  57. data/man/man8/puppet-lookup.8 +1 -1
  58. data/man/man8/puppet-man.8 +1 -1
  59. data/man/man8/puppet-master.8 +1 -1
  60. data/man/man8/puppet-module.8 +1 -1
  61. data/man/man8/puppet-node.8 +1 -1
  62. data/man/man8/puppet-parser.8 +1 -1
  63. data/man/man8/puppet-plugin.8 +1 -1
  64. data/man/man8/puppet-report.8 +1 -1
  65. data/man/man8/puppet-resource.8 +1 -1
  66. data/man/man8/puppet-script.8 +1 -1
  67. data/man/man8/puppet-status.8 +1 -1
  68. data/man/man8/puppet.8 +2 -2
  69. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-enabled.txt → dnf-module-list.txt} +6 -0
  70. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  71. data/spec/integration/defaults_spec.rb +1 -2
  72. data/spec/integration/parser/compiler_spec.rb +11 -0
  73. data/spec/integration/util/windows/adsi_spec.rb +5 -0
  74. data/spec/integration/util/windows/registry_spec.rb +7 -7
  75. data/spec/unit/agent_spec.rb +1 -1
  76. data/spec/unit/daemon_spec.rb +0 -1
  77. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  78. data/spec/unit/network/http/api/indirected_routes_spec.rb +2 -1
  79. data/spec/unit/parser/environment_compiler_spec.rb +7 -0
  80. data/spec/unit/provider/package/dnfmodule_spec.rb +25 -5
  81. data/spec/unit/provider/package/pip_spec.rb +42 -16
  82. data/spec/unit/provider/package/zypper_spec.rb +13 -0
  83. data/spec/unit/provider/service/systemd_spec.rb +93 -20
  84. data/spec/unit/provider/user/openbsd_spec.rb +1 -0
  85. data/spec/unit/provider/user/useradd_spec.rb +30 -16
  86. data/spec/unit/test/test_helper_spec.rb +17 -0
  87. data/spec/unit/type/service_spec.rb +9 -8
  88. data/spec/unit/type/user_spec.rb +19 -13
  89. data/spec/unit/util/log/destinations_spec.rb +1 -29
  90. data/spec/unit/util/windows/api_types_spec.rb +104 -40
  91. metadata +7 -7
  92. data/spec/integration/test/test_helper_spec.rb +0 -31
@@ -26,7 +26,8 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
26
26
  def self.instances
27
27
  i = []
28
28
  output = systemctl('list-unit-files', '--type', 'service', '--full', '--all', '--no-pager')
29
- output.scan(/^(\S+)\s+(disabled|enabled|masked|indirect)\s*$/i).each do |m|
29
+ output.scan(/^(\S+)\s+(disabled|enabled|masked|indirect|bad|static)\s*$/i).each do |m|
30
+ Puppet.debug("#{m[0]} marked as bad by `systemctl`. It is recommended to be further checked.") if m[1] == "bad"
30
31
  i << new(:name => m[0])
31
32
  end
32
33
  return i
@@ -34,6 +35,22 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
34
35
  return []
35
36
  end
36
37
 
38
+ # Static services cannot be enabled or disabled manually. Indirect services
39
+ # should not be enabled or disabled due to limitations in systemd (see
40
+ # https://github.com/systemd/systemd/issues/6681).
41
+ def enabled_insync?(current)
42
+ case cached_enabled?[:output]
43
+ when 'static'
44
+ Puppet.debug("Unable to enable or disable static service #{@resource[:name]}")
45
+ return true
46
+ when 'indirect'
47
+ Puppet.debug("Service #{@resource[:name]} is in 'indirect' state and cannot be enabled/disabled")
48
+ return true
49
+ else
50
+ current == @resource[:enable]
51
+ end
52
+ end
53
+
37
54
  # This helper ensures that the enable state cache is always reset
38
55
  # after a systemctl enable operation. A particular service state is not guaranteed
39
56
  # after such an operation, so the cache must be emptied to prevent inconsistencies
@@ -65,12 +82,13 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
65
82
  def cached_enabled?
66
83
  return @cached_enabled if @cached_enabled
67
84
  cmd = [command(:systemctl), 'is-enabled', '--', @resource[:name]]
68
- @cached_enabled = execute(cmd, :failonfail => false).strip
85
+ result = execute(cmd, :failonfail => false)
86
+ @cached_enabled = { output: result.chomp, exitcode: result.exitstatus }
69
87
  end
70
88
 
71
89
  def enabled?
72
- output = cached_enabled?
73
- code = $CHILD_STATUS.exitstatus
90
+ output = cached_enabled?[:output]
91
+ code = cached_enabled?[:exitcode]
74
92
 
75
93
  # The masked state is equivalent to the disabled state in terms of
76
94
  # comparison so we only care to check if it is masked if we want to keep
@@ -21,7 +21,11 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
21
21
  options :expiry, :method => :sp_expire,
22
22
  :munge => proc { |value|
23
23
  if value == :absent
24
- ''
24
+ if Facter.value(:operatingsystem)=='SLES' && Facter.value(:operatingsystemmajrelease) == "11"
25
+ -1
26
+ else
27
+ ''
28
+ end
25
29
  else
26
30
  case Facter.value(:operatingsystem)
27
31
  when 'Solaris'
@@ -134,10 +138,17 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
134
138
 
135
139
  def check_manage_home
136
140
  cmd = []
137
- if @resource.managehome? && (!@resource.forcelocal?)
138
- cmd << "-m"
139
- elsif (!@resource.managehome?) && Facter.value(:osfamily) == 'RedHat'
140
- cmd << "-M"
141
+ if @resource.managehome?
142
+ # libuser does not implement the -m flag
143
+ cmd << "-m" unless @resource.forcelocal?
144
+ else
145
+ osfamily = Facter.value(:osfamily)
146
+ osversion = Facter.value(:operatingsystemmajrelease).to_i
147
+ # SLES 11 uses pwdutils instead of shadow, which does not have -M
148
+ # Solaris and OpenBSD use different useradd flavors
149
+ unless osfamily =~ /Solaris|OpenBSD/ || osfamily == 'Suse' && osversion <= 11
150
+ cmd << "-M"
151
+ end
141
152
  end
142
153
  cmd
143
154
  end
@@ -11,6 +11,7 @@ class Puppet::Resource::Type
11
11
  include Puppet::Util::Warnings
12
12
  include Puppet::Util::Errors
13
13
 
14
+ # @deprecated application orchestration will be removed in puppet 7 (capability_mapping, application, site)
14
15
  RESOURCE_KINDS = [:hostclass, :node, :definition, :capability_mapping, :application, :site]
15
16
 
16
17
  # Map the names used in our documentation to the names used internally
@@ -69,6 +70,8 @@ class Puppet::Resource::Type
69
70
 
70
71
  # Evaluate the resources produced by the given resource. These resources are
71
72
  # evaluated in a separate but identical scope from the rest of the resource.
73
+ #
74
+ # @deprecated application orchestration will be removed in puppet 7
72
75
  def evaluate_produces(resource, scope)
73
76
  # Only defined types and classes can produce capabilities
74
77
  return unless definition? || hostclass?
@@ -159,19 +162,23 @@ class Puppet::Resource::Type
159
162
  @module_name = options[:module_name]
160
163
  end
161
164
 
165
+ # @deprecated application orchestration will be removed in puppet 7
162
166
  def produces
163
167
  @produces || EMPTY_ARRAY
164
168
  end
165
169
 
170
+ # @deprecated application orchestration will be removed in puppet 7
166
171
  def consumes
167
172
  @consumes || EMPTY_ARRAY
168
173
  end
169
174
 
175
+ # @deprecated application orchestration will be removed in puppet 7
170
176
  def add_produces(blueprint)
171
177
  @produces ||= []
172
178
  @produces << blueprint
173
179
  end
174
180
 
181
+ # @deprecated application orchestration will be removed in puppet 7
175
182
  def add_consumes(blueprint)
176
183
  @consumes ||= []
177
184
  @consumes << blueprint
@@ -233,6 +240,7 @@ class Puppet::Resource::Type
233
240
  when :node
234
241
  :node
235
242
  when :site
243
+ # @deprecated application orchestration will be removed in puppet 7
236
244
  :site
237
245
  end
238
246
 
@@ -68,7 +68,14 @@ module Puppet::Test
68
68
  # any individual tests.
69
69
  # @return nil
70
70
  def self.before_all_tests()
71
- # Make sure that all of the setup is also done for any before(:all) blocks
71
+ # The process environment is a shared, persistent resource.
72
+ # Can't use Puppet.features.microsoft_windows? as it may be mocked out in a test. This can cause test recurring test failures
73
+ if (!!File::ALT_SEPARATOR)
74
+ mode = :windows
75
+ else
76
+ mode = :posix
77
+ end
78
+ $old_env = Puppet::Util.get_environment(mode)
72
79
  end
73
80
 
74
81
  # Call this method once, at the end of a test run, when no more tests
@@ -118,15 +125,6 @@ module Puppet::Test
118
125
  }
119
126
  end
120
127
 
121
- # The process environment is a shared, persistent resource.
122
- # Can't use Puppet.features.microsoft_windows? as it may be mocked out in a test. This can cause test recurring test failures
123
- if (!!File::ALT_SEPARATOR)
124
- mode = :windows
125
- else
126
- mode = :posix
127
- end
128
- $old_env = Puppet::Util.get_environment(mode)
129
-
130
128
  # So is the load_path
131
129
  $old_load_path = $LOAD_PATH.dup
132
130
 
@@ -110,8 +110,10 @@ class Type
110
110
 
111
111
  # Allow declaring that a type is actually a capability
112
112
  class << self
113
+ # @deprecated application orchestration will be removed in puppet 7
113
114
  attr_accessor :is_capability
114
115
 
116
+ # @deprecated application orchestration will be removed in puppet 7
115
117
  def is_capability?
116
118
  c = is_capability
117
119
  c.nil? ? false : c
@@ -123,6 +125,8 @@ class Type
123
125
  # represent application instances, this implementation always returns
124
126
  # +false+. Having this method though makes code checking whether a
125
127
  # resource is an application instance simpler
128
+ #
129
+ # @deprecated application orchestration will be removed in puppet 7
126
130
  def self.application?
127
131
  false
128
132
  end
@@ -1667,6 +1671,7 @@ class Type
1667
1671
  }
1668
1672
  end
1669
1673
 
1674
+ # @deprecated application orchestration will be removed in puppet 7
1670
1675
  newmetaparam(:export, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
1671
1676
  desc <<EOS
1672
1677
  Export a capability resource.
@@ -1692,6 +1697,7 @@ web { server:
1692
1697
  EOS
1693
1698
  end
1694
1699
 
1700
+ # @deprecated application orchestration will be removed in puppet 7
1695
1701
  newmetaparam(:consume, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
1696
1702
  desc <<EOS
1697
1703
  Consume a capability resource.
@@ -61,6 +61,9 @@ module Puppet
61
61
  passed to the installer command."
62
62
  feature :uninstall_options, "The provider accepts options to be
63
63
  passed to the uninstaller command."
64
+ feature :disableable, "The provider can disable packages. This feature is used by specifying `disabled` as the
65
+ desired value for the package.",
66
+ :methods => [:disable]
64
67
  feature :supports_flavors, "The provider accepts flavors, which are specific variants of packages."
65
68
  feature :package_settings, "The provider accepts package_settings to be
66
69
  ensured for the given package. The meaning and format of these settings is
@@ -104,6 +107,10 @@ module Puppet
104
107
  provider.deprecated_hold
105
108
  end
106
109
 
110
+ newvalue(:disabled, :required_features => :disableable) do
111
+ provider.disable
112
+ end
113
+
107
114
  # Alias the 'present' value.
108
115
  aliasvalue(:installed, :present)
109
116
 
@@ -151,7 +158,7 @@ module Puppet
151
158
  @should.each { |should|
152
159
  case should
153
160
  when :present
154
- return true unless [:absent, :purged, :held].include?(is)
161
+ return true unless [:absent, :purged, :held, :disabled].include?(is)
155
162
  when :latest
156
163
  # Short-circuit packages that are not present
157
164
  return false if is == :absent || is == :purged
@@ -404,6 +411,11 @@ module Puppet
404
411
  newproperty(:flavor, :required_features => :supports_flavors) do
405
412
  desc "OpenBSD and DNF modules support 'flavors', which are
406
413
  further specifications for which type of package you want."
414
+ validate do |value|
415
+ if [:disabled, "disabled"].include?(@resource[:ensure]) && value
416
+ raise ArgumentError, _('Cannot have both `ensure => disabled` and `flavor`')
417
+ end
418
+ end
407
419
  end
408
420
 
409
421
  newparam(:source) do
@@ -502,6 +514,9 @@ module Puppet
502
514
  if [true, :true, "true"].include?(value) && @resource[:flavor]
503
515
  raise ArgumentError, _('Cannot have both `enable_only => true` and `flavor`')
504
516
  end
517
+ if [:disabled, "disabled"].include?(@resource[:ensure])
518
+ raise ArgumentError, _('Cannot have both `ensure => disabled` and `enable_only => true`')
519
+ end
505
520
  end
506
521
  end
507
522
 
@@ -78,14 +78,8 @@ module Puppet
78
78
  provider.delayed_start
79
79
  end
80
80
 
81
- # This only makes sense on systemd systems. Static services cannot be enabled
82
- # or disabled manually.
83
81
  def insync?(current)
84
- if provider.respond_to?(:cached_enabled?) && provider.cached_enabled? == 'static'
85
- Puppet.debug("Unable to enable or disable static service #{@resource[:name]}")
86
- return true
87
- end
88
-
82
+ return provider.enabled_insync?(current) if provider.respond_to?(:enabled_insync?)
89
83
  super(current)
90
84
  end
91
85
 
@@ -719,17 +719,11 @@ module Puppet
719
719
  value = test_sym if [:true, :false].include? test_sym
720
720
 
721
721
  return [] if value == :false
722
- home = resource[:home]
723
- if value == :true and not home
724
- raise ArgumentError, _("purge_ssh_keys can only be true for users with a defined home directory")
725
- end
722
+ home = resource[:home] || Dir.home(resource[:name])
726
723
 
727
724
  return [ "#{home}/.ssh/authorized_keys" ] if value == :true
728
725
  # value is an array - munge each value
729
726
  [ value ].flatten.map do |entry|
730
- if entry =~ /^~|^%h/ and not home
731
- raise ArgumentError, _("purge_ssh_keys value '%{value}' meta character ~ or %{home_placeholder} only allowed for users with a defined home directory") % { value: value, home_placeholder: '%h' }
732
- end
733
727
  entry.gsub!(/^~\//, "#{home}/")
734
728
  entry.gsub!(/^%h\//, "#{home}/")
735
729
  entry
@@ -27,21 +27,20 @@ module Util
27
27
 
28
28
  extend Puppet::Util::SymbolicFileMode
29
29
 
30
- def default_env
31
- Puppet.features.microsoft_windows? ?
32
- :windows :
33
- :posix
34
- end
35
- module_function :default_env
30
+ DEFAULT_ENV = if Puppet::Util::Platform.windows?
31
+ :windows
32
+ else
33
+ :posix
34
+ end.freeze
36
35
 
37
36
  # @param name [String] The name of the environment variable to retrieve
38
37
  # @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
39
38
  # @return [String] Value of the specified environment variable. nil if it does not exist
40
39
  # @api private
41
- def get_env(name, mode = default_env)
40
+ def get_env(name, mode = DEFAULT_ENV)
42
41
  if mode == :windows
43
- Puppet::Util::Windows::Process.get_environment_strings.each do |key, value |
44
- if name.casecmp(key) == 0 then
42
+ Puppet::Util::Windows::Process.get_environment_strings.find do |key, value|
43
+ if name.casecmp(key) == 0
45
44
  return value
46
45
  end
47
46
  end
@@ -55,7 +54,7 @@ module Util
55
54
  # @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
56
55
  # @return [Hash] A hashtable of all environment variables
57
56
  # @api private
58
- def get_environment(mode = default_env)
57
+ def get_environment(mode = DEFAULT_ENV)
59
58
  case mode
60
59
  when :posix
61
60
  ENV.to_hash
@@ -70,7 +69,7 @@ module Util
70
69
  # Removes all environment variables
71
70
  # @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
72
71
  # @api private
73
- def clear_environment(mode = default_env)
72
+ def clear_environment(mode = DEFAULT_ENV)
74
73
  case mode
75
74
  when :posix
76
75
  ENV.clear
@@ -88,7 +87,7 @@ module Util
88
87
  # @param value [String] The value to set the variable to. nil deletes the environment variable
89
88
  # @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
90
89
  # @api private
91
- def set_env(name, value = nil, mode = default_env)
90
+ def set_env(name, value = nil, mode = DEFAULT_ENV)
92
91
  case mode
93
92
  when :posix
94
93
  ENV[name] = value
@@ -103,7 +102,7 @@ module Util
103
102
  # @param name [Hash] Environment variables to merge into the existing environment. nil values will remove the variable
104
103
  # @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
105
104
  # @api private
106
- def merge_environment(env_hash, mode = default_env)
105
+ def merge_environment(env_hash, mode = DEFAULT_ENV)
107
106
  case mode
108
107
  when :posix
109
108
  env_hash.each { |name, val| ENV[name.to_s] = val }
@@ -90,18 +90,9 @@ Puppet::Util::Log.newdesttype :file do
90
90
  end
91
91
  end
92
92
 
93
- file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
93
+ file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
94
94
  file.puts('[') if need_array_start
95
95
 
96
- # Give ownership to the user and group puppet will run as
97
- if Puppet.features.root? && !Puppet::Util::Platform.windows? && !file_exists
98
- begin
99
- FileUtils.chown(Puppet[:user], Puppet[:group], path)
100
- rescue ArgumentError, Errno::EPERM
101
- Puppet.err _("Unable to set ownership to %{user}:%{group} for log file: %{path}") % { user: Puppet[:user], group: Puppet[:group], path: path }
102
- end
103
- end
104
-
105
96
  @file = file
106
97
 
107
98
  @autoflush = Puppet[:autoflush]
@@ -19,15 +19,11 @@ module Puppet::Util::Windows::APITypes
19
19
 
20
20
  class ::FFI::Pointer
21
21
  NULL_HANDLE = 0
22
+ WCHAR_NULL = "\0\0".encode('UTF-16LE').freeze
22
23
 
23
24
  def self.from_string_to_wide_string(str, &block)
24
25
  str = Puppet::Util::Windows::String.wide_string(str)
25
- FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
26
- # uchar here is synonymous with byte
27
- ptr.put_array_of_uchar(0, str.bytes.to_a)
28
-
29
- yield ptr
30
- end
26
+ FFI::MemoryPointer.from_wide_string(str, &block)
31
27
 
32
28
  # ptr has already had free called, so nothing to return
33
29
  nil
@@ -53,11 +49,17 @@ module Puppet::Util::Windows::APITypes
53
49
  alias_method :read_word, :read_uint16
54
50
  alias_method :read_array_of_wchar, :read_array_of_uint16
55
51
 
56
- def read_wide_string(char_length, dst_encoding = Encoding::UTF_8, encode_options = {})
52
+ def read_wide_string(char_length, dst_encoding = Encoding::UTF_8, strip = false, encode_options = {})
57
53
  # char_length is number of wide chars (typically excluding NULLs), *not* bytes
58
54
  str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
55
+
56
+ if strip
57
+ i = str.index(WCHAR_NULL)
58
+ str = str[0, i] if i
59
+ end
60
+
59
61
  str.encode(dst_encoding, str.encoding, encode_options)
60
- rescue Exception => e
62
+ rescue EncodingError => e
61
63
  Puppet.debug "Unable to convert value #{str.nil? ? 'nil' : str.dump} to encoding #{dst_encoding} due to #{e.inspect}"
62
64
  raise
63
65
  end
@@ -68,32 +70,31 @@ module Puppet::Util::Windows::APITypes
68
70
  # null_terminator = :double_null, then the terminating sequence is four bytes of zero. This is UNIT32 = 0
69
71
  # @param encode_options [Hash] Accepts the same option hash that may be passed to String#encode in Ruby
70
72
  def read_arbitrary_wide_string_up_to(max_char_length = 512, null_terminator = :single_null, encode_options = {})
71
- if null_terminator != :single_null && null_terminator != :double_null
72
- raise _("Unable to read wide strings with %{null_terminator} terminal nulls") % { null_terminator: null_terminator }
73
- end
74
-
75
- terminator_width = null_terminator == :single_null ? 1 : 2
76
- reader_method = null_terminator == :single_null ? :get_uint16 : :get_uint32
77
-
78
- # Look for a null terminating characters; if found, read up to that null (exclusive)
79
- (0...max_char_length - terminator_width).each do |i|
80
- return read_wide_string(i, Encoding::UTF_8, encode_options) if send(reader_method, (i * 2)) == 0
81
- end
82
-
83
- # String is longer than the max; read just to the max
84
- read_wide_string(max_char_length, Encoding::UTF_8, encode_options)
73
+ idx = case null_terminator
74
+ when :single_null
75
+ # find index of wide null between 0 and max (exclusive)
76
+ (0...max_char_length).find do |i|
77
+ get_uint16(i * 2) == 0
78
+ end
79
+ when :double_null
80
+ # find index of double-wide null between 0 and max - 1 (exclusive)
81
+ (0...max_char_length - 1).find do |i|
82
+ get_uint32(i * 2) == 0
83
+ end
84
+ else
85
+ raise _("Unable to read wide strings with %{null_terminator} terminal nulls") % { null_terminator: null_terminator }
86
+ end
87
+
88
+ read_wide_string(idx || max_char_length, Encoding::UTF_8, false, encode_options)
85
89
  end
86
90
 
87
91
  def read_win32_local_pointer(&block)
88
- ptr = nil
92
+ ptr = read_pointer
89
93
  begin
90
- ptr = read_pointer
91
94
  yield ptr
92
95
  ensure
93
- if ptr && ! ptr.null?
94
- if FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
95
- Puppet.debug "LocalFree memory leak"
96
- end
96
+ if !ptr.null? && FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
97
+ Puppet.debug "LocalFree memory leak"
97
98
  end
98
99
  end
99
100
 
@@ -102,23 +103,35 @@ module Puppet::Util::Windows::APITypes
102
103
  end
103
104
 
104
105
  def read_com_memory_pointer(&block)
105
- ptr = nil
106
+ ptr = read_pointer
106
107
  begin
107
- ptr = read_pointer
108
108
  yield ptr
109
109
  ensure
110
- FFI::WIN32::CoTaskMemFree(ptr) if ptr && ! ptr.null?
110
+ FFI::WIN32::CoTaskMemFree(ptr) unless ptr.null?
111
111
  end
112
112
 
113
113
  # ptr has already had CoTaskMemFree called, so nothing to return
114
114
  nil
115
115
  end
116
116
 
117
-
118
117
  alias_method :write_dword, :write_uint32
119
118
  alias_method :write_word, :write_uint16
120
119
  end
121
120
 
121
+ class FFI::MemoryPointer
122
+ # Return a MemoryPointer that points to wide string. This is analogous to the
123
+ # FFI::MemoryPointer.from_string method.
124
+ def self.from_wide_string(wstr)
125
+ ptr = FFI::MemoryPointer.new(:uchar, wstr.bytesize + 2)
126
+ ptr.put_array_of_uchar(0, wstr.bytes.to_a)
127
+ ptr.put_uint16(wstr.bytesize, 0)
128
+
129
+ yield ptr if block_given?
130
+
131
+ ptr
132
+ end
133
+ end
134
+
122
135
  # FFI Types
123
136
  # https://github.com/ffi/ffi/wiki/Types
124
137