win32-dir 0.4.7 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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)