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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e5e981af6ec776b828331968e333f10e07a00da1
4
- data.tar.gz: 6d4998906fc38e42b166b4f169bcd3e209e8fe50
2
+ SHA256:
3
+ metadata.gz: 2a8115d4e340523af631d3637a12c7e69836ebf25557b68d7ff6cbe57c04af7b
4
+ data.tar.gz: 68d05c5b0298b4deaeba910386066a2f92fbff050606b3b3af8e27c6a09d786c
5
5
  SHA512:
6
- metadata.gz: 3f6d943d7546b4b5a6df5507bf06e2dca571fe4f708eac4cf6f483f24cb20e304f3ab5cbbfb075d98cce0112e6e676069f0551d555f7e37ac78f536f2a5b45a9
7
- data.tar.gz: cb65e88ec9fa7d671c4a2744ed4f7e0cb80405d88f63a22a15411b33b04bbfef00adf37fa24a3120f1f274569e92fd06bcadb465ddefc63f591a541c5b9f44db
6
+ metadata.gz: 1a61c6fc6ce9259d40d1922a095b760578da70a31e526aee950e91eef74db83b7ee0c3c1716b50574fd251f462c2fa36aa2dd1233d1bc0e5234972a230e07381
7
+ data.tar.gz: 6007e11c210cc84bed879c0d025f4c94238da5dc96bcf28dadd1a3cae908a48e8eb01823a2943e15bd701e793a9e48402bd5546239b24dab381f147e8eca7fe2
@@ -0,0 +1 @@
1
+ require_relative "win32/dir"
@@ -1,92 +1,96 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'dir', 'constants')
2
- require File.join(File.dirname(File.expand_path(__FILE__)), 'dir', 'functions')
3
- require File.join(File.dirname(File.expand_path(__FILE__)), 'dir', 'structs')
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
- 'DESKTOP', 0x0000,
16
- 'INTERNET', 0x0001,
17
- 'PROGRAMS', 0x0002,
18
- 'CONTROLS', 0x0003,
19
- 'PRINTERS', 0x0004,
20
- 'PERSONAL', 0x0005,
21
- 'FAVORITES', 0x0006,
22
- 'STARTUP', 0x0007,
23
- 'RECENT', 0x0008,
24
- 'SENDTO', 0x0009,
25
- 'BITBUCKET', 0x000a,
26
- 'STARTMENU', 0x000b,
27
- 'MYDOCUMENTS', 0x000c,
28
- 'MYMUSIC', 0x000d,
29
- 'MYVIDEO', 0x000e,
30
- 'DESKTOPDIRECTORY', 0x0010,
31
- 'DRIVES', 0x0011,
32
- 'NETWORK', 0x0012,
33
- 'NETHOOD', 0x0013,
34
- 'FONTS', 0x0014,
35
- 'TEMPLATES', 0x0015,
36
- 'COMMON_STARTMENU', 0x0016,
37
- 'COMMON_PROGRAMS', 0X0017,
38
- 'COMMON_STARTUP', 0x0018,
39
- 'COMMON_FAVORITES', 0x001f,
40
- 'COMMON_DESKTOPDIRECTORY', 0x0019,
41
- 'APPDATA', 0x001a,
42
- 'PRINTHOOD', 0x001b,
43
- 'LOCAL_APPDATA', 0x001c,
44
- 'ALTSTARTUP', 0x001d,
45
- 'COMMON_ALTSTARTUP', 0x001e,
46
- 'INTERNET_CACHE', 0x0020,
47
- 'COOKIES', 0x0021,
48
- 'HISTORY', 0x0022,
49
- 'COMMON_APPDATA', 0x0023,
50
- 'WINDOWS', 0x0024,
51
- 'SYSTEM', 0x0025,
52
- 'PROGRAM_FILES', 0x0026,
53
- 'MYPICTURES', 0x0027,
54
- 'PROFILE', 0x0028,
55
- 'SYSTEMX86', 0x0029,
56
- 'PROGRAM_FILESX86', 0x002a,
57
- 'PROGRAM_FILES_COMMON', 0x002b,
58
- 'PROGRAM_FILES_COMMONX86', 0x002c,
59
- 'COMMON_TEMPLATES', 0x002d,
60
- 'COMMON_DOCUMENTS', 0x002e,
61
- 'CONNECTIONS', 0x0031,
62
- 'COMMON_MUSIC', 0x0035,
63
- 'COMMON_PICTURES', 0x0036,
64
- 'COMMON_VIDEO', 0x0037,
65
- 'RESOURCES', 0x0038,
66
- 'RESOURCES_LOCALIZED', 0x0039,
67
- 'COMMON_OEM_LINKS', 0x003a,
68
- 'CDBURN_AREA', 0x003b,
69
- 'COMMON_ADMINTOOLS', 0x002f,
70
- 'ADMINTOOLS', 0x0030
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{ |key, value|
71
+ csidl.each do |key, value|
75
72
  buf = 0.chr * 1024
76
73
  path = nil
77
- buf.encode!('UTF-16LE')
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(:long)
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
- if SHGetFileInfo(ptr.read_long, 0, info, info.size, flags) != 0
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('UTF-8')) if path
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| "#{pattern}".tr("\\", "/") }
120
+ temp = glob_pattern.map! { |pattern| string_check(pattern).tr("\\", "/") }
117
121
  else
