module Puppet::Util::Windows::File

Constants

INVALID_HANDLE_VALUE

define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)

Public Class Methods

add_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
 97 def add_attributes(path, flags)
 98   oldattrs = get_attributes(path)
 99 
100   if (oldattrs | flags) != oldattrs
101     set_attributes(path, oldattrs | flags)
102   end
103 end
create_file(file_name, desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file_handle) click to toggle source
    # File lib/puppet/util/windows/file.rb
125 def self.create_file(file_name, desired_access, share_mode, security_attributes,
126   creation_disposition, flags_and_attributes, template_file_handle)
127 
128   result = CreateFileW(wide_string(file_name.to_s),
129     desired_access, share_mode, security_attributes, creation_disposition,
130     flags_and_attributes, template_file_handle)
131 
132   return result unless result == INVALID_HANDLE_VALUE
133   raise Puppet::Util::Windows::Error.new(
134     "CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_mode.to_s(8)}, " +
135       "#{security_attributes}, #{creation_disposition.to_s(8)}, " +
136       "#{flags_and_attributes.to_s(8)}, #{template_file_handle})")
137 end
device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil) click to toggle source
    # File lib/puppet/util/windows/file.rb
178 def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil)
179   if out_buffer.nil?
180     raise Puppet::Util::Windows::Error.new(_("out_buffer is required"))
181   end
182 
183   FFI::MemoryPointer.new(:dword, 1) do |bytes_returned_ptr|
184     result = DeviceIoControl(
185       handle,
186       io_control_code,
187       in_buffer, in_buffer.nil? ? 0 : in_buffer.size,
188       out_buffer, out_buffer.size,
189       bytes_returned_ptr,
190       nil
191     )
192 
193     if result == FFI::WIN32_FALSE
194       raise Puppet::Util::Windows::Error.new(
195         "DeviceIoControl(#{handle}, #{io_control_code}, " +
196         "#{in_buffer}, #{in_buffer ? in_buffer.size : ''}, " +
197         "#{out_buffer}, #{out_buffer ? out_buffer.size : ''}")
198     end
199   end
200 
201   out_buffer
202 end
exist?(path) click to toggle source
   # File lib/puppet/util/windows/file.rb
55 def exist?(path)
56   path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
57   path = path.to_s # support String and Pathname
58 
59   seen_paths = []
60   # follow up to 64 symlinks before giving up
61   0.upto(64) do |depth|
62     # return false if this path has been seen before.  This is protection against circular symlinks
63     return false if seen_paths.include?(path.downcase)
64 
65     result = get_attributes(path,false)
66 
67     # return false for path not found
68     return false if result == INVALID_FILE_ATTRIBUTES
69 
70     # return true if path exists and it's not a symlink
71     # Other file attributes are ignored. https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
72     reparse_point = (result & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
73     if reparse_point && symlink_reparse_point?(path)
74       # walk the symlink and try again...
75       seen_paths << path.downcase
76       path = readlink(path)
77     else
78       # file was found and its not a symlink
79       return true
80     end
81   end
82 
83   false
84 end
get_attributes(file_name, raise_on_invalid = true) click to toggle source
   # File lib/puppet/util/windows/file.rb
87 def get_attributes(file_name, raise_on_invalid = true)
88   result = GetFileAttributesW(wide_string(file_name.to_s))
89   if raise_on_invalid && result == INVALID_FILE_ATTRIBUTES
90     raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})")
91   end
92 
93   result
94 end
get_long_pathname(path) click to toggle source
    # File lib/puppet/util/windows/file.rb
246 def get_long_pathname(path)
247   converted = ''
248   FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
249     # includes terminating NULL
250     buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0)
251     FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
252       if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
253         raise Puppet::Util::Windows::Error.new(_("Failed to call GetLongPathName"))
254       end
255 
256       converted = converted_ptr.read_wide_string(buffer_size - 1)
257     end
258   end
259 
260   converted
261 end
get_reparse_point_data(handle) { |buffer_type| ... } click to toggle source
    # File lib/puppet/util/windows/file.rb
139 def self.get_reparse_point_data(handle, &block)
140   # must be multiple of 1024, min 10240
141   FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|
142     device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
143 
144     reparse_tag = reparse_data_buffer_ptr.read_win32_ulong
145     buffer_type = case reparse_tag
146     when IO_REPARSE_TAG_SYMLINK
147       SYMLINK_REPARSE_DATA_BUFFER
148     when IO_REPARSE_TAG_MOUNT_POINT
149       MOUNT_POINT_REPARSE_DATA_BUFFER
150     when IO_REPARSE_TAG_NFS
151       raise Puppet::Util::Windows::Error.new("Retrieving NFS reparse point data is unsupported")
152     else
153       raise Puppet::Util::Windows::Error.new("DeviceIoControl(#{handle}, " +
154         "FSCTL_GET_REPARSE_POINT) returned unknown tag 0x#{reparse_tag.to_s(16).upcase}")
155     end
156 
157     yield buffer_type.new(reparse_data_buffer_ptr)
158   end
159 
160   # underlying struct MemoryPointer has been cleaned up by this point, nothing to return
161   nil
162 end
get_reparse_point_tag(handle) click to toggle source
    # File lib/puppet/util/windows/file.rb
