Module: Puppet::Util::Windows::File

Extended by:
FFI::Library, String
Defined in:
lib/puppet/util/windows/file.rb

Defined Under Namespace

Classes: REPARSE_DATA_BUFFER

Constant Summary collapse

FILE_ATTRIBUTE_READONLY =
0x00000001
SYNCHRONIZE =
0x100000
STANDARD_RIGHTS_REQUIRED =
0xf0000
STANDARD_RIGHTS_READ =
0x20000
STANDARD_RIGHTS_WRITE =
0x20000
STANDARD_RIGHTS_EXECUTE =
0x20000
STANDARD_RIGHTS_ALL =
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
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
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

Class Method Summary collapse

Methods included from FFI::Library

attach_function_private

Methods included from String

wide_string

Class Method Details

.add_attributes(path, flags) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/puppet/util/windows/file.rb', line 101

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



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/puppet/util/windows/file.rb', line 129

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



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/puppet/util/windows/file.rb', line 154

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

.get_attributes(file_name) ⇒ Object



94
95
96
97
98
# File 'lib/puppet/util/windows/file.rb', line 94

def get_attributes(file_name)
  result = GetFileAttributesW(wide_string(file_name.to_s))
  return result unless result == INVALID_FILE_ATTRIBUTES
  raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})")
end

.get_reparse_point_data(handle, &block) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/puppet/util/windows/file.rb', line 143

def self.get_reparse_point_data(handle, &block)
  # must be multiple of 1024, min 10240
  FFI::MemoryPointer.new(REPARSE_DATA_BUFFER.size) do |reparse_data_buffer_ptr|
    device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
    yield REPARSE_DATA_BUFFER.new(reparse_data_buffer_ptr)
  end

  # underlying struct MemoryPointer has been cleaned up by this point, nothing to return
  nil
end

.lstat(file_name) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/puppet/util/windows/file.rb', line 254

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



71
72
73
74
75
76
77
78
79
# File 'lib/puppet/util/windows/file.rb', line 71

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


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/puppet/util/windows/file.rb', line 202

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


220
221
222
223
224
225
226
227
# File 'lib/puppet/util/windows/file.rb', line 220

def readlink(link_name)
  link = nil
  open_symlink(link_name) do |handle|
    link = resolve_symlink(handle)
  end

  link
end

.remove_attributes(path, flags) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/puppet/util/windows/file.rb', line 110

def remove_attributes(path, flags)
  oldattrs = get_attributes(path)

  if (oldattrs & ~flags) != oldattrs
    set_attributes(path, oldattrs & ~flags)
  end
end

.replace_file(target, source) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/puppet/util/windows/file.rb', line 51

def replace_file(target, source)
  target_encoded = wide_string(target.to_s)
  source_encoded = wide_string(source.to_s)

  flags = 0x1
  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



119
120
121
122
123
124
# File 'lib/puppet/util/windows/file.rb', line 119

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



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/puppet/util/windows/file.rb', line 230

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


82
83
84
85
86
87
88
89
# File 'lib/puppet/util/windows/file.rb', line 82

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

Returns:

  • (Boolean)


181
182
183
184
185
186
187
188
189
# File 'lib/puppet/util/windows/file.rb', line 181

def symlink?(file_name)
  begin
    attributes = get_attributes(file_name)
    (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
  rescue
    # raised INVALID_FILE_ATTRIBUTES is equivalent to file not found
    false
  end
end