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
open_symlink(link_name) { |handle = create_file( link_name, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0) ensure WIN32.CloseHandle(handle)| ... }
click to toggle source
# File lib/puppet/util/windows/file.rb 218 def self.open_symlink(link_name) 219 begin 220 yield handle = create_file( 221 link_name, 222 GENERIC_READ, 223 FILE_SHARE_READ, 224 nil, # security_attributes 225 OPEN_EXISTING, 226 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 227 0) # template_file 228 ensure 229 FFI::WIN32.CloseHandle(handle) if handle 230 end 231 232 # handle has had CloseHandle called against it, so nothing to return 233 nil 234 end
readlink(link_name)
click to toggle source
# File lib/puppet/util/windows/file.rb 236 def readlink(link_name) 237 link = nil 238 open_symlink(link_name) do |handle| 239 link = resolve_symlink(handle) 240 end 241 242 link 243 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
symlink(target, symlink)
click to toggle source
# File lib/puppet/util/windows/file.rb 45 def symlink(target, symlink) 46 flags = File.directory?(target) ? 0x1 : 0x0 47 result = CreateSymbolicLinkW(wide_string(symlink.to_s), 48 wide_string(target.to_s), flags) 49 return true if result != FFI::WIN32_FALSE 50 raise Puppet::Util::Windows::Error.new( 51 "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})") 52 end
symlink?(file_name)
click to toggle source
# File lib/puppet/util/windows/file.rb 212 def symlink?(file_name) 213 # Puppet currently only handles mount point and symlink reparse points, ignores others 214 reparse_point?(file_name) && symlink_reparse_point?(file_name) 215 end
Private Class Methods
resolve_symlink(handle)
click to toggle source
# File lib/puppet/util/windows/file.rb 325 def self.resolve_symlink(handle) 326 path = nil 327 get_reparse_point_data(handle) do |reparse_data| 328 offset = reparse_data[:PrintNameOffset] 329 length = reparse_data[:PrintNameLength] 330 331 ptr = reparse_data.pointer + reparse_data.offset_of(:PathBuffer) + offset 332 path = ptr.read_wide_string(length / 2) # length is bytes, need UTF-16 wchars 333 end 334 335 path 336 end
symlink_reparse_point?(path)
click to toggle source
these reparse point types are the only ones Puppet
currently understands so rather than raising an exception in readlink, prefer to not consider the path a symlink when stat'ing later
# File lib/puppet/util/windows/file.rb 342 def self.symlink_reparse_point?(path) 343 symlink = false 344 345 open_symlink(path) do |handle| 346 symlink = [ 347 IO_REPARSE_TAG_SYMLINK, 348 IO_REPARSE_TAG_MOUNT_POINT 349 ].include?(get_reparse_point_tag(handle)) 350 end 351 352 symlink 353 end
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
readlink(link_name)
click to toggle source
# File lib/puppet/util/windows/file.rb 236 def readlink(link_name) 237 link = nil 238 open_symlink(link_name) do |handle| 239 link = resolve_symlink(handle) 240 end 241 242 link 243 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
symlink(target, symlink)
click to toggle source
# File lib/puppet/util/windows/file.rb 45 def symlink(target, symlink) 46 flags = File.directory?(target) ? 0x1 : 0x0 47 result = CreateSymbolicLinkW(wide_string(symlink.to_s), 48 wide_string(target.to_s), flags) 49 return true if result != FFI::WIN32_FALSE 50 raise Puppet::Util::Windows::Error.new( 51 "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})") 52 end
symlink?(file_name)
click to toggle source
# File lib/puppet/util/windows/file.rb 212 def symlink?(file_name) 213 # Puppet currently only handles mount point and symlink reparse points, ignores others 214 reparse_point?(file_name) && symlink_reparse_point?(file_name) 215 end