Module: Puppet::Util::Windows::File
- Extended by:
- FFI::Library, String
- Defined in:
- lib/puppet/util/windows.rb,
lib/puppet/util/windows/file.rb
Defined Under Namespace
Classes: MOUNT_POINT_REPARSE_DATA_BUFFER, SYMLINK_REPARSE_DATA_BUFFER
Constant Summary collapse
- FILE_ATTRIBUTE_READONLY =
0x00000001- SYNCHRONIZE =
msdn.microsoft.com/en-us/library/windows/desktop/aa379607(v=vs.85).aspx The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. Some object types do not support this access right.
0x100000- DELETE =
The right to delete the object.
0x00010000- WRITE_DAC =
The right to read the information in the object’s security descriptor, not including the information in the system access control list (SACL). READ_CONTROL = 0x00020000 The right to modify the discretionary access control list (DACL) in the object’s security descriptor.
0x00040000- WRITE_OWNER =
The right to change the owner in the object’s security descriptor.
0x00080000- STANDARD_RIGHTS_REQUIRED =
Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.
0xf0000- STANDARD_RIGHTS_READ =
Currently defined to equal READ_CONTROL.
0x20000- STANDARD_RIGHTS_WRITE =
Currently defined to equal READ_CONTROL.
0x20000- STANDARD_RIGHTS_EXECUTE =
Currently defined to equal READ_CONTROL.
0x20000- STANDARD_RIGHTS_ALL =
Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE access.
0x1F0000
- SPECIFIC_RIGHTS_ALL =
0xFFFF
- FILE_READ_DATA =
1- FILE_WRITE_DATA =
2- FILE_APPEND_DATA =
4- FILE_READ_EA =
8- FILE_WRITE_EA =
16- FILE_EXECUTE =
32- FILE_DELETE_CHILD =
64- FILE_READ_ATTRIBUTES =
128- FILE_WRITE_ATTRIBUTES =
256- FILE_ALL_ACCESS =
STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
- FILE_GENERIC_READ =
STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE
- FILE_GENERIC_WRITE =
STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE
- FILE_GENERIC_EXECUTE =
STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE
- REPLACEFILE_WRITE_THROUGH =
0x1- REPLACEFILE_IGNORE_MERGE_ERRORS =
0x2- REPLACEFILE_IGNORE_ACL_ERRORS =
0x3- INVALID_FILE_ATTRIBUTES =
define INVALID_FILE_ATTRIBUTES (DWORD (-1))
0xFFFFFFFF
- INVALID_HANDLE_VALUE =
define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
FFI::Pointer.new(-1).address
- IO_REPARSE_TAG_MOUNT_POINT =
0xA0000003
- IO_REPARSE_TAG_HSM =
0xC0000004
- IO_REPARSE_TAG_HSM2 =
0x80000006- IO_REPARSE_TAG_SIS =
0x80000007- IO_REPARSE_TAG_WIM =
0x80000008- IO_REPARSE_TAG_CSV =
0x80000009- IO_REPARSE_TAG_DFS =
0x8000000A
- IO_REPARSE_TAG_SYMLINK =
0xA000000C
- IO_REPARSE_TAG_DFSR =
0x80000012- IO_REPARSE_TAG_DEDUP =
0x80000013- IO_REPARSE_TAG_NFS =
0x80000014- FILE_ATTRIBUTE_REPARSE_POINT =
0x400- GENERIC_READ =
0x80000000- GENERIC_WRITE =
0x40000000- GENERIC_EXECUTE =
0x20000000- GENERIC_ALL =
0x10000000- FILE_SHARE_READ =
1- FILE_SHARE_WRITE =
2- OPEN_EXISTING =
3- FILE_FLAG_OPEN_REPARSE_POINT =
0x00200000- FILE_FLAG_BACKUP_SEMANTICS =
0x02000000- ERROR_FILE_NOT_FOUND =
2- ERROR_PATH_NOT_FOUND =
3- FSCTL_GET_REPARSE_POINT =
0x900a8- MAXIMUM_REPARSE_DATA_BUFFER_SIZE =
16384
Class Method Summary collapse
- .add_attributes(path, flags) ⇒ Object
- .create_file(file_name, desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file_handle) ⇒ Object
- .device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil) ⇒ Object
- .exist?(path) ⇒ Boolean
- .get_attributes(file_name, raise_on_invalid = true) ⇒ Object
- .get_long_pathname(path) ⇒ Object
- .get_reparse_point_data(handle, &block) ⇒ Object
- .get_reparse_point_tag(handle) ⇒ Object
- .get_short_pathname(path) ⇒ Object
- .lstat(file_name) ⇒ Object
- .move_file_ex(source, target, flags = 0) ⇒ Object
- .open_symlink(link_name) ⇒ Object
- .readlink(link_name) ⇒ Object
- .remove_attributes(path, flags) ⇒ Object
- .reparse_point?(file_name) ⇒ Boolean
- .replace_file(target, source) ⇒ Object
- .set_attributes(path, flags) ⇒ Object
- .stat(file_name) ⇒ Object
- .symlink(target, symlink) ⇒ Object
- .symlink?(file_name) ⇒ Boolean
Methods included from FFI::Library
Methods included from String
Class Method Details
.add_attributes(path, flags) ⇒ Object
160 161 162 163 164 165 166 |
# File 'lib/puppet/util/windows/file.rb', line 160 def add_attributes(path, flags) oldattrs = get_attributes(path) if (oldattrs | flags) != oldattrs set_attributes(path, oldattrs | flags) end end |
.create_file(file_name, desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file_handle) ⇒ Object
188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/puppet/util/windows/file.rb', line 188 def self.create_file(file_name, desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file_handle) result = CreateFileW(wide_string(file_name.to_s), desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file_handle) return result unless result == INVALID_HANDLE_VALUE raise Puppet::Util::Windows::Error.new( "CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_mode.to_s(8)}, " + "#{security_attributes}, #{creation_disposition.to_s(8)}, " + "#{flags_and_attributes.to_s(8)}, #{template_file_handle})") end |
.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil) ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/puppet/util/windows/file.rb', line 253 def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil) if out_buffer.nil? raise Puppet::Util::Windows::Error.new(_("out_buffer is required")) end FFI::MemoryPointer.new(:dword, 1) do |bytes_returned_ptr| result = DeviceIoControl( handle, io_control_code, in_buffer, in_buffer.nil? ? 0 : in_buffer.size, out_buffer, out_buffer.size, bytes_returned_ptr, nil ) if result == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new( "DeviceIoControl(#{handle}, #{io_control_code}, " + "#{in_buffer}, #{in_buffer ? in_buffer.size : ''}, " + "#{out_buffer}, #{out_buffer ? out_buffer.size : ''}") end end out_buffer end |
.exist?(path) ⇒ Boolean
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/puppet/util/windows/file.rb', line 115 def exist?(path) path = path.to_str if path.respond_to?(:to_str) # support WatchedFile path = path.to_s # support String and Pathname seen_paths = [] # follow up to 64 symlinks before giving up 0.upto(64) do |depth| # return false if this path has been seen before. This is protection against circular symlinks return false if seen_paths.include?(path.downcase) result = get_attributes(path,false) # return false for path not found return false if result == INVALID_FILE_ATTRIBUTES # return true if path exists and it's not a symlink # Other file attributes are ignored. https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx reparse_point = (result & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT if reparse_point && symlink_reparse_point?(path) # walk the symlink and try again... seen_paths << path.downcase path = readlink(path) else # file was found and its not a symlink return true end end false end |
.get_attributes(file_name, raise_on_invalid = true) ⇒ Object
150 151 152 153 154 155 156 157 |
# File 'lib/puppet/util/windows/file.rb', line 150 def get_attributes(file_name, raise_on_invalid = true) result = GetFileAttributesW(wide_string(file_name.to_s)) if raise_on_invalid && result == INVALID_FILE_ATTRIBUTES raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})") end result end |
.get_long_pathname(path) ⇒ Object
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/puppet/util/windows/file.rb', line 335 def get_long_pathname(path) converted = '' FFI::Pointer.from_string_to_wide_string(path) do |path_ptr| # includes terminating NULL buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0) FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr| if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to call GetLongPathName")) end converted = converted_ptr.read_wide_string(buffer_size - 1) end end converted end |
.get_reparse_point_data(handle, &block) ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/puppet/util/windows/file.rb', line 214 def self.get_reparse_point_data(handle, &block) # must be multiple of 1024, min 10240 FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr| device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr) reparse_tag = reparse_data_buffer_ptr.read_win32_ulong buffer_type = case reparse_tag when IO_REPARSE_TAG_SYMLINK SYMLINK_REPARSE_DATA_BUFFER when IO_REPARSE_TAG_MOUNT_POINT MOUNT_POINT_REPARSE_DATA_BUFFER when IO_REPARSE_TAG_NFS raise Puppet::Util::Windows::Error.new("Retrieving NFS reparse point data is unsupported") else raise Puppet::Util::Windows::Error.new("DeviceIoControl(#{handle}, " + "FSCTL_GET_REPARSE_POINT) returned unknown tag 0x#{reparse_tag.to_s(16).upcase}") end yield buffer_type.new(reparse_data_buffer_ptr) end # underlying struct MemoryPointer has been cleaned up by this point, nothing to return nil end |
.get_reparse_point_tag(handle) ⇒ Object
239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/puppet/util/windows/file.rb', line 239 def self.get_reparse_point_tag(handle) reparse_tag = nil # must be multiple of 1024, min 10240 FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr| device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr) # DWORD ReparseTag is the first member of the struct reparse_tag = reparse_data_buffer_ptr.read_win32_ulong end reparse_tag end |
.get_short_pathname(path) ⇒ Object
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/puppet/util/windows/file.rb', line 353 def get_short_pathname(path) converted = '' FFI::Pointer.from_string_to_wide_string(path) do |path_ptr| # includes terminating NULL buffer_size = GetShortPathNameW(path_ptr, FFI::Pointer::NULL, 0) FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr| if GetShortPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new("Failed to call GetShortPathName") end converted = converted_ptr.read_wide_string(buffer_size - 1) end end converted end |
.lstat(file_name) ⇒ Object
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/puppet/util/windows/file.rb', line 395 def lstat(file_name) file_name = file_name.to_s # accommodate PathName or String # monkey'ing around! stat = File.lstat(file_name) singleton_class = class << stat; self; end singleton_class.send(:define_method, :mode) do Puppet::Util::Windows::Security.get_mode(file_name) end if symlink?(file_name) def stat.ftype "link" end end stat end |
.move_file_ex(source, target, flags = 0) ⇒ Object
93 94 95 96 97 98 99 100 101 |
# File 'lib/puppet/util/windows/file.rb', line 93 def move_file_ex(source, target, flags = 0) result = MoveFileExW(wide_string(source.to_s), wide_string(target.to_s), flags) return true if result != FFI::WIN32_FALSE raise Puppet::Util::Windows::Error. new("MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})") end |
.open_symlink(link_name) ⇒ Object
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/puppet/util/windows/file.rb', line 304 def self.open_symlink(link_name) begin yield handle = create_file( link_name, GENERIC_READ, FILE_SHARE_READ, nil, # security_attributes OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0) # template_file ensure FFI::WIN32.CloseHandle(handle) if handle end # handle has had CloseHandle called against it, so nothing to return nil end |
.readlink(link_name) ⇒ Object
322 323 324 325 326 327 328 329 |
# File 'lib/puppet/util/windows/file.rb', line 322 def readlink(link_name) link = nil open_symlink(link_name) do |handle| link = resolve_symlink(handle) end link end |
.remove_attributes(path, flags) ⇒ Object
169 170 171 172 173 174 175 |
# File 'lib/puppet/util/windows/file.rb', line 169 def remove_attributes(path, flags) oldattrs = get_attributes(path) if (oldattrs & ~flags) != oldattrs set_attributes(path, oldattrs & ~flags) end end |
.reparse_point?(file_name) ⇒ Boolean
280 281 282 283 284 285 |
# File 'lib/puppet/util/windows/file.rb', line 280 def reparse_point?(file_name) attributes = get_attributes(file_name, false) return false if (attributes == INVALID_FILE_ATTRIBUTES) (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT end |
.replace_file(target, source) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/puppet/util/windows/file.rb', line 73 def replace_file(target, source) target_encoded = wide_string(target.to_s) source_encoded = wide_string(source.to_s) flags = REPLACEFILE_IGNORE_MERGE_ERRORS backup_file = nil result = ReplaceFileW( target_encoded, source_encoded, backup_file, flags, FFI::Pointer::NULL, FFI::Pointer::NULL ) return true if result != FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new("ReplaceFile(#{target}, #{source})") end |
.set_attributes(path, flags) ⇒ Object
178 179 180 181 182 183 |
# File 'lib/puppet/util/windows/file.rb', line 178 def set_attributes(path, flags) success = SetFileAttributesW(wide_string(path), flags) != FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to set file attributes")) if !success success end |
.stat(file_name) ⇒ Object
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/puppet/util/windows/file.rb', line 371 def stat(file_name) file_name = file_name.to_s # accommodate PathName or String stat = File.stat(file_name) singleton_class = class << stat; self; end target_path = file_name if symlink?(file_name) target_path = readlink(file_name) link_ftype = File.stat(target_path).ftype # sigh, monkey patch instance method for instance, and close over link_ftype singleton_class.send(:define_method, :ftype) do link_ftype end end singleton_class.send(:define_method, :mode) do Puppet::Util::Windows::Security.get_mode(target_path) end stat end |
.symlink(target, symlink) ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/puppet/util/windows/file.rb', line 104 def symlink(target, symlink) flags = File.directory?(target) ? 0x1 : 0x0 result = CreateSymbolicLinkW(wide_string(symlink.to_s), wide_string(target.to_s), flags) return true if result != FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new( "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})") end |
.symlink?(file_name) ⇒ Boolean
288 289 290 291 |
# File 'lib/puppet/util/windows/file.rb', line 288 def symlink?(file_name) # Puppet currently only handles mount point and symlink reparse points, ignores others reparse_point?(file_name) && symlink_reparse_point?(file_name) end |