win32-dir 0.4.7 → 0.7.2
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 +5 -5
- data/lib/win32-dir.rb +1 -0
- data/lib/win32/dir.rb +185 -173
- data/lib/win32/dir/constants.rb +6 -3
- data/lib/win32/dir/functions.rb +17 -17
- data/lib/win32/dir/structs.rb +1 -1
- data/lib/win32/dir/version.rb +6 -0
- metadata +13 -51
- data/CHANGES +0 -98
- data/MANIFEST +0 -8
- data/README +0 -273
- data/Rakefile +0 -38
- data/examples/dir_example.rb +0 -23
- data/test/test_win32_dir.rb +0 -452
- data/win32-dir.gemspec +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2a8115d4e340523af631d3637a12c7e69836ebf25557b68d7ff6cbe57c04af7b
|
4
|
+
data.tar.gz: 68d05c5b0298b4deaeba910386066a2f92fbff050606b3b3af8e27c6a09d786c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a61c6fc6ce9259d40d1922a095b760578da70a31e526aee950e91eef74db83b7ee0c3c1716b50574fd251f462c2fa36aa2dd1233d1bc0e5234972a230e07381
|
7
|
+
data.tar.gz: 6007e11c210cc84bed879c0d025f4c94238da5dc96bcf28dadd1a3cae908a48e8eb01823a2943e15bd701e793a9e48402bd5546239b24dab381f147e8eca7fe2
|
data/lib/win32-dir.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "win32/dir"
|
data/lib/win32/dir.rb
CHANGED
@@ -1,92 +1,96 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative "dir/constants"
|
2
|
+
require_relative "dir/functions"
|
3
|
+
require_relative "dir/structs"
|
4
4
|
|
5
5
|
class Dir
|
6
6
|
include Dir::Structs
|
7
7
|
include Dir::Constants
|
8
8
|
extend Dir::Functions
|
9
9
|
|
10
|
-
# The version of the win32-dir library.
|
11
|
-
VERSION = '0.4.7'
|
12
|
-
|
13
10
|
# CSIDL constants
|
14
11
|
csidl = Hash[
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
12
|
+
"DESKTOP", 0x0000,
|
13
|
+
"INTERNET", 0x0001,
|
14
|
+
"PROGRAMS", 0x0002,
|
15
|
+
"CONTROLS", 0x0003,
|
16
|
+
"PRINTERS", 0x0004,
|
17
|
+
"PERSONAL", 0x0005,
|
18
|
+
"FAVORITES", 0x0006,
|
19
|
+
"STARTUP", 0x0007,
|
20
|
+
"RECENT", 0x0008,
|
21
|
+
"SENDTO", 0x0009,
|
22
|
+
"BITBUCKET", 0x000a,
|
23
|
+
"STARTMENU", 0x000b,
|
24
|
+
"MYDOCUMENTS", 0x000c,
|
25
|
+
"MYMUSIC", 0x000d,
|
26
|
+
"MYVIDEO", 0x000e,
|
27
|
+
"DESKTOPDIRECTORY", 0x0010,
|
28
|
+
"DRIVES", 0x0011,
|
29
|
+
"NETWORK", 0x0012,
|
30
|
+
"NETHOOD", 0x0013,
|
31
|
+
"FONTS", 0x0014,
|
32
|
+
"TEMPLATES", 0x0015,
|
33
|
+
"COMMON_STARTMENU", 0x0016,
|
34
|
+
"COMMON_PROGRAMS", 0X0017,
|
35
|
+
"COMMON_STARTUP", 0x0018,
|
36
|
+
"COMMON_FAVORITES", 0x001f,
|
37
|
+
"COMMON_DESKTOPDIRECTORY", 0x0019,
|
38
|
+
"APPDATA", 0x001a,
|
39
|
+
"PRINTHOOD", 0x001b,
|
40
|
+
"LOCAL_APPDATA", 0x001c,
|
41
|
+
"ALTSTARTUP", 0x001d,
|
42
|
+
"COMMON_ALTSTARTUP", 0x001e,
|
43
|
+
"INTERNET_CACHE", 0x0020,
|
44
|
+
"COOKIES", 0x0021,
|
45
|
+
"HISTORY", 0x0022,
|
46
|
+
"COMMON_APPDATA", 0x0023,
|
47
|
+
"WINDOWS", 0x0024,
|
48
|
+
"SYSTEM", 0x0025,
|
49
|
+
"PROGRAM_FILES", 0x0026,
|
50
|
+
"MYPICTURES", 0x0027,
|
51
|
+
"PROFILE", 0x0028,
|
52
|
+
"SYSTEMX86", 0x0029,
|
53
|
+
"PROGRAM_FILESX86", 0x002a,
|
54
|
+
"PROGRAM_FILES_COMMON", 0x002b,
|
55
|
+
"PROGRAM_FILES_COMMONX86", 0x002c,
|
56
|
+
"COMMON_TEMPLATES", 0x002d,
|
57
|
+
"COMMON_DOCUMENTS", 0x002e,
|
58
|
+
"CONNECTIONS", 0x0031,
|
59
|
+
"COMMON_MUSIC", 0x0035,
|
60
|
+
"COMMON_PICTURES", 0x0036,
|
61
|
+
"COMMON_VIDEO", 0x0037,
|
62
|
+
"RESOURCES", 0x0038,
|
63
|
+
"RESOURCES_LOCALIZED", 0x0039,
|
64
|
+
"COMMON_OEM_LINKS", 0x003a,
|
65
|
+
"CDBURN_AREA", 0x003b,
|
66
|
+
"COMMON_ADMINTOOLS", 0x002f,
|
67
|
+
"ADMINTOOLS", 0x0030
|
71
68
|
]
|
72
69
|
|
73
70
|
# Dynamically set each of the CSIDL constants
|
74
|
-
csidl.each
|
71
|
+
csidl.each do |key, value|
|
75
72
|
buf = 0.chr * 1024
|
76
73
|
path = nil
|
77
|
-
buf.encode!(
|
74
|
+
buf.encode!("UTF-16LE")
|
78
75
|
|
79
76
|
if SHGetFolderPathW(0, value, 0, 0, buf) == 0 # Current path
|
80
77
|
path = buf.strip
|
81
78
|
elsif SHGetFolderPathW(0, value, 0, 1, buf) == 0 # Default path
|
82
79
|
path = buf.strip
|
83
80
|
else
|
84
|
-
ptr = FFI::MemoryPointer.new(:
|
81
|
+
ptr = FFI::MemoryPointer.new(:uint64)
|
85
82
|
info = SHFILEINFO.new
|
86
83
|
flags = SHGFI_DISPLAYNAME | SHGFI_PIDL
|
87
84
|
|
88
85
|
if SHGetFolderLocation(0, value, 0, 0, ptr) == 0
|
89
|
-
|
86
|
+
# Use read_array_of_uint64 for compatibility with JRuby if necessary.
|
87
|
+
if ptr.respond_to?(:read_uint64)
|
88
|
+
res = SHGetFileInfo(ptr.read_uint64, 0, info, info.size, flags)
|
89
|
+
else
|
90
|
+
res = SHGetFileInfo(ptr.read_array_of_uint64(1).first, 0, info, info.size, flags)
|
91
|
+
end
|
92
|
+
|
93
|
+
if res != 0
|
90
94
|
path = info[:szDisplayName].to_s
|
91
95
|
path.force_encoding(Encoding.default_external)
|
92
96
|
end
|
@@ -96,9 +100,9 @@ class Dir
|
|
96
100
|
begin
|
97
101
|
Dir.const_set(key, path.encode(Encoding.default_external)) if path
|
98
102
|
rescue Encoding::UndefinedConversionError
|
99
|
-
Dir.const_set(key, path.encode(
|
103
|
+
Dir.const_set(key, path.encode("UTF-8")) if path
|
100
104
|
end
|
101
|
-
|
105
|
+
end
|
102
106
|
|
103
107
|
# Set Dir::MYDOCUMENTS to the same as Dir::PERSONAL if undefined
|
104
108
|
unless defined? MYDOCUMENTS
|
@@ -113,9 +117,9 @@ class Dir
|
|
113
117
|
#
|
114
118
|
def glob(glob_pattern, flags = 0, &block)
|
115
119
|
if glob_pattern.is_a?(Array)
|
116
|
-
temp = glob_pattern.map!{ |pattern|
|
120
|
+
temp = glob_pattern.map! { |pattern| string_check(pattern).tr("\\", "/") }
|
117
121
|
else
|
118
|
-
temp =
|
122
|
+
temp = string_check(glob_pattern).tr("\\", "/")
|
119
123
|
end
|
120
124
|
|
121
125
|
old_glob(temp, flags, &block)
|
@@ -127,12 +131,12 @@ class Dir
|
|
127
131
|
# backslashes in path names.
|
128
132
|
#
|
129
133
|
def [](*glob_patterns)
|
130
|
-
temp = glob_patterns.map!{ |pattern| "#{pattern}".tr("\\", "/") }
|
134
|
+
temp = glob_patterns.map! { |pattern| "#{pattern}".tr("\\", "/") }
|
131
135
|
old_ref(*temp)
|
132
136
|
end
|
133
137
|
|
134
138
|
# JRuby normalizes the path by default.
|
135
|
-
unless RUBY_PLATFORM ==
|
139
|
+
unless RUBY_PLATFORM == "java"
|
136
140
|
alias oldgetwd getwd
|
137
141
|
alias oldpwd pwd
|
138
142
|
|
@@ -175,7 +179,7 @@ class Dir
|
|
175
179
|
begin
|
176
180
|
path.encode(Encoding.default_external)
|
177
181
|
rescue Encoding::UndefinedConversionError
|
178
|
-
path.encode(
|
182
|
+
path.encode("UTF-8")
|
179
183
|
end
|
180
184
|
end
|
181
185
|
|
@@ -192,10 +196,10 @@ class Dir
|
|
192
196
|
# Dir.create_junction('C:/to', 'C:/from')
|
193
197
|
#
|
194
198
|
def self.create_junction(to, from)
|
195
|
-
to =
|
196
|
-
from =
|
199
|
+
to = string_check(to).wincode
|
200
|
+
from = string_check(from).wincode
|
197
201
|
|
198
|
-
from_path = (0.chr * 1024).encode(
|
202
|
+
from_path = (0.chr * 1024).encode("UTF-16LE")
|
199
203
|
|
200
204
|
length = GetFullPathNameW(from, from_path.size, from_path, nil)
|
201
205
|
|
@@ -205,7 +209,7 @@ class Dir
|
|
205
209
|
from_path.strip!
|
206
210
|
end
|
207
211
|
|
208
|
-
to_path = (0.chr * 1024).encode(
|
212
|
+
to_path = (0.chr * 1024).encode("UTF-16LE")
|
209
213
|
|
210
214
|
length = GetFullPathNameW(to, to_path.size, to_path, nil)
|
211
215
|
|
@@ -223,57 +227,55 @@ class Dir
|
|
223
227
|
end
|
224
228
|
end
|
225
229
|
|
230
|
+
# Generic read & write + open existing + reparse point & backup semantics
|
231
|
+
handle = CreateFileW(
|
232
|
+
to_path,
|
233
|
+
GENERIC_READ | GENERIC_WRITE,
|
234
|
+
0,
|
235
|
+
nil,
|
236
|
+
OPEN_EXISTING,
|
237
|
+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
238
|
+
0
|
239
|
+
)
|
240
|
+
|
241
|
+
if handle == INVALID_HANDLE_VALUE
|
242
|
+
raise SystemCallError.new("CreateFileW", FFI.errno)
|
243
|
+
end
|
244
|
+
|
245
|
+
target = "\\??\\".encode("UTF-16LE") + from_path
|
246
|
+
|
247
|
+
rdb = REPARSE_JDATA_BUFFER.new
|
248
|
+
rdb[:ReparseTag] = 2684354563 # IO_REPARSE_TAG_MOUNT_POINT
|
249
|
+
rdb[:ReparseDataLength] = target.bytesize + 12
|
250
|
+
rdb[:Reserved] = 0
|
251
|
+
rdb[:SubstituteNameOffset] = 0
|
252
|
+
rdb[:SubstituteNameLength] = target.bytesize
|
253
|
+
rdb[:PrintNameOffset] = target.bytesize + 2
|
254
|
+
rdb[:PrintNameLength] = 0
|
255
|
+
rdb[:PathBuffer] = target
|
256
|
+
|
257
|
+
bytes = FFI::MemoryPointer.new(:ulong)
|
258
|
+
|
226
259
|
begin
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
260
|
+
bool = DeviceIoControl(
|
261
|
+
handle,
|
262
|
+
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, 0),
|
263
|
+
rdb,
|
264
|
+
rdb[:ReparseDataLength] + rdb.header_size,
|
232
265
|
nil,
|
233
|
-
|
234
|
-
|
235
|
-
|
266
|
+
0,
|
267
|
+
bytes,
|
268
|
+
nil
|
236
269
|
)
|
237
270
|
|
238
|
-
|
239
|
-
raise SystemCallError.new("CreateFileW", FFI.errno)
|
240
|
-
end
|
271
|
+
error = FFI.errno
|
241
272
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
rdb[:ReparseTag] = 2684354563 # IO_REPARSE_TAG_MOUNT_POINT
|
246
|
-
rdb[:ReparseDataLength] = target.bytesize + 12
|
247
|
-
rdb[:Reserved] = 0
|
248
|
-
rdb[:SubstituteNameOffset] = 0
|
249
|
-
rdb[:SubstituteNameLength] = target.bytesize
|
250
|
-
rdb[:PrintNameOffset] = target.bytesize + 2
|
251
|
-
rdb[:PrintNameLength] = 0
|
252
|
-
rdb[:PathBuffer] = target
|
253
|
-
|
254
|
-
bytes = FFI::MemoryPointer.new(:ulong)
|
255
|
-
|
256
|
-
begin
|
257
|
-
bool = DeviceIoControl(
|
258
|
-
handle,
|
259
|
-
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, 0),
|
260
|
-
rdb,
|
261
|
-
rdb[:ReparseDataLength] + rdb.header_size,
|
262
|
-
nil,
|
263
|
-
0,
|
264
|
-
bytes,
|
265
|
-
nil
|
266
|
-
)
|
267
|
-
|
268
|
-
error = FFI.errno
|
269
|
-
|
270
|
-
unless bool
|
271
|
-
RemoveDirectoryW(to_path)
|
272
|
-
raise SystemCallError.new("DeviceIoControl", error)
|
273
|
-
end
|
274
|
-
ensure
|
275
|
-
CloseHandle(handle)
|
273
|
+
unless bool
|
274
|
+
RemoveDirectoryW(to_path)
|
275
|
+
raise SystemCallError.new("DeviceIoControl", error)
|
276
276
|
end
|
277
|
+
ensure
|
278
|
+
CloseHandle(handle)
|
277
279
|
end
|
278
280
|
|
279
281
|
self
|
@@ -290,11 +292,11 @@ class Dir
|
|
290
292
|
# Dir.read_junction("c:/to") # => "c:/from"
|
291
293
|
#
|
292
294
|
def self.read_junction(junction)
|
293
|
-
return false unless Dir.junction?(
|
295
|
+
return false unless Dir.junction?(junction)
|
294
296
|
|
295
|
-
junction =
|
297
|
+
junction = string_check(junction).wincode
|
296
298
|
|
297
|
-
junction_path = (0.chr * 1024).encode(
|
299
|
+
junction_path = (0.chr * 1024).encode("UTF-16LE")
|
298
300
|
|
299
301
|
length = GetFullPathNameW(junction, junction_path.size, junction_path, nil)
|
300
302
|
|
@@ -304,65 +306,64 @@ class Dir
|
|
304
306
|
junction_path.strip!
|
305
307
|
end
|
306
308
|
|
309
|
+
# Generic read & write + open existing + reparse point & backup semantics
|
310
|
+
handle = CreateFileW(
|
311
|
+
junction_path,
|
312
|
+
GENERIC_READ | GENERIC_WRITE,
|
313
|
+
0,
|
314
|
+
nil,
|
315
|
+
OPEN_EXISTING,
|
316
|
+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
317
|
+
0
|
318
|
+
)
|
319
|
+
|
320
|
+
if handle == INVALID_HANDLE_VALUE
|
321
|
+
raise SystemCallError.new("CreateFileW", FFI.errno)
|
322
|
+
end
|
323
|
+
|
324
|
+
rdb = REPARSE_JDATA_BUFFER.new
|
325
|
+
rdb[:ReparseTag] = 0
|
326
|
+
rdb[:ReparseDataLength] = 0
|
327
|
+
rdb[:Reserved] = 0
|
328
|
+
rdb[:SubstituteNameOffset] = 0
|
329
|
+
rdb[:SubstituteNameLength] = 0
|
330
|
+
rdb[:PrintNameOffset] = 0
|
331
|
+
rdb[:PrintNameLength] = 0
|
332
|
+
rdb[:PathBuffer] = ""
|
333
|
+
|
334
|
+
bytes = FFI::MemoryPointer.new(:ulong)
|
335
|
+
|
307
336
|
begin
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
GENERIC_READ | GENERIC_WRITE,
|
312
|
-
0,
|
337
|
+
bool = DeviceIoControl(
|
338
|
+
handle,
|
339
|
+
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, 0),
|
313
340
|
nil,
|
314
|
-
|
315
|
-
|
316
|
-
|
341
|
+
0,
|
342
|
+
rdb,
|
343
|
+
1024,
|
344
|
+
bytes,
|
345
|
+
nil
|
317
346
|
)
|
318
347
|
|
319
|
-
|
320
|
-
raise SystemCallError.new("CreateFileW", FFI.errno)
|
321
|
-
end
|
348
|
+
error = FFI.errno
|
322
349
|
|
323
|
-
|
324
|
-
|
325
|
-
rdb[:ReparseDataLength] = 0
|
326
|
-
rdb[:Reserved] = 0
|
327
|
-
rdb[:SubstituteNameOffset] = 0
|
328
|
-
rdb[:SubstituteNameLength] = 0
|
329
|
-
rdb[:PrintNameOffset] = 0
|
330
|
-
rdb[:PrintNameLength] = 0
|
331
|
-
rdb[:PathBuffer] = ''
|
332
|
-
|
333
|
-
bytes = FFI::MemoryPointer.new(:ulong)
|
334
|
-
|
335
|
-
begin
|
336
|
-
bool = DeviceIoControl(
|
337
|
-
handle,
|
338
|
-
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, 0),
|
339
|
-
nil,
|
340
|
-
0,
|
341
|
-
rdb,
|
342
|
-
1024,
|
343
|
-
bytes,
|
344
|
-
nil
|
345
|
-
)
|
346
|
-
|
347
|
-
error = FFI.errno
|
348
|
-
|
349
|
-
unless bool
|
350
|
-
raise SystemCallError.new("DeviceIoControl", error)
|
351
|
-
end
|
352
|
-
ensure
|
353
|
-
CloseHandle(handle)
|
350
|
+
unless bool
|
351
|
+
raise SystemCallError.new("DeviceIoControl", error)
|
354
352
|
end
|
353
|
+
ensure
|
354
|
+
CloseHandle(handle)
|
355
355
|
end
|
356
356
|
|
357
357
|
# MSDN says print and substitute names can be in any order
|
358
358
|
jname = (rdb[:PathBuffer].to_ptr + rdb[:SubstituteNameOffset]).read_string(rdb[:SubstituteNameLength])
|
359
|
-
jname = jname.bytes.to_a.pack(
|
359
|
+
jname = jname.bytes.to_a.pack("C*")
|
360
360
|
jname = jname.force_encoding("UTF-16LE")
|
361
|
-
raise "
|
361
|
+
raise "Invalid junction name: #{jname.encode("UTF-8")}" unless jname[0..3] == "\\??\\".encode("UTF-16LE")
|
362
|
+
|
362
363
|
begin
|
363
364
|
File.expand_path(jname[4..-1].encode(Encoding.default_external))
|
364
365
|
rescue Encoding::UndefinedConversionError
|
365
|
-
File.expand_path(jname[4..-1].encode(
|
366
|
+
File.expand_path(jname[4..-1].encode("UTF-8"))
|
366
367
|
end
|
367
368
|
end
|
368
369
|
|
@@ -376,15 +377,15 @@ class Dir
|
|
376
377
|
# Returns whether or not +path+ is a junction.
|
377
378
|
#
|
378
379
|
def self.junction?(path)
|
380
|
+
string_check(path)
|
379
381
|
bool = true
|
380
382
|
|
381
383
|
attrib = GetFileAttributesW("#{path}".wincode)
|
382
384
|
|
383
385
|
# Only directories with a reparse point attribute can be junctions
|
384
386
|
if attrib == INVALID_FILE_ATTRIBUTES ||
|
385
|
-
|
386
|
-
|
387
|
-
then
|
387
|
+
attrib & FILE_ATTRIBUTE_DIRECTORY == 0 ||
|
388
|
+
attrib & FILE_ATTRIBUTE_REPARSE_POINT == 0
|
388
389
|
bool = false
|
389
390
|
end
|
390
391
|
|
@@ -399,6 +400,17 @@ class Dir
|
|
399
400
|
|
400
401
|
private
|
401
402
|
|
403
|
+
class << self
|
404
|
+
# Simulate MRI's contortions for a stringiness check.
|
405
|
+
def string_check(arg)
|
406
|
+
return arg if arg.is_a?(String)
|
407
|
+
return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI honors it, even if private
|
408
|
+
return arg.to_path if arg.respond_to?(:to_path)
|
409
|
+
|
410
|
+
raise TypeError
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
402
414
|
# Macro from Windows header file, used by the create_junction method.
|
403
415
|
def self.CTL_CODE(device, function, method, access)
|
404
416
|
((device) << 16) | ((access) << 14) | ((function) << 2) | (method)
|