Hello
You may try the following applescript script, which is a simple wrapper of rubycocoa script. It requires OSX 10.6 or later for CF API to resolve alias.
It will ask you to choose the directory where the target file system subtree is rooted and then try to replace every alias file found in the tree with symlink. Package contents are not traversed. A log file is created on desktop.
If alias file cannot be replaced, e.g., being locked or without write permission etc, symlink is not created and error is logged. If the volume where target of alias resides is not mounted, the alias is not resolved and error is logged.
Briefly tested under 10.6.8. However, no warranties of any kind. Please make sure you have backup of target directory.
Hope this may help,
H
set d to (choose folder with prompt "Choose start folder")'s POSIX path
replace_alias_with_symlink(d)
on replace_alias_with_symlink(d)
(*
string d : POSIX path of directory where target subtree is rooted
*)
set ruby to "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby"
do shell script ruby & " -w <<'EOF' - " & d's quoted form & "
require 'FileUtils'
require 'osx/cocoa'
include OSX
# log file is YYYY-MM-DD_alias_to_symlink_log.txt in ~/desktop
LOGF = File.expand_path(Time.now.strftime('%F_alias_to_symlink_log.txt'), '~/desktop')
def log(s, options = {:stamp => true})
File.open(LOGF, 'a') do |a|
a.puts '%-26s%s' % [options[:stamp] ? Time.now.strftime('%F %T%z') : '', s]
end
end
def resolve_alias(f)
#
# string f : POSIX path of alias file
# return string : POSIX path of target file or nil if failed to resolve alias
#
# * requires OSX 10.6 or later for
# CFURLCreateBookmarkDataFromFile()
# CFURLCreateByResolvingBookmarkData()
#
url = NSURL.fileURLWithPath(f)
bmrk = CFURLCreateBookmarkDataFromFile(KCFAllocatorDefault, url, nil)
unless bmrk
log('# Error: unable to get bookmark data from %s' % f)
return nil
end
stale = ObjcPtr.new(:char) # BOOL*
url1 = CFURLCreateByResolvingBookmarkData(
KCFAllocatorDefault,
bmrk,
KCFBookmarkResolutionWithoutMountingMask | KCFBookmarkResolutionWithoutUIMask,
nil,
nil,
stale,
nil)
unless url1
log('# Error: unable to resolve alias %s' % f)
return nil
end
if stale.bool != 0 # this should not happen, for bmrk is fresh
log('# Warning: stale alias %s' % f)
end
return url1.path.to_s
end
raise ArgumentError, %Q[Usage: #{File.basename($0)} directory] unless ARGV.length == 1
dir = ARGV[0].chomp('/')
denum = NSFileManager.defaultManager.enumeratorAtPath(dir)
wks = NSWorkspace.sharedWorkspace
# scan aliases
aa = [] # list of aliases under dir
while (f = denum.nextObject) != nil do
file = dir + '/' + f.to_s
denum.skipDescendants if wks.isFilePackageAtPath(file) # ignore package contents
if denum.fileAttributes.objectForKey(NSFileType) == NSFileTypeRegular
aa << file if wks.objc_send(:typeOfFile, file, :error, nil) == 'com.apple.alias-file'
end
end
# replace alias with symlink
aa.each do |a|
f = resolve_alias(a)
next unless f
begin
FileUtils.ln_sf(f, a)
log('Created symlink %s => %s' % [a, f])
rescue => ex
log('# Error: failed to create symlink %s => %s' % [a, f])
log(' %s: %s' % [ex.class, ex.message], :stamp => false)
end
end
EOF"
end replace_alias_with_symlink