Skip to content

Commit

Permalink
Showing 1 changed file with 75 additions and 70 deletions.
145 changes: 75 additions & 70 deletions core/src/main/ruby/jruby/kernel/file.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# Windows symlink support borrowed from djberg96/win32-file and ffi-win32-extensions

if org.jruby.platform.Platform::IS_WINDOWS
require 'ffi'

module JRuby
module Windows

begin
require 'ffi'
rescue LoadError
# Gracefully bail if FFI is not available
end

if defined?(::FFI)
module JRuby::Windows
module File
module Constants
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
@@ -81,88 +86,88 @@ class WIN32_FIND_DATA < FFI::Struct
end
end
end
end

# Since we only do this for symlink, skip it all if it's not available on this version of Windows (jruby/jruby#3998)
if JRuby::Windows::File::Functions.respond_to? :CreateSymbolicLinkW
class File
include JRuby::Windows::File::Constants
include JRuby::Windows::File::Structs
extend JRuby::Windows::File::Functions

# Creates a symbolic link called +new_name+ for the file or directory
# +old_name+.
#
# This method requires Windows Vista or later to work. Otherwise, it
# returns nil as per MRI.
#
def self.symlink(target, link)
target = string_check(target)
link = string_check(link)

flags = File.directory?(target) ? 1 : 0

wlink = link.wincode
wtarget = target.wincode

unless CreateSymbolicLinkW(wlink, wtarget, flags)
raise SystemCallError.new('CreateSymbolicLink', FFI.errno)
end
# Since we only do this for symlink, skip it all if it's not available on this version of Windows (jruby/jruby#3998)
if JRuby::Windows::File::Functions.respond_to? :CreateSymbolicLinkW
class File
include JRuby::Windows::File::Constants
include JRuby::Windows::File::Structs
extend JRuby::Windows::File::Functions

# Creates a symbolic link called +new_name+ for the file or directory
# +old_name+.
#
# This method requires Windows Vista or later to work. Otherwise, it
# returns nil as per MRI.
#
def self.symlink(target, link)
target = string_check(target)
link = string_check(link)

flags = File.directory?(target) ? 1 : 0

wlink = link.wincode
wtarget = target.wincode

unless CreateSymbolicLinkW(wlink, wtarget, flags)
raise SystemCallError.new('CreateSymbolicLink', FFI.errno)
end

0 # Comply with spec
end
0 # Comply with spec
end

# Returns whether or not +file+ is a symlink.
#
def self.symlink?(file)
return false unless File.exist?(file)
# Returns whether or not +file+ is a symlink.
#
def self.symlink?(file)
return false unless File.exist?(file)

bool = false
wfile = string_check(file).wincode
bool = false
wfile = string_check(file).wincode

attrib = GetFileAttributesW(wfile)
attrib = GetFileAttributesW(wfile)

if attrib == INVALID_FILE_ATTRIBUTES
raise SystemCallError.new('GetFileAttributes', FFI.errno)
end
if attrib == INVALID_FILE_ATTRIBUTES
raise SystemCallError.new('GetFileAttributes', FFI.errno)
end

if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0
begin
find_data = WIN32_FIND_DATA.new
handle = FindFirstFileW(wfile, find_data)
if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0
begin
find_data = WIN32_FIND_DATA.new
handle = FindFirstFileW(wfile, find_data)

if handle == INVALID_HANDLE_VALUE
raise SystemCallError.new('FindFirstFile', FFI.errno)
end
if handle == INVALID_HANDLE_VALUE
raise SystemCallError.new('FindFirstFile', FFI.errno)
end

if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
bool = true
if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
bool = true
end
ensure
CloseHandle(handle)
end
ensure
CloseHandle(handle)
end
end

bool
end
bool
end

private
private

# Simulate Ruby's string checking
def self.string_check(arg)
return arg if arg.is_a?(String)
return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str
return arg.to_path if arg.respond_to?(:to_path)
raise TypeError
# Simulate Ruby's string checking
def self.string_check(arg)
return arg if arg.is_a?(String)
return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str
return arg.to_path if arg.respond_to?(:to_path)
raise TypeError
end
end
end

class String
# Convenience method for converting strings to UTF-16LE for wide character
# functions that require it.
#
def wincode
(self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
class String
# Convenience method for converting strings to UTF-16LE for wide character
# functions that require it.
#
def wincode
(self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
end
end
end
end

0 comments on commit b8739c1

Please sign in to comment.