164 def self.get_reparse_point_tag(handle)
165   reparse_tag = nil
166 
167   # must be multiple of 1024, min 10240
168   FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|
169     device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
170 
171     # DWORD ReparseTag is the first member of the struct
172     reparse_tag = reparse_data_buffer_ptr.read_win32_ulong
173   end
174 
175   reparse_tag
176 end
get_short_pathname(path) click to toggle source
    # File lib/puppet/util/windows/file.rb
264 def get_short_pathname(path)
265   converted = ''
266   FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
267     # includes terminating NULL
268     buffer_size = GetShortPathNameW(path_ptr, FFI::Pointer::NULL, 0)
269     FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
270       if GetShortPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
271         raise Puppet::Util::Windows::Error.new("Failed to call GetShortPathName")
272       end
273 
274       converted = converted_ptr.read_wide_string(buffer_size - 1)
275     end
276   end
277 
278   converted
279 end
lstat(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
306 def lstat(file_name)
307   file_name = file_name.to_s # accommodate PathName or String
308   # monkey'ing around!
309   stat = File.lstat(file_name)
310 
311   singleton_class = class << stat; self; end
312   singleton_class.send(:define_method, :mode) do
313     Puppet::Util::Windows::Security.get_mode(file_name)
314   end
315 
316   if symlink?(file_name)
317     def stat.ftype
318       "link"
319     end
320   end
321   stat
322 end
move_file_ex(source, target, flags = 0) click to toggle source
   # File lib/puppet/util/windows/file.rb
34 def move_file_ex(source, target, flags = 0)
35   result = MoveFileExW(wide_string(source.to_s),
36                        wide_string(target.to_s),
37                        flags)
38 
39   return true if result != FFI::WIN32_FALSE
40   raise Puppet::Util::Windows::Error.
41     new("MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})")
42 end
remove_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
106 def remove_attributes(path, flags)
107   oldattrs = get_attributes(path)
108 
109   if (oldattrs & ~flags) != oldattrs
110     set_attributes(path, oldattrs & ~flags)
111   end
112 end
reparse_point?(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
204 def reparse_point?(file_name)
205   attributes = get_attributes(file_name, false)
206 
207   return false if (attributes == INVALID_FILE_ATTRIBUTES)
208   (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
209 end
replace_file(target, source) click to toggle source
   # File lib/puppet/util/windows/file.rb
14 def replace_file(target, source)
15   target_encoded = wide_string(target.to_s)
16   source_encoded = wide_string(source.to_s)
17 
18   flags = REPLACEFILE_IGNORE_MERGE_ERRORS
19   backup_file = nil
20   result = ReplaceFileW(
21     target_encoded,
22     source_encoded,
23     backup_file,
24     flags,
25     FFI::Pointer::NULL,
26     FFI::Pointer::NULL
27   )
28 
29   return true if result != FFI::WIN32_FALSE
30   raise Puppet::Util::Windows::Error.new("ReplaceFile(#{target}, #{source})")
31 end
set_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
115 def set_attributes(path, flags)
116   success = SetFileAttributesW(wide_string(path), flags) != FFI::WIN32_FALSE
117   raise Puppet::Util::Windows::Error.new(_("Failed to set file attributes")) if !success
118 
119   success
120 end
stat(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
282 def stat(file_name)
283   file_name = file_name.to_s # accommodate PathName or String
284   stat = File.stat(file_name)
285   singleton_class = class << stat; self; end
286   target_path = file_name
287 
288   if symlink?(file_name)
289     target_path = readlink(file_name)
290     link_ftype = File.stat(target_path).ftype
291 
292     # sigh, monkey patch instance method for instance, and close over link_ftype
293     singleton_class.send(:define_method, :ftype) do
294       link_ftype
295     end
296   end
297 
298   singleton_class.send(:define_method, :mode) do
299     Puppet::Util::Windows::Security.get_mode(target_path)
300   end
301 
302   stat
303 end

Private Class Methods

Private Instance Methods

add_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
 97 def add_attributes(path, flags)
 98   oldattrs = get_attributes(path)
 99 
100   if (oldattrs | flags) != oldattrs
101     set_attributes(path, oldattrs | flags)
102   end
103 end
exist?(path) click to toggle source
   # File lib/puppet/util/windows/file.rb
55 def exist?(path)
56   path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
57   path = path.to_s # support String and Pathname
58 
59   seen_paths = []
60   # follow up to 64 symlinks before giving up
61   0.upto(64) do |depth|
62     # return false if this path has been seen before.  This is protection against circular symlinks
63     return false if seen_paths.include?(path.downcase)
64 
65     result = get_attributes(path,false)
66 
67     # return false for path not found
68     return false if result == INVALID_FILE_ATTRIBUTES
69 
70     # return true if path exists and it's not a symlink
71     # Other file attributes are ignored. https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
72     reparse_point = (result & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
73     if reparse_point && symlink_reparse_point?(path)
74       # walk the symlink and try again...
75       seen_paths << path.downcase
76       path = readlink(path)
77     else
78       # file was found and its not a symlink
79       return true
80     end
81   end
82 
83   false
84 end
get_attributes(file_name, raise_on_invalid = true) click to toggle source
   # File lib/puppet/util/windows/file.rb
87 def get_attributes(file_name, raise_on_invalid = true)
88   result = GetFileAttributesW(wide_string(file_name.to_s))
89   if raise_on_invalid && result == INVALID_FILE_ATTRIBUTES
90     raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})")
91   end
92 
93   result
94 end
get_long_pathname(path) click to toggle source
    # File lib/puppet/util/windows/file.rb
246 def get_long_pathname(path)
247   converted = ''
248   FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
249     # includes terminating NULL
250     buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0)
251     FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
252       if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
253         raise Puppet::Util::Windows::Error.new(_("Failed to call GetLongPathName"))
254       end
255 
256       converted = converted_ptr.read_wide_string(buffer_size - 1)
257     end
258   end
259 
260   converted
261 end
get_short_pathname(path) click to toggle source
    # File lib/puppet/util/windows/file.rb
264 def get_short_pathname(path)
265   converted = ''
266   FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
267     # includes terminating NULL
268     buffer_size = GetShortPathNameW(path_ptr, FFI::Pointer::NULL, 0)
269     FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
270       if GetShortPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
271         raise Puppet::Util::Windows::Error.new("Failed to call GetShortPathName")
272       end
273 
274       converted = converted_ptr.read_wide_string(buffer_size - 1)
275     end
276   end
277 
278   converted
279 end
lstat(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
306 def lstat(file_name)
307   file_name = file_name.to_s # accommodate PathName or String
308   # monkey'ing around!
309   stat = File.lstat(file_name)
310 
311   singleton_class = class << stat; self; end
312   singleton_class.send(:define_method, :mode) do
313     Puppet::Util::Windows::Security.get_mode(file_name)
314   end
315 
316   if symlink?(file_name)
317     def stat.ftype
318       "link"
319     end
320   end
321   stat
322 end
move_file_ex(source, target, flags = 0) click to toggle source
   # File lib/puppet/util/windows/file.rb
34 def move_file_ex(source, target, flags = 0)
35   result = MoveFileExW(wide_string(source.to_s),
36                        wide_string(target.to_s),
37                        flags)
38 
39   return true if result != FFI::WIN32_FALSE
40   raise Puppet::Util::Windows::Error.
41     new("MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})")
42 end
remove_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
106 def remove_attributes(path, flags)
107   oldattrs = get_attributes(path)
108 
109   if (oldattrs & ~flags) != oldattrs
110     set_attributes(path, oldattrs & ~flags)
111   end
112 end
reparse_point?(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
204 def reparse_point?(file_name)
205   attributes = get_attributes(file_name, false)
206 
207   return false if (attributes == INVALID_FILE_ATTRIBUTES)
208   (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
209 end
replace_file(target, source) click to toggle source
   # File lib/puppet/util/windows/file.rb
14 def replace_file(target, source)
15   target_encoded = wide_string(target.to_s)
16   source_encoded = wide_string(source.to_s)
17 
18   flags = REPLACEFILE_IGNORE_MERGE_ERRORS
19   backup_file = nil
20   result = ReplaceFileW(
21     target_encoded,
22     source_encoded,
23     backup_file,
24     flags,
25     FFI::Pointer::NULL,
26     FFI::Pointer::NULL
27   )
28 
29   return true if result != FFI::WIN32_FALSE
30   raise Puppet::Util::Windows::Error.new("ReplaceFile(#{target}, #{source})")
31 end
set_attributes(path, flags) click to toggle source
    # File lib/puppet/util/windows/file.rb
115 def set_attributes(path, flags)
116   success = SetFileAttributesW(wide_string(path), flags) != FFI::WIN32_FALSE
117   raise Puppet::Util::Windows::Error.new(_("Failed to set file attributes")) if !success
118 
119   success
120 end
stat(file_name) click to toggle source
    # File lib/puppet/util/windows/file.rb
282 def stat(file_name)
283   file_name = file_name.to_s # accommodate PathName or String
284   stat = File.stat(file_name)
285   singleton_class = class << stat; self; end
286   target_path = file_name
287 
288   if symlink?(file_name)
289     target_path = readlink(file_name)
290     link_ftype = File.stat(target_path).ftype
291 
292     # sigh, monkey patch instance method for instance, and close over link_ftype
293     singleton_class.send(:define_method, :ftype) do
294       link_ftype
295     end
296   end
297 
298   singleton_class.send(:define_method, :mode) do
299     Puppet::Util::Windows::Security.get_mode(target_path)
300   end
301 
302   stat
303 end