win32-dir 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.4.0 - 29-Jun-2012
2
+ * Conversion to FFI. Should work with JRuby now.
3
+ * If current versions of Dir::XXX constant values cannot be found
4
+ then default values are tried.
5
+ * Now requires Ruby 1.9 or later.
6
+
1
7
  == 0.3.7 - 18-Jul-2010
2
8
  * Modified Dir.glob and Dir[] to handle backslashes in path names.
3
9
  * Added tests for the modified Dir.glob and Dir[] behavior.
data/MANIFEST CHANGED
@@ -1,8 +1,8 @@
1
- * README
2
- * MANIFEST
3
- * CHANGES
4
- * Rakefile
5
- * win32-dir.gemspec
6
- * examples/dir_example.rb
7
- * lib/win32/dir.rb
8
- * test/test_win32_dir.rb
1
+ * README
2
+ * MANIFEST
3
+ * CHANGES
4
+ * Rakefile
5
+ * win32-dir.gemspec
6
+ * examples/dir_example.rb
7
+ * lib/win32/dir.rb
8
+ * test/test_win32_dir.rb
data/README CHANGED
@@ -233,16 +233,11 @@ Dir::TEMPLATES
233
233
  only instead of an actual path.
234
234
 
235
235
  == Known Bugs
236
- The Unicode support is not quite there for Dir.create_junction. It creates
237
- the directory and junction fine, but the +to+ name appears to get garbled
238
- with regards to the character set.
239
-
240
- Please log any other bug reports on the RubyForge project page at
241
- http://www.rubyforge.net/projects/win32utils.
236
+ Please log any bug reports on the project page at
237
+ http://www.github.com/djberg96/win32-dir
242
238
 
243
239
  == Future Plans
244
- Fix the Unicode issue with Dir.create_junction.
245
- Other suggestions welcome.
240
+ Suggestions welcome.
246
241
 
247
242
  == Acknowledgements
248
243
  Shashank Date and Zach Dennis for the suggestion and supporting comments
@@ -258,7 +253,7 @@ Dir::TEMPLATES
258
253
  Artistic 2.0
259
254
 
260
255
  == Copyright
261
- (C) 2003-2010 Daniel J. Berger, All Rights Reserved
256
+ (C) 2003-2012 Daniel J. Berger, All Rights Reserved
262
257
 
263
258
  == Warranty
264
259
  This package is provided "as is" and without any express or
data/Rakefile CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'rake'
2
+ require 'rake/clean'
2
3
  require 'rake/testtask'
3
4
 
5
+ CLEAN.include('**/*.gem', '**/*.log')
6
+
4
7
  namespace 'gem' do
5
8
  desc "Create the win32-dir gem"
6
- task :build do
9
+ task :build => [:clean] do
7
10
  Dir["*.gem"].each{ |f| File.delete(f) }
8
11
  spec = eval(IO.read('win32-dir.gemspec'))
9
12
  Gem::Builder.new(spec).build
@@ -25,3 +28,5 @@ Rake::TestTask.new do |t|
25
28
  t.warning = true
26
29
  t.verbose = true
27
30
  end