118
- temp = "#{glob_pattern}".tr("\\", "/")
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 == 'java'
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('UTF-8')
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 = "#{to}".wincode
196
- from = "#{from}".wincode
199
+ to = string_check(to).wincode
200
+ from = string_check(from).wincode
197
201
 
198
- from_path = (0.chr * 1024).encode('UTF-16LE')
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('UTF-16LE')
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
- # Generic read & write + open existing + reparse point & backup semantics
228
- handle = CreateFileW(
229
- to_path,
230
- GENERIC_READ | GENERIC_WRITE,
231
- 0,
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
- OPEN_EXISTING,
234
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
235
- 0
266
+ 0,
267
+ bytes,
268
+ nil
236
269
  )
237
270
 
238
- if handle == INVALID_HANDLE_VALUE
239
- raise SystemCallError.new("CreateFileW", FFI.errno)
240
- end
271
+ error = FFI.errno
241
272
 
242
- target = "\\??\\".encode('UTF-16LE') + from_path
243
-
244
- rdb = REPARSE_JDATA_BUFFER.new
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?("#{junction}")
295
+ return false unless Dir.junction?(junction)
294
296
 
295
- junction = "#{junction}".wincode
297
+ junction = string_check(junction).wincode
296
298
 
297
- junction_path = (0.chr * 1024).encode('UTF-16LE')
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
- # Generic read & write + open existing + reparse point & backup semantics
309
- handle = CreateFileW(
310
- junction_path,
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
- OPEN_EXISTING,
315
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
316
- 0
341
+ 0,
342
+ rdb,
343
+ 1024,
344
+ bytes,
345
+ nil
317
346
  )
318
347
 
319
- if handle == INVALID_HANDLE_VALUE
320
- raise SystemCallError.new("CreateFileW", FFI.errno)
321
- end
348
+ error = FFI.errno
322
349
 
323
- rdb = REPARSE_JDATA_BUFFER.new
324
- rdb[:ReparseTag] = 0
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('C*')
359
+ jname = jname.bytes.to_a.pack("C*")
360
360
  jname = jname.force_encoding("UTF-16LE")
361
- raise "Junction name came back as #{jname}" unless jname[0..3] == "\\??\\".encode("UTF-16LE")
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('UTF-8'))
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
- attrib & FILE_ATTRIBUTE_DIRECTORY == 0 ||
386
- attrib & FILE_ATTRIBUTE_REPARSE_POINT == 0
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)