pdk 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +3 -9
- data/exe/pdk +1 -1
- data/lib/pdk.rb +5 -4
- data/lib/pdk/cli.rb +62 -59
- data/lib/pdk/cli/errors.rb +1 -1
- data/lib/pdk/cli/exec.rb +154 -29
- data/lib/pdk/cli/input.rb +2 -2
- data/lib/pdk/cli/new.rb +12 -27
- data/lib/pdk/cli/new/class.rb +28 -41
- data/lib/pdk/cli/new/module.rb +30 -41
- data/lib/pdk/cli/test.rb +9 -20
- data/lib/pdk/cli/test/unit.rb +38 -0
- data/lib/pdk/cli/util/option_normalizer.rb +45 -19
- data/lib/pdk/cli/util/option_validator.rb +24 -20
- data/lib/pdk/cli/validate.rb +65 -65
- data/lib/pdk/generate.rb +5 -0
- data/lib/pdk/generators/module.rb +37 -33
- data/lib/pdk/generators/puppet_class.rb +1 -1
- data/lib/pdk/generators/puppet_object.rb +19 -20
- data/lib/pdk/logger.rb +1 -1
- data/lib/pdk/module/metadata.rb +35 -18
- data/lib/pdk/module/templatedir.rb +40 -33
- data/lib/pdk/report.rb +76 -19
- data/lib/pdk/report/event.rb +276 -0
- data/lib/pdk/template_file.rb +8 -6
- data/lib/pdk/tests/unit.rb +8 -3
- data/lib/pdk/util.rb +65 -0
- data/lib/pdk/util/bundler.rb +167 -0
- data/lib/pdk/util/version.rb +34 -0
- data/lib/pdk/validate.rb +3 -4
- data/lib/pdk/validators/base_validator.rb +60 -4
- data/lib/pdk/validators/metadata.rb +29 -0
- data/lib/pdk/validators/puppet/puppet_lint.rb +47 -0
- data/lib/pdk/validators/puppet/puppet_parser.rb +34 -0
- data/lib/pdk/validators/puppet_validator.rb +30 -0
- data/lib/pdk/validators/ruby/rubocop.rb +59 -0
- data/lib/pdk/validators/ruby_validator.rb +29 -0
- data/lib/pdk/version.rb +1 -1
- data/lib/puppet/util/windows.rb +14 -0
- data/lib/puppet/util/windows/api_types.rb +278 -0
- data/lib/puppet/util/windows/file.rb +488 -0
- data/lib/puppet/util/windows/string.rb +16 -0
- data/locales/de/pdk.po +263 -78
- data/locales/pdk.pot +224 -65
- metadata +60 -8
- data/lib/pdk/cli/tests/unit.rb +0 -52
- data/lib/pdk/validators/puppet_lint.rb +0 -17
- data/lib/pdk/validators/puppet_parser.rb +0 -17
- data/lib/pdk/validators/ruby_lint.rb +0 -17
@@ -0,0 +1,488 @@
|
|
1
|
+
require 'puppet/util/windows'
|
2
|
+
|
3
|
+
module Puppet::Util::Windows::File
|
4
|
+
require 'ffi'
|
5
|
+
extend FFI::Library
|
6
|
+
extend Puppet::Util::Windows::String
|
7
|
+
|
8
|
+
FILE_ATTRIBUTE_READONLY = 0x00000001
|
9
|
+
|
10
|
+
SYNCHRONIZE = 0x100000
|
11
|
+
STANDARD_RIGHTS_REQUIRED = 0xf0000
|
12
|
+
STANDARD_RIGHTS_READ = 0x20000
|
13
|
+
STANDARD_RIGHTS_WRITE = 0x20000
|
14
|
+
STANDARD_RIGHTS_EXECUTE = 0x20000
|
15
|
+
STANDARD_RIGHTS_ALL = 0x1F0000
|
16
|
+
SPECIFIC_RIGHTS_ALL = 0xFFFF
|
17
|
+
|
18
|
+
FILE_READ_DATA = 1
|
19
|
+
FILE_WRITE_DATA = 2
|
20
|
+
FILE_APPEND_DATA = 4
|
21
|
+
FILE_READ_EA = 8
|
22
|
+
FILE_WRITE_EA = 16
|
23
|
+
FILE_EXECUTE = 32
|
24
|
+
FILE_DELETE_CHILD = 64
|
25
|
+
FILE_READ_ATTRIBUTES = 128
|
26
|
+
FILE_WRITE_ATTRIBUTES = 256
|
27
|
+
|
28
|
+
FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
|
29
|
+
|
30
|
+
FILE_GENERIC_READ =
|
31
|
+
STANDARD_RIGHTS_READ |
|
32
|
+
FILE_READ_DATA |
|
33
|
+
FILE_READ_ATTRIBUTES |
|
34
|
+
FILE_READ_EA |
|
35
|
+
SYNCHRONIZE
|
36
|
+
|
37
|
+
FILE_GENERIC_WRITE =
|
38
|
+
STANDARD_RIGHTS_WRITE |
|
39
|
+
FILE_WRITE_DATA |
|
40
|
+
FILE_WRITE_ATTRIBUTES |
|
41
|
+
FILE_WRITE_EA |
|
42
|
+
FILE_APPEND_DATA |
|
43
|
+
SYNCHRONIZE
|
44
|
+
|
45
|
+
FILE_GENERIC_EXECUTE =
|
46
|
+
STANDARD_RIGHTS_EXECUTE |
|
47
|
+
FILE_READ_ATTRIBUTES |
|
48
|
+
FILE_EXECUTE |
|
49
|
+
SYNCHRONIZE
|
50
|
+
|
51
|
+
REPLACEFILE_WRITE_THROUGH = 0x1
|
52
|
+
REPLACEFILE_IGNORE_MERGE_ERRORS = 0x2
|
53
|
+
REPLACEFILE_IGNORE_ACL_ERRORS = 0x3
|
54
|
+
|
55
|
+
def replace_file(target, source)
|
56
|
+
target_encoded = wide_string(target.to_s)
|
57
|
+
source_encoded = wide_string(source.to_s)
|
58
|
+
|
59
|
+
flags = REPLACEFILE_IGNORE_MERGE_ERRORS
|
60
|
+
backup_file = nil
|
61
|
+
result = ReplaceFileW(
|
62
|
+
target_encoded,
|
63
|
+
source_encoded,
|
64
|
+
backup_file,
|
65
|
+
flags,
|
66
|
+
FFI::Pointer::NULL,
|
67
|
+
FFI::Pointer::NULL
|
68
|
+
)
|
69
|
+
|
70
|
+
return true if result != FFI::WIN32_FALSE
|
71
|
+
raise Puppet::Util::Windows::Error.new("ReplaceFile(#{target}, #{source})")
|
72
|
+
end
|
73
|
+
module_function :replace_file
|
74
|
+
|
75
|
+
def move_file_ex(source, target, flags = 0)
|
76
|
+
result = MoveFileExW(wide_string(source.to_s),
|
77
|
+
wide_string(target.to_s),
|
78
|
+
flags)
|
79
|
+
|
80
|
+
return true if result != FFI::WIN32_FALSE
|
81
|
+
raise Puppet::Util::Windows::Error.
|
82
|
+
new("MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})")
|
83
|
+
end
|
84
|
+
module_function :move_file_ex
|
85
|
+
|
86
|
+
def symlink(target, symlink)
|
87
|
+
flags = File.directory?(target) ? 0x1 : 0x0
|
88
|
+
result = CreateSymbolicLinkW(wide_string(symlink.to_s),
|
89
|
+
wide_string(target.to_s), flags)
|
90
|
+
return true if result != FFI::WIN32_FALSE
|
91
|
+
raise Puppet::Util::Windows::Error.new(
|
92
|
+
"CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})")
|
93
|
+
end
|
94
|
+
module_function :symlink
|
95
|
+
|
96
|
+
|
97
|
+
def exist?(path)
|
98
|
+
path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
|
99
|
+
path = path.to_s # support String and Pathname
|
100
|
+
|
101
|
+
seen_paths = []
|
102
|
+
# follow up to 64 symlinks before giving up
|
103
|
+
0.upto(64) do |depth|
|
104
|
+
# return false if this path has been seen before. This is protection against circular symlinks
|
105
|
+
return false if seen_paths.include?(path.downcase)
|
106
|
+
|
107
|
+
result = get_attributes(path,false)
|
108
|
+
|
109
|
+
# return false for path not found
|
110
|
+
return false if result == INVALID_FILE_ATTRIBUTES
|
111
|
+
|
112
|
+
# return true if path exists and it's not a symlink
|
113
|
+
# Other file attributes are ignored. https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
|
114
|
+
return true if (result & FILE_ATTRIBUTE_REPARSE_POINT) != FILE_ATTRIBUTE_REPARSE_POINT
|
115
|
+
|
116
|
+
# walk the symlink and try again...
|
117
|
+
seen_paths << path.downcase
|
118
|
+
path = readlink(path)
|
119
|
+
end
|
120
|
+
|
121
|
+
false
|
122
|
+
end
|
123
|
+
module_function :exist?
|
124
|
+
|
125
|
+
|
126
|
+
INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF #define INVALID_FILE_ATTRIBUTES (DWORD (-1))
|
127
|
+
|
128
|
+
def get_attributes(file_name, raise_on_invalid = true)
|
129
|
+
result = GetFileAttributesW(wide_string(file_name.to_s))
|
130
|
+
if raise_on_invalid && result == INVALID_FILE_ATTRIBUTES
|
131
|
+
raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})")
|
132
|
+
end
|
133
|
+
|
134
|
+
result
|
135
|
+
end
|
136
|
+
module_function :get_attributes
|
137
|
+
|
138
|
+
def add_attributes(path, flags)
|
139
|
+
oldattrs = get_attributes(path)
|
140
|
+
|
141
|
+
if (oldattrs | flags) != oldattrs
|
142
|
+
set_attributes(path, oldattrs | flags)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
module_function :add_attributes
|
146
|
+
|
147
|
+
def remove_attributes(path, flags)
|
148
|
+
oldattrs = get_attributes(path)
|
149
|
+
|
150
|
+
if (oldattrs & ~flags) != oldattrs
|
151
|
+
set_attributes(path, oldattrs & ~flags)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
module_function :remove_attributes
|
155
|
+
|
156
|
+
def set_attributes(path, flags)
|
157
|
+
success = SetFileAttributesW(wide_string(path), flags) != FFI::WIN32_FALSE
|
158
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to set file attributes")) if !success
|
159
|
+
|
160
|
+
success
|
161
|
+
end
|
162
|
+
module_function :set_attributes
|
163
|
+
|
164
|
+
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
|
165
|
+
INVALID_HANDLE_VALUE = FFI::Pointer.new(-1).address
|
166
|
+
def self.create_file(file_name, desired_access, share_mode, security_attributes,
|
167
|
+
creation_disposition, flags_and_attributes, template_file_handle)
|
168
|
+
|
169
|
+
result = CreateFileW(wide_string(file_name.to_s),
|
170
|
+
desired_access, share_mode, security_attributes, creation_disposition,
|
171
|
+
flags_and_attributes, template_file_handle)
|
172
|
+
|
173
|
+
return result unless result == INVALID_HANDLE_VALUE
|
174
|
+
raise Puppet::Util::Windows::Error.new(
|
175
|
+
"CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_mode.to_s(8)}, " +
|
176
|
+
"#{security_attributes}, #{creation_disposition.to_s(8)}, " +
|
177
|
+
"#{flags_and_attributes.to_s(8)}, #{template_file_handle})")
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.get_reparse_point_data(handle, &block)
|
181
|
+
# must be multiple of 1024, min 10240
|
182
|
+
FFI::MemoryPointer.new(REPARSE_DATA_BUFFER.size) do |reparse_data_buffer_ptr|
|
183
|
+
device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
|
184
|
+
yield REPARSE_DATA_BUFFER.new(reparse_data_buffer_ptr)
|
185
|
+
end
|
186
|
+
|
187
|
+
# underlying struct MemoryPointer has been cleaned up by this point, nothing to return
|
188
|
+
nil
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil)
|
192
|
+
if out_buffer.nil?
|
193
|
+
raise Puppet::Util::Windows::Error.new(_("out_buffer is required"))
|
194
|
+
end
|
195
|
+
|
196
|
+
FFI::MemoryPointer.new(:dword, 1) do |bytes_returned_ptr|
|
197
|
+
result = DeviceIoControl(
|
198
|
+
handle,
|
199
|
+
io_control_code,
|
200
|
+
in_buffer, in_buffer.nil? ? 0 : in_buffer.size,
|
201
|
+
out_buffer, out_buffer.size,
|
202
|
+
bytes_returned_ptr,
|
203
|
+
nil
|
204
|
+
)
|
205
|
+
|
206
|
+
if result == FFI::WIN32_FALSE
|
207
|
+
raise Puppet::Util::Windows::Error.new(
|
208
|
+
"DeviceIoControl(#{handle}, #{io_control_code}, " +
|
209
|
+
"#{in_buffer}, #{in_buffer ? in_buffer.size : ''}, " +
|
210
|
+
"#{out_buffer}, #{out_buffer ? out_buffer.size : ''}")
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
out_buffer
|
215
|
+
end
|
216
|
+
|
217
|
+
FILE_ATTRIBUTE_REPARSE_POINT = 0x400
|
218
|
+
def symlink?(file_name)
|
219
|
+
attributes = get_attributes(file_name, false)
|
220
|
+
|
221
|
+
return false if (attributes == INVALID_FILE_ATTRIBUTES)
|
222
|
+
(attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
|
223
|
+
end
|
224
|
+
module_function :symlink?
|
225
|
+
|
226
|
+
GENERIC_READ = 0x80000000
|
227
|
+
GENERIC_WRITE = 0x40000000
|
228
|
+
GENERIC_EXECUTE = 0x20000000
|
229
|
+
GENERIC_ALL = 0x10000000
|
230
|
+
FILE_SHARE_READ = 1
|
231
|
+
FILE_SHARE_WRITE = 2
|
232
|
+
OPEN_EXISTING = 3
|
233
|
+
FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
|
234
|
+
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
|
235
|
+
|
236
|
+
def self.open_symlink(link_name)
|
237
|
+
begin
|
238
|
+
yield handle = create_file(
|
239
|
+
link_name,
|
240
|
+
GENERIC_READ,
|
241
|
+
FILE_SHARE_READ,
|
242
|
+
nil, # security_attributes
|
243
|
+
OPEN_EXISTING,
|
244
|
+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
245
|
+
0) # template_file
|
246
|
+
ensure
|
247
|
+
FFI::WIN32.CloseHandle(handle) if handle
|
248
|
+
end
|
249
|
+
|
250
|
+
# handle has had CloseHandle called against it, so nothing to return
|
251
|
+
nil
|
252
|
+
end
|
253
|
+
|
254
|
+
def readlink(link_name)
|
255
|
+
link = nil
|
256
|
+
open_symlink(link_name) do |handle|
|
257
|
+
link = resolve_symlink(handle)
|
258
|
+
end
|
259
|
+
|
260
|
+
link
|
261
|
+
end
|
262
|
+
module_function :readlink
|
263
|
+
|
264
|
+
ERROR_FILE_NOT_FOUND = 2
|
265
|
+
ERROR_PATH_NOT_FOUND = 3
|
266
|
+
|
267
|
+
def get_long_pathname(path)
|
268
|
+
converted = ''
|
269
|
+
FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
|
270
|
+
# includes terminating NULL
|
271
|
+
buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0)
|
272
|
+
FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
|
273
|
+
if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
|
274
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to call GetLongPathName"))
|
275
|
+
end
|
276
|
+
|
277
|
+
converted = converted_ptr.read_wide_string(buffer_size - 1)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
converted
|
282
|
+
end
|
283
|
+
module_function :get_long_pathname
|
284
|
+
|
285
|
+
def get_short_pathname(path)
|
286
|
+
converted = ''
|
287
|
+
FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
|
288
|
+
# includes terminating NULL
|
289
|
+
buffer_size = GetShortPathNameW(path_ptr, FFI::Pointer::NULL, 0)
|
290
|
+
FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
|
291
|
+
if GetShortPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
|
292
|
+
raise Puppet::Util::Windows::Error.new("Failed to call GetShortPathName")
|
293
|
+
end
|
294
|
+
|
295
|
+
converted = converted_ptr.read_wide_string(buffer_size - 1)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
converted
|
300
|
+
end
|
301
|
+
module_function :get_short_pathname
|
302
|
+
|
303
|
+
def stat(file_name)
|
304
|
+
file_name = file_name.to_s # accommodate PathName or String
|
305
|
+
stat = File.stat(file_name)
|
306
|
+
singleton_class = class << stat; self; end
|
307
|
+
target_path = file_name
|
308
|
+
|
309
|
+
if symlink?(file_name)
|
310
|
+
target_path = readlink(file_name)
|
311
|
+
link_ftype = File.stat(target_path).ftype
|
312
|
+
|
313
|
+
# sigh, monkey patch instance method for instance, and close over link_ftype
|
314
|
+
singleton_class.send(:define_method, :ftype) do
|
315
|
+
link_ftype
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
singleton_class.send(:define_method, :mode) do
|
320
|
+
Puppet::Util::Windows::Security.get_mode(target_path)
|
321
|
+
end
|
322
|
+
|
323
|
+
stat
|
324
|
+
end
|
325
|
+
module_function :stat
|
326
|
+
|
327
|
+
def lstat(file_name)
|
328
|
+
file_name = file_name.to_s # accommodate PathName or String
|
329
|
+
# monkey'ing around!
|
330
|
+
stat = File.lstat(file_name)
|
331
|
+
|
332
|
+
singleton_class = class << stat; self; end
|
333
|
+
singleton_class.send(:define_method, :mode) do
|
334
|
+
Puppet::Util::Windows::Security.get_mode(file_name)
|
335
|
+
end
|
336
|
+
|
337
|
+
if symlink?(file_name)
|
338
|
+
def stat.ftype
|
339
|
+
"link"
|
340
|
+
end
|
341
|
+
end
|
342
|
+
stat
|
343
|
+
end
|
344
|
+
module_function :lstat
|
345
|
+
|
346
|
+
private
|
347
|
+
|
348
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx
|
349
|
+
FSCTL_GET_REPARSE_POINT = 0x900a8
|
350
|
+
|
351
|
+
def self.resolve_symlink(handle)
|
352
|
+
path = nil
|
353
|
+
get_reparse_point_data(handle) do |reparse_data|
|
354
|
+
offset = reparse_data[:PrintNameOffset]
|
355
|
+
length = reparse_data[:PrintNameLength]
|
356
|
+
|
357
|
+
ptr = reparse_data.pointer + reparse_data.offset_of(:PathBuffer) + offset
|
358
|
+
path = ptr.read_wide_string(length / 2) # length is bytes, need UTF-16 wchars
|
359
|
+
end
|
360
|
+
|
361
|
+
path
|
362
|
+
end
|
363
|
+
|
364
|
+
ffi_convention :stdcall
|
365
|
+
|
366
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365512(v=vs.85).aspx
|
367
|
+
# BOOL WINAPI ReplaceFile(
|
368
|
+
# _In_ LPCTSTR lpReplacedFileName,
|
369
|
+
# _In_ LPCTSTR lpReplacementFileName,
|
370
|
+
# _In_opt_ LPCTSTR lpBackupFileName,
|
371
|
+
# _In_ DWORD dwReplaceFlags - 0x1 REPLACEFILE_WRITE_THROUGH,
|
372
|
+
# 0x2 REPLACEFILE_IGNORE_MERGE_ERRORS,
|
373
|
+
# 0x4 REPLACEFILE_IGNORE_ACL_ERRORS
|
374
|
+
# _Reserved_ LPVOID lpExclude,
|
375
|
+
# _Reserved_ LPVOID lpReserved
|
376
|
+
# );
|
377
|
+
ffi_lib :kernel32
|
378
|
+
attach_function_private :ReplaceFileW,
|
379
|
+
[:lpcwstr, :lpcwstr, :lpcwstr, :dword, :lpvoid, :lpvoid], :win32_bool
|
380
|
+
|
381
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
|
382
|
+
# BOOL WINAPI MoveFileEx(
|
383
|
+
# _In_ LPCTSTR lpExistingFileName,
|
384
|
+
# _In_opt_ LPCTSTR lpNewFileName,
|
385
|
+
# _In_ DWORD dwFlags
|
386
|
+
# );
|
387
|
+
ffi_lib :kernel32
|
388
|
+
attach_function_private :MoveFileExW,
|
389
|
+
[:lpcwstr, :lpcwstr, :dword], :win32_bool
|
390
|
+
|
391
|
+
# BOOLEAN WINAPI CreateSymbolicLink(
|
392
|
+
# _In_ LPTSTR lpSymlinkFileName, - symbolic link to be created
|
393
|
+
# _In_ LPTSTR lpTargetFileName, - name of target for symbolic link
|
394
|
+
# _In_ DWORD dwFlags - 0x0 target is a file, 0x1 target is a directory
|
395
|
+
# );
|
396
|
+
# rescue on Windows < 6.0 so that code doesn't explode
|
397
|
+
begin
|
398
|
+
ffi_lib :kernel32
|
399
|
+
attach_function_private :CreateSymbolicLinkW,
|
400
|
+
[:lpwstr, :lpwstr, :dword], :boolean
|
401
|
+
rescue LoadError
|
402
|
+
end
|
403
|
+
|
404
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
|
405
|
+
# DWORD WINAPI GetFileAttributes(
|
406
|
+
# _In_ LPCTSTR lpFileName
|
407
|
+
# );
|
408
|
+
ffi_lib :kernel32
|
409
|
+
attach_function_private :GetFileAttributesW,
|
410
|
+
[:lpcwstr], :dword
|
411
|
+
|
412
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365535(v=vs.85).aspx
|
413
|
+
# BOOL WINAPI SetFileAttributes(
|
414
|
+
# _In_ LPCTSTR lpFileName,
|
415
|
+
# _In_ DWORD dwFileAttributes
|
416
|
+
# );
|
417
|
+
ffi_lib :kernel32
|
418
|
+
attach_function_private :SetFileAttributesW,
|
419
|
+
[:lpcwstr, :dword], :win32_bool
|
420
|
+
|
421
|
+
# HANDLE WINAPI CreateFile(
|
422
|
+
# _In_ LPCTSTR lpFileName,
|
423
|
+
# _In_ DWORD dwDesiredAccess,
|
424
|
+
# _In_ DWORD dwShareMode,
|
425
|
+
# _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
426
|
+
# _In_ DWORD dwCreationDisposition,
|
427
|
+
# _In_ DWORD dwFlagsAndAttributes,
|
428
|
+
# _In_opt_ HANDLE hTemplateFile
|
429
|
+
# );
|
430
|
+
ffi_lib :kernel32
|
431
|
+
attach_function_private :CreateFileW,
|
432
|
+
[:lpcwstr, :dword, :dword, :pointer, :dword, :dword, :handle], :handle
|
433
|
+
|
434
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx
|
435
|
+
# BOOL WINAPI DeviceIoControl(
|
436
|
+
# _In_ HANDLE hDevice,
|
437
|
+
# _In_ DWORD dwIoControlCode,
|
438
|
+
# _In_opt_ LPVOID lpInBuffer,
|
439
|
+
# _In_ DWORD nInBufferSize,
|
440
|
+
# _Out_opt_ LPVOID lpOutBuffer,
|
441
|
+
# _In_ DWORD nOutBufferSize,
|
442
|
+
# _Out_opt_ LPDWORD lpBytesReturned,
|
443
|
+
# _Inout_opt_ LPOVERLAPPED lpOverlapped
|
444
|
+
# );
|
445
|
+
ffi_lib :kernel32
|
446
|
+
attach_function_private :DeviceIoControl,
|
447
|
+
[:handle, :dword, :lpvoid, :dword, :lpvoid, :dword, :lpdword, :pointer], :win32_bool
|
448
|
+
|
449
|
+
MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384
|
450
|
+
|
451
|
+
# REPARSE_DATA_BUFFER
|
452
|
+
# https://msdn.microsoft.com/en-us/library/cc232006.aspx
|
453
|
+
# https://msdn.microsoft.com/en-us/library/windows/hardware/ff552012(v=vs.85).aspx
|
454
|
+
# struct is always MAXIMUM_REPARSE_DATA_BUFFER_SIZE bytes
|
455
|
+
class REPARSE_DATA_BUFFER < FFI::Struct
|
456
|
+
layout :ReparseTag, :win32_ulong,
|
457
|
+
:ReparseDataLength, :ushort,
|
458
|
+
:Reserved, :ushort,
|
459
|
+
:SubstituteNameOffset, :ushort,
|
460
|
+
:SubstituteNameLength, :ushort,
|
461
|
+
:PrintNameOffset, :ushort,
|
462
|
+
:PrintNameLength, :ushort,
|
463
|
+
:Flags, :win32_ulong,
|
464
|
+
# max less above fields dword / uint 4 bytes, ushort 2 bytes
|
465
|
+
# technically a WCHAR buffer, but we care about size in bytes here
|
466
|
+
:PathBuffer, [:byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 20]
|
467
|
+
end
|
468
|
+
|
469
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx
|
470
|
+
# DWORD WINAPI GetLongPathName(
|
471
|
+
# _In_ LPCTSTR lpszShortPath,
|
472
|
+
# _Out_ LPTSTR lpszLongPath,
|
473
|
+
# _In_ DWORD cchBuffer
|
474
|
+
# );
|
475
|
+
ffi_lib :kernel32
|
476
|
+
attach_function_private :GetLongPathNameW,
|
477
|
+
[:lpcwstr, :lpwstr, :dword], :dword
|
478
|
+
|
479
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx
|
480
|
+
# DWORD WINAPI GetShortPathName(
|
481
|
+
# _In_ LPCTSTR lpszLongPath,
|
482
|
+
# _Out_ LPTSTR lpszShortPath,
|
483
|
+
# _In_ DWORD cchBuffer
|
484
|
+
# );
|
485
|
+
ffi_lib :kernel32
|
486
|
+
attach_function_private :GetShortPathNameW,
|
487
|
+
[:lpcwstr, :lpwstr, :dword], :dword
|
488
|
+
end
|