31
+
32
+ task :default => :test
@@ -1,23 +1,23 @@
1
- ####################################################################
2
- # dir_example.rb
3
- #
4
- # Generic test script for general futzing. Modify as you see fit.
5
- # You can run this via the 'rake example' task.
6
- ####################################################################
7
- require 'win32/dir'
8
-
9
- puts "Admin Tools:\t\t" + Dir::ADMINTOOLS
10
- puts "Common Admin Tools:\t" + Dir::COMMON_ADMINTOOLS
11
- puts "App Data:\t\t" + Dir::APPDATA
12
- puts "Common App Data:\t" + Dir::COMMON_APPDATA
13
- puts "Common Documents:\t" + Dir::COMMON_DOCUMENTS
14
- puts "Cookies:\t\t" + Dir::COOKIES
15
- puts "History:\t\t" + Dir::HISTORY
16
- puts "Internet Cache:\t\t" + Dir::INTERNET_CACHE
17
- puts "Local App Data:\t\t" + Dir::LOCAL_APPDATA
18
- puts "My Pictures:\t\t" + Dir::MYPICTURES
19
- puts "Personal:\t\t" + Dir::PERSONAL
20
- puts "Program Files:\t\t" + Dir::PROGRAM_FILES
21
- puts "Program Files Common:\t" + Dir::PROGRAM_FILES_COMMON
22
- puts "System:\t\t\t" + Dir::SYSTEM
1
+ ####################################################################
2
+ # dir_example.rb
3
+ #
4
+ # Generic test script for general futzing. Modify as you see fit.
5
+ # You can run this via the 'rake example' task.
6
+ ####################################################################
7
+ require 'win32/dir'
8
+
9
+ puts "Admin Tools:\t\t" + Dir::ADMINTOOLS
10
+ puts "Common Admin Tools:\t" + Dir::COMMON_ADMINTOOLS
11
+ puts "App Data:\t\t" + Dir::APPDATA
12
+ puts "Common App Data:\t" + Dir::COMMON_APPDATA
13
+ puts "Common Documents:\t" + Dir::COMMON_DOCUMENTS
14
+ puts "Cookies:\t\t" + Dir::COOKIES
15
+ puts "History:\t\t" + Dir::HISTORY
16
+ puts "Internet Cache:\t\t" + Dir::INTERNET_CACHE
17
+ puts "Local App Data:\t\t" + Dir::LOCAL_APPDATA
18
+ puts "My Pictures:\t\t" + Dir::MYPICTURES
19
+ puts "Personal:\t\t" + Dir::PERSONAL
20
+ puts "Program Files:\t\t" + Dir::PROGRAM_FILES
21
+ puts "Program Files Common:\t" + Dir::PROGRAM_FILES_COMMON
22
+ puts "System:\t\t\t" + Dir::SYSTEM
23
23
  puts "Windows:\t\t" + Dir::WINDOWS
data/lib/win32/dir.rb CHANGED
@@ -1,119 +1,188 @@
1
- require 'windows/directory'
2
- require 'windows/shell'
3
- require 'windows/file'
4
- require 'windows/error'
5
- require 'windows/device_io'
6
- require 'windows/unicode'
7
- require 'windows/directory'
8
- require 'windows/handle'
9
- require 'windows/path'
10
- require 'windows/limits'
11
- require 'windows/system_info'
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')
12
4
 
13
5
  class Dir
14
- include Windows::Directory
15
- include Windows::Shell
16
- include Windows::Error
17
- include Windows::File
18
- include Windows::DeviceIO
19
- include Windows::Limits
20
-
21
- extend Windows::Directory
22
- extend Windows::Shell
23
- extend Windows::File
24
- extend Windows::Error
25
- extend Windows::DeviceIO
26
- extend Windows::Unicode
27
- extend Windows::Handle
28
- extend Windows::Path
29
- extend Windows::Limits
30
- extend Windows::SystemInfo
31
-
6
+ include Dir::Structs
7
+ include Dir::Constants
8
+ extend Dir::Functions
9
+
10
+ private_class_method(
11
+ :SHGetFolderPathW,
12
+ :SHGetFolderLocation,
13
+ :SHGetFileInfo,
14
+ :PathIsDirectoryEmptyW,
15
+ :CloseHandle,
16
+ :CreateDirectoryW,
17
+ :CreateFileW,
18
+ :DeviceIoControl,
19
+ :GetCurrentDirectoryW,
20
+ :GetFileAttributesW,
21
+ :GetLastError,
22
+ :GetShortPathNameW,
23
+ :GetLongPathNameW,
24
+ :GetFullPathNameW,
25
+ :RemoveDirectoryW
26
+ )
27
+
32
28
  # The version of the win32-dir library.
