pdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|