|
1 | 1 | # Windows symlink support borrowed from djberg96/win32-file and ffi-win32-extensions |
2 | 2 |
|
3 | 3 | if org.jruby.platform.Platform::IS_WINDOWS |
4 | | - require 'ffi' |
5 | | - |
6 | | - module JRuby |
7 | | - module Windows |
| 4 | + |
| 5 | + begin |
| 6 | + require 'ffi' |
| 7 | + rescue LoadError |
| 8 | + # Gracefully bail if FFI is not available |
| 9 | + end |
| 10 | + |
| 11 | + if defined?(::FFI) |
| 12 | + module JRuby::Windows |
8 | 13 | module File |
9 | 14 | module Constants |
10 | 15 | FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 |
@@ -81,88 +86,88 @@ class WIN32_FIND_DATA < FFI::Struct |
81 | 86 | end |
82 | 87 | end |
83 | 88 | end |
84 | | - end |
85 | 89 |
|
86 | | - # Since we only do this for symlink, skip it all if it's not available on this version of Windows (jruby/jruby#3998) |
87 | | - if JRuby::Windows::File::Functions.respond_to? :CreateSymbolicLinkW |
88 | | - class File |
89 | | - include JRuby::Windows::File::Constants |
90 | | - include JRuby::Windows::File::Structs |
91 | | - extend JRuby::Windows::File::Functions |
92 | | - |
93 | | - # Creates a symbolic link called +new_name+ for the file or directory |
94 | | - # +old_name+. |
95 | | - # |
96 | | - # This method requires Windows Vista or later to work. Otherwise, it |
97 | | - # returns nil as per MRI. |
98 | | - # |
99 | | - def self.symlink(target, link) |
100 | | - target = string_check(target) |
101 | | - link = string_check(link) |
102 | | - |
103 | | - flags = File.directory?(target) ? 1 : 0 |
104 | | - |
105 | | - wlink = link.wincode |
106 | | - wtarget = target.wincode |
107 | | - |
108 | | - unless CreateSymbolicLinkW(wlink, wtarget, flags) |
109 | | - raise SystemCallError.new('CreateSymbolicLink', FFI.errno) |
110 | | - end |
| 90 | + # Since we only do this for symlink, skip it all if it's not available on this version of Windows (jruby/jruby#3998) |
| 91 | + if JRuby::Windows::File::Functions.respond_to? :CreateSymbolicLinkW |
| 92 | + class File |
| 93 | + include JRuby::Windows::File::Constants |
| 94 | + include JRuby::Windows::File::Structs |
| 95 | + extend JRuby::Windows::File::Functions |
| 96 | + |
| 97 | + # Creates a symbolic link called +new_name+ for the file or directory |
| 98 | + # +old_name+. |
| 99 | + # |
| 100 | + # This method requires Windows Vista or later to work. Otherwise, it |
| 101 | + # returns nil as per MRI. |
| 102 | + # |
| 103 | + def self.symlink(target, link) |
| 104 | + target = string_check(target) |
| 105 | + link = string_check(link) |
| 106 | + |
| 107 | + flags = File.directory?(target) ? 1 : 0 |
| 108 | + |
| 109 | + wlink = link.wincode |
| 110 | + wtarget = target.wincode |
| 111 | + |
| 112 | + unless CreateSymbolicLinkW(wlink, wtarget, flags) |
| 113 | + raise SystemCallError.new('CreateSymbolicLink', FFI.errno) |
| 114 | + end |
111 | 115 |
|
112 | | - 0 # Comply with spec |
113 | | - end |
| 116 | + 0 # Comply with spec |
| 117 | + end |
114 | 118 |
|
115 | | - # Returns whether or not +file+ is a symlink. |
116 | | - # |
117 | | - def self.symlink?(file) |
118 | | - return false unless File.exist?(file) |
| 119 | + # Returns whether or not +file+ is a symlink. |
| 120 | + # |
| 121 | + def self.symlink?(file) |
| 122 | + return false unless File.exist?(file) |
119 | 123 |
|
120 | | - bool = false |
121 | | - wfile = string_check(file).wincode |
| 124 | + bool = false |
| 125 | + wfile = string_check(file).wincode |
122 | 126 |
|
123 | | - attrib = GetFileAttributesW(wfile) |
| 127 | + attrib = GetFileAttributesW(wfile) |
124 | 128 |
|
125 | | - if attrib == INVALID_FILE_ATTRIBUTES |
126 | | - raise SystemCallError.new('GetFileAttributes', FFI.errno) |
127 | | - end |
| 129 | + if attrib == INVALID_FILE_ATTRIBUTES |
| 130 | + raise SystemCallError.new('GetFileAttributes', FFI.errno) |
| 131 | + end |
128 | 132 |
|
129 | | - if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0 |
130 | | - begin |
131 | | - find_data = WIN32_FIND_DATA.new |
132 | | - handle = FindFirstFileW(wfile, find_data) |
| 133 | + if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0 |
| 134 | + begin |
| 135 | + find_data = WIN32_FIND_DATA.new |
| 136 | + handle = FindFirstFileW(wfile, find_data) |
133 | 137 |
|
134 | | - if handle == INVALID_HANDLE_VALUE |
135 | | - raise SystemCallError.new('FindFirstFile', FFI.errno) |
136 | | - end |
| 138 | + if handle == INVALID_HANDLE_VALUE |
| 139 | + raise SystemCallError.new('FindFirstFile', FFI.errno) |
| 140 | + end |
137 | 141 |
|
138 | | - if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK |
139 | | - bool = true |
| 142 | + if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK |
| 143 | + bool = true |
| 144 | + end |
| 145 | + ensure |
| 146 | + CloseHandle(handle) |
140 | 147 | end |
141 | | - ensure |
142 | | - CloseHandle(handle) |
143 | 148 | end |
144 | | - end |
145 | 149 |
|
146 | | - bool |
147 | | - end |
| 150 | + bool |
| 151 | + end |
148 | 152 |
|
149 | | - private |
| 153 | + private |
150 | 154 |
|
151 | | - # Simulate Ruby's string checking |
152 | | - def self.string_check(arg) |
153 | | - return arg if arg.is_a?(String) |
154 | | - return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str |
155 | | - return arg.to_path if arg.respond_to?(:to_path) |
156 | | - raise TypeError |
| 155 | + # Simulate Ruby's string checking |
| 156 | + def self.string_check(arg) |
| 157 | + return arg if arg.is_a?(String) |
| 158 | + return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str |
| 159 | + return arg.to_path if arg.respond_to?(:to_path) |
| 160 | + raise TypeError |
| 161 | + end |
157 | 162 | end |
158 | | - end |
159 | 163 |
|
160 | | - class String |
161 | | - # Convenience method for converting strings to UTF-16LE for wide character |
162 | | - # functions that require it. |
163 | | - # |
164 | | - def wincode |
165 | | - (self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE') |
| 164 | + class String |
| 165 | + # Convenience method for converting strings to UTF-16LE for wide character |
| 166 | + # functions that require it. |
| 167 | + # |
| 168 | + def wincode |
| 169 | + (self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE') |
| 170 | + end |
166 | 171 | end |
167 | 172 | end |
168 | 173 | end |
|
0 commit comments