33
- VERSION = '0.3.7'
34
-
35
- # Dynamically set each of the CSIDL_ constants
36
- constants.grep(/CSIDL/).each{ |constant|
37
- path = 0.chr * MAXPATH
38
- nconst = constant.to_s.split('CSIDL_').last # to_s call for 1.9.x
39
-
40
- if SHGetFolderPath(0, const_get(constant), 0, 1, path) != 0
41
- path = nil
42
- else
43
- path.strip!
44
- end
29
+ VERSION = '0.4.0'
30
+
31
+ # CSIDL constants
32
+ csidl = Hash[
33
+ 'DESKTOP', 0x0000,
34
+ 'INTERNET', 0x0001,
35
+ 'PROGRAMS', 0x0002,
36
+ 'CONTROLS', 0x0003,
37
+ 'PRINTERS', 0x0004,
38
+ 'PERSONAL', 0x0005,
39
+ 'FAVORITES', 0x0006,
40
+ 'STARTUP', 0x0007,
41
+ 'RECENT', 0x0008,
42
+ 'SENDTO', 0x0009,
43
+ 'BITBUCKET', 0x000a,
44
+ 'STARTMENU', 0x000b,
45
+ 'MYDOCUMENTS', 0x000c,
46
+ 'MYMUSIC', 0x000d,
47
+ 'MYVIDEO', 0x000e,
48
+ 'DESKTOPDIRECTORY', 0x0010,
49
+ 'DRIVES', 0x0011,
50
+ 'NETWORK', 0x0012,
51
+ 'NETHOOD', 0x0013,
52
+ 'FONTS', 0x0014,
53
+ 'TEMPLATES', 0x0015,
54
+ 'COMMON_STARTMENU', 0x0016,
55
+ 'COMMON_PROGRAMS', 0X0017,
56
+ 'COMMON_STARTUP', 0x0018,
57
+ 'COMMON_FAVORITES', 0x001f,
58
+ 'COMMON_DESKTOPDIRECTORY', 0x0019,
59
+ 'APPDATA', 0x001a,
60
+ 'PRINTHOOD', 0x001b,
61
+ 'LOCAL_APPDATA', 0x001c,
62
+ 'ALTSTARTUP', 0x001d,
63
+ 'COMMON_ALTSTARTUP', 0x001e,
64
+ 'INTERNET_CACHE', 0x0020,
65
+ 'COOKIES', 0x0021,
66
+ 'HISTORY', 0x0022,
67
+ 'COMMON_APPDATA', 0x0023,
68
+ 'WINDOWS', 0x0024,
69
+ 'SYSTEM', 0x0025,
70
+ 'PROGRAM_FILES', 0x0026,
71
+ 'MYPICTURES', 0x0027,
72
+ 'PROFILE', 0x0028,
73
+ 'SYSTEMX86', 0x0029,
74
+ 'PROGRAM_FILESX86', 0x002a,
75
+ 'PROGRAM_FILES_COMMON', 0x002b,
76
+ 'PROGRAM_FILES_COMMONX86', 0x002c,
77
+ 'COMMON_TEMPLATES', 0x002d,
78
+ 'COMMON_DOCUMENTS', 0x002e,
79
+ 'CONNECTIONS', 0x0031,
80
+ 'COMMON_MUSIC', 0x0035,
81
+ 'COMMON_PICTURES', 0x0036,
82
+ 'COMMON_VIDEO', 0x0037,
83
+ 'RESOURCES', 0x0038,
84
+ 'RESOURCES_LOCALIZED', 0x0039,
85
+ 'COMMON_OEM_LINKS', 0x003a,
86
+ 'CDBURN_AREA', 0x003b,
87
+ 'COMMON_ADMINTOOLS', 0x002f,
88
+ 'ADMINTOOLS', 0x0030
89
+ ]
45
90
 
46
- # Try another approach for virtual folders
47
- if path.nil?
48
- ppidl = 0.chr * 4 # PIDLIST_ABSOLUTE
91
+ # Dynamically set each of the CSIDL constants
92
+ csidl.each{ |key, value|
93
+ buf = 0.chr * 1024
94
+ path = nil
95
+ buf.encode!('UTF-16LE')
49
96
 
50
- if SHGetFolderLocation(0, const_get(constant), 0, 0, ppidl) == S_OK
51
- info = 0.chr * 692 # sizeof(SHFILEINFO)
52
- flags = SHGFI_DISPLAYNAME | SHGFI_PIDL
53
- SHGetFileInfo(ppidl.unpack('L')[0], 0, info, 692, flags)
54
- path = info[12..-1].strip
97
+ if SHGetFolderPathW(0, value, 0, 0, buf) == 0 # Current path
98
+ path = buf.strip
99
+ elsif SHGetFolderPathW(0, value, 0, 1, buf) == 0 # Default path
100
+ path = buf.strip
101
+ else
102
+ ptr = FFI::MemoryPointer.new(:long)
103
+ info = SHFILEINFO.new
104
+ flags = SHGFI_DISPLAYNAME | SHGFI_PIDL
105
+
106
+ if SHGetFolderLocation(0, value, 0, 0, ptr) == 0
107
+ if SHGetFileInfo(ptr.read_long, 0, info, info.size, flags) != 0
108
+ path = info[:szDisplayName].to_s
109
+ end
55
110
  end
56
111
  end
57
112
 
58
- Dir.const_set(nconst, path) if path
113
+ Dir.const_set(key, path) if path
59
114
  }
60
115
 
61
116
  # Set Dir::MYDOCUMENTS to the same as Dir::PERSONAL if undefined
62
117
  unless defined? MYDOCUMENTS
63
- # Same as Dir::PERSONAL
64
118
  MYDOCUMENTS = PERSONAL
65
119
  end
66
-
120
+
67
121
  class << self
68
- remove_method :getwd
69
- remove_method :pwd
70
- alias :old_glob :glob
71
- alias :old_ref :[]
72
- remove_method :glob
73
- remove_method :[]
74
- end
122
+ alias old_glob glob
75
123
 
76
- # Same as the standard MRI Dir.glob method except that it handles
77
- # backslashes in path names.
78
- #
79
- def self.glob(glob_pattern, flags = 0, &block)
80
- glob_pattern = glob_pattern.tr("\\", "/")
81
- old_glob(glob_pattern, flags, &block)
82
- end
124
+ # Same as the standard MRI Dir.glob method except that it handles
125
+ # backslashes in path names.
126
+ #
127
+ def glob(glob_pattern, flags = 0, &block)
128
+ glob_pattern = glob_pattern.tr("\\", "/")
129
+ old_glob(glob_pattern, flags, &block)
130
+ end
83
131
 
84
- # Same as the standard MRI Dir[] method except that it handles
85
- # backslashes in path names.
86
- #
87
- def self.[](glob_pattern)
88
- glob_pattern = glob_pattern.tr("\\", "/")
89
- old_ref(glob_pattern)
90
- end
91
-
92
- # Returns the present working directory. Unlike MRI, this method always
93
- # normalizes the path.
94
- #
95
- # Examples:
96
- #
97
- # Dir.chdir("C:/Progra~1")
98
- # Dir.getwd # => C:\Program Files
99
- #
100
- # Dir.chdir("C:/PROGRAM FILES")
101
- # Dir.getwd # => C:\Program Files
102
- #
103
- def self.getwd
104
- path1 = 0.chr * MAXPATH
105
- path2 = 0.chr * MAXPATH
106
- path3 = 0.chr * MAXPATH
132
+ alias old_ref []
107
133
 
108
- GetCurrentDirectory(MAXPATH, path1)
109
- GetShortPathName(path1, path2, MAXPATH)
110
- GetLongPathName(path2, path3, MAXPATH)
134
+ # Same as the standard MRI Dir[] method except that it handles
135
+ # backslashes in path names.
136
+ #
137
+ def [](glob_pattern)
138
+ glob_pattern = glob_pattern.tr("\\", "/")
139
+ old_ref(glob_pattern)
140
+ end
111
141
 
112
- path3[/^[^\0]*/]
113
- end
114
-
115
- class << self
116
- alias :pwd :getwd
142
+ # JRuby normalizes the path by default.
143
+ unless RUBY_PLATFORM == 'java'
144
+ alias oldgetwd getwd
145
+ alias oldpwd pwd
146
+
147
+ # Returns the present working directory. Unlike MRI, this method always
148
+ # normalizes the path.
149
+ #
150
+ # Examples:
151
+ #
152
+ # Dir.chdir("C:/Progra~1")
153
+ # Dir.getwd # => C:\Program Files
154
+ #
155
+ # Dir.chdir("C:/PROGRAM FILES")
156
+ # Dir.getwd # => C:\Program Files
157
+ #
158
+ def getwd
159
+ path1 = 0.chr * 1024
160
+ path2 = 0.chr * 1024
161
+ path3 = 0.chr * 1024
162
+
163
+ path1.encode!('UTF-16LE')
164
+
165
+ if GetCurrentDirectoryW(path1.size, path1) == 0
166
+ raise SystemCallError, FFI.errno, "GetCurrentDirectoryW"
167
+ end
168
+
169
+ path2.encode!('UTF-16LE')
170
+
171
+ if GetShortPathNameW(path1, path2, path2.size) == 0
172
+ raise SystemCallError, FFi.errno, "GetShortPathNameW"
173
+ end
174
+
175
+ path3.encode!('UTF-16LE')
176
+
177
+ if GetLongPathNameW(path2, path3, path3.size) == 0
178
+ raise SystemCallError, FFI.errno, "GetLongPathNameW"
179
+ end
180
+
181
+ path3.strip.encode(Encoding.default_external)
182
+ end
183
+
184
+ alias :pwd :getwd
185
+ end
117
186
  end
118
187
 
119
188
  # Creates the symlink +to+, linked to the existing directory +from+. If the
@@ -123,121 +192,140 @@ class Dir
123
192
  #
124
193
  # Dir.mkdir('C:/from')
125
194
  # Dir.create_junction('C:/to', 'C:/from')
126
- #
195
+ #
127
196
  def self.create_junction(to, from)
128
- to = to.tr(File::SEPARATOR, File::ALT_SEPARATOR) # Normalize path
129
- from = from.tr(File::SEPARATOR, File::ALT_SEPARATOR) # Normalize path
130
-
131
- to_path = 0.chr * MAXPATH
132
- from_path = 0.chr * MAXPATH
133
- buf_target = 0.chr * MAXPATH
134
-
135
- length = GetFullPathName(from, from_path.size, from_path, 0)
197
+ to = to.tr(File::SEPARATOR, File::ALT_SEPARATOR) + "\0" # Normalize path
198
+ from = from.tr(File::SEPARATOR, File::ALT_SEPARATOR) + "\0" # Normalize path
199
+
200
+ to.encode!('UTF-16LE')
201
+ from.encode!('UTF-16LE')
202
+
203
+ from_path = 0.chr * 1024
204
+ from_path.encode!('UTF-16LE')
205
+
206
+ length = GetFullPathNameW(from, from_path.size, from_path, nil)
136
207
 
137
208
  if length == 0
138
- raise StandardError, 'GetFullPathName() failed: ' + get_last_error
209
+ raise SystemCallError, FFI.errno, "GetFullPathNameW"
139
210
  else
140
- from_path = from_path[0..length-1]
211
+ from_path.strip!
141
212
  end
142
-
143
- length = GetFullPathName(to, to_path.size, to_path, 0)
213
+
214
+ to_path = 0.chr * 1024
215
+ to.encode!('UTF-16LE')
216
+ to_path.encode!('UTF-16LE')
217
+
218
+ length = GetFullPathNameW(to, to_path.size, to_path, nil)
144
219
 
145
220
  if length == 0
146
- raise StandardError, 'GetFullPathName() failed: ' + get_last_error
221
+ raise SystemCallError, FFI.errno, "GetFullPathNameW"
147
222
  else
148
- to_path = to_path[0..length-1]
223
+ to_path.strip!
149
224
  end
150
225
 
151
226
  # You can create a junction to a directory that already exists, so
152
227
  # long as it's empty.
153
- rv = CreateDirectory(to_path, 0)
154
-
155
- if rv == 0 && rv != ERROR_ALREADY_EXISTS
156
- raise StandardError, 'CreateDirectory() failed: ' + get_last_error
228
+ unless CreateDirectoryW(to_path, nil)
229
+ if FFI.errno != ERROR_ALREADY_EXISTS
230
+ raise SystemCallError, FFI.errno, "CreateDirectoryW"
231
+ end
157
232
  end
158
-
159
- handle = CreateFile(
160
- to_path,
161
- GENERIC_READ | GENERIC_WRITE,
162
- 0,
163
- 0,
164
- OPEN_EXISTING,
165
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
166
- 0
167
- )
168
-
169
- if handle == INVALID_HANDLE_VALUE
170
- raise StandardError, 'CreateFile() failed: ' + get_last_error
171
- end
172
-
173
- buf_target = buf_target.split(0.chr).first
174
- buf_target = "\\??\\" << from_path
175
- wide_string = multi_to_wide(buf_target)[0..-3]
176
-
177
- # REPARSE_JDATA_BUFFER
178
- rdb = [
179
- "0xA0000003L".hex, # ReparseTag (IO_REPARSE_TAG_MOUNT_POINT)
180
- wide_string.size + 12, # ReparseDataLength
181
- 0, # Reserved
182
- 0, # SubstituteNameOffset
183
- wide_string.size, # SubstituteNameLength
184
- wide_string.size + 2, # PrintNameOffset
185
- 0, # PrintNameLength
186
- wide_string # PathBuffer
187
- ].pack('LSSSSSSa' + (wide_string.size + 4).to_s)
188
-
189
- bytes = [0].pack('L')
190
233
 
191
234
  begin
192
- bool = DeviceIoControl(
193
- handle,
194
- CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, 0),
195
- rdb,
196
- rdb.size,
235
+ # Generic read & write + open existing + reparse point & backup semantics
236
+ handle = CreateFileW(
237
+ to_path,
238
+ GENERIC_READ | GENERIC_WRITE,
197
239
  0,
198
- 0,
199
- bytes,
240
+ nil,
241
+ OPEN_EXISTING,
242
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
200
243
  0
201
244
  )
202
-
203
- unless bool
204
- error = 'DeviceIoControl() failed: ' + get_last_error
205
- RemoveDirectory(to_path)
206
- raise error
245
+
246
+ if handle == INVALID_HANDLE_VALUE
247
+ raise SystemCallError, FFI.errno, "CreateFileW"
248
+ end
249
+
250
+ target = "\\??\\".encode('UTF-16LE') + from_path
251
+
252
+ rdb = REPARSE_JDATA_BUFFER.new
253
+ rdb[:ReparseTag] = 2684354563 # IO_REPARSE_TAG_MOUNT_POINT
254
+ rdb[:ReparseDataLength] = target.bytesize + 12
255
+ rdb[:Reserved] = 0
256
+ rdb[:SubstituteNameOffset] = 0
257
+ rdb[:SubstituteNameLength] = target.bytesize
258
+ rdb[:PrintNameOffset] = target.bytesize + 2
259
+ rdb[:PrintNameLength] = 0
260
+ rdb[:PathBuffer] = target
261
+
262
+ bytes = FFI::MemoryPointer.new(:ulong)
263
+
264
+ begin
265
+ bool = DeviceIoControl(
266
+ handle,
267
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, 0),
268
+ rdb,
269
+ rdb[:ReparseDataLength] + 8,
270
+ nil,
271
+ 0,
272
+ bytes,
273
+ nil
274
+ )
275
+
276
+ error = FFI.errno
277
+
278
+ unless bool
279
+ RemoveDirectoryW(to_path)
280
+ raise SystemCallError, error, "DeviceIoControl"
281
+ end
282
+ ensure
283
+ CloseHandle(handle)
207
284
  end
