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

Private Class Methods

Private Instance Methods

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