Skip to content

Commit b8739c1

Browse files
committed
Don't define symlink for Windows if FFI can't be loaded.
Fixes jruby#3943.
1 parent 005136a commit b8739c1

File tree

1 file changed

+75
-70
lines changed
  • core/src/main/ruby/jruby/kernel

1 file changed

+75
-70
lines changed

core/src/main/ruby/jruby/kernel/file.rb

Lines changed: 75 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
# Windows symlink support borrowed from djberg96/win32-file and ffi-win32-extensions
22

33
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
813
module File
914
module Constants
1015
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
@@ -81,88 +86,88 @@ class WIN32_FIND_DATA < FFI::Struct
8186
end
8287
end
8388
end
84-
end
8589

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
111115

112-
0 # Comply with spec
113-
end
116+
0 # Comply with spec
117+
end
114118

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)
119123

120-
bool = false
121-
wfile = string_check(file).wincode
124+
bool = false
125+
wfile = string_check(file).wincode
122126

123-
attrib = GetFileAttributesW(wfile)
127+
attrib = GetFileAttributesW(wfile)
124128

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
128132

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)
133137

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
137141

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)
140147
end
141-
ensure
142-
CloseHandle(handle)
143148
end
144-
end
145149

146-
bool
147-
end
150+
bool
151+
end
148152

149-
private
153+
private
150154

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
157162
end
158-
end
159163

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
166171
end
167172
end
168173
end

0 commit comments

Comments
 (0)