208
- ensure
209
- CloseHandle(handle)
210
285
  end
211
-
212
- self
286
+
287
+ self
213
288
  end
214
-
289
+
215
290
  # Returns whether or not +path+ is empty. Returns false if +path+ is not
216
291
  # a directory, or contains any files other than '.' or '..'.
217
- #
292
+ #
218
293
  def self.empty?(path)
219
- PathIsDirectoryEmpty(path)
294
+ path = path + "\0"
295
+ path = path.encode('UTF-16LE')
296
+ PathIsDirectoryEmptyW(path)
220
297
  end
221
-
298
+
222
299
  # Returns whether or not +path+ is a junction.
223
- #
300
+ #
224
301
  def self.junction?(path)
225
- bool = true
226
- attrib = GetFileAttributes(path)
227
-
302
+ bool = true
303
+ path = path + "\0"
304
+ path.encode!('UTF-16LE')
305
+
306
+ attrib = GetFileAttributesW(path)
307
+
308
+ # Only directories with a reparse point attribute can be junctions
228
309
  if attrib == INVALID_FILE_ATTRIBUTES ||
229
310
  attrib & FILE_ATTRIBUTE_DIRECTORY == 0 ||
230
311
  attrib & FILE_ATTRIBUTE_REPARSE_POINT == 0
231
312
  then
232
- bool = false
313
+ bool = false
233
314
  end
234
-
315
+
235
316
  bool
236
- end
237
-
317
+ end
318
+
238
319
  # Class level aliases
239
320
  #
240
321
  class << self
241
322
  alias reparse_dir? junction?
242
323
  end
324
+
325
+ private
326
+
327
+ # Macro from Windows header file, used by the create_junction method.
328
+ def self.CTL_CODE(device, function, method, access)
329
+ ((device) << 16) | ((access) << 14) | ((function) << 2) | (method)
330
+ end
243
331
  end