| [reply] |
I don't know, Randal, your column looked pretty trivial to me.
*cough*
| [reply] |
/me wonders why someone wouldn't just use File::PathConvert to convert relative paths to absolute, resolve symlinks, AND handle cross platform portability...
But anyway, I decided to see if I could write a symlink resolver that returns the absolute path of symlink. As the column merlyn refers to points out, symlinks can sometimes point to symlinks, so I made sure it can handle that. This is probably not the most efficient technique, but I did write it without refering to any documentation other 'mkdir' (I forgot about the permissions mask parameter...).
I'm not a heavy *nix internals program, so if someone can point out why this way may be a bad idea, I'd like to know. *nix internals is something I'd like to have a little more experience with, but so many projects... so little time.
It will also probably break on a condition where a '/' is embedded in a filename. I don't know if this is absolutely impossible or not, perhaps someone more unix-y can tell me.
Update:Add 's' modified on regex to handle newlines in file names, and add '"./" . ' to readlink() in case symlink pointed to a directory, instead of a file. Also, '/' occuring in a file name is not a concern, per tilly, tye and merlyn.
#!/usr/local/bin/perl -w
use strict;
use Cwd;
sub symlink_resolve
{
my $symlink = "./" . shift;
my ($path, $file);
my $here = getcwd ();
while (-l $symlink)
{
($path, $file) = $symlink =~ m|(.*/)(.*)|s;
chdir ($path) || return undef;
$symlink = "./" . readlink ($file) || return undef;
}
($file) = $symlink =~ m|(?:.*/)(.*)|;
$path = getcwd () || return undef;
chdir ($here) || die;
return "$path/$file";
}
{
#
# Delete it if already exists
#
unlink 'sym.final', 'sym.temp/sym.link1', 'sym.link2', 'sym.temp/sy
+m.link3', 'sym.link4';
rmdir 'sym.temp';
mkdir 'sym.temp', 0777;
open (FH, '>sym.final') || die;
close FH;
#
# Create a symlink: ~/sym.link4 -> ~/sym.temp/sym.link3 -> ~/sym.l
+ink2 -> ~/sym.temp/sym.link1 -> ~/sym.final
#
symlink ('../sym.final', 'sym.temp/sym.link1') || die;
symlink ('sym.temp/sym.link1', 'sym.link2') || die;
symlink ('../sym.link2', 'sym.temp/sym.link3') || die;
symlink ('sym.temp/sym.link3', 'sym.link4') || die;
#
# The test... Should tell us that sym.link4 resolves to sym.final
#
die unless my $file = symlink_resolve ('sym.link4');
print "sym.link4 resolves to $file\n";
#
# Clean up after ourselves
#
unlink 'sym.final', 'sym.temp/sym.link1', 'sym.link2', 'sym.temp/sy
+m.link3', 'sym.link4';
rmdir 'sym.temp';
}
--Chris
e-mail jcwren | [reply] [d/l] |
me wonders why someone wouldn't just use File::PathConvert to convert relative paths to absolute, resolve symlinks, AND handle cross platform portability...
Uh, the part in the middle was the hard part. {grin}
Your code uses an alteration of the working directory, which is a strategy
I considered (and had used in similar programs).
Your code also breaks (quickly {grin}) on paths containing newline, my favorite
pet peeve. Remember those /s modifiers!
-- Randal L. Schwartz, Perl hacker
| [reply] [d/l] |