in reply to RE: Simple file question under linux
in thread Simple file question under linux

/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

Replies are listed 'Best First'.
RE: (jcwren) RE: (2) Simple file question under linux
by merlyn (Sage) on Oct 12, 2000 at 18:25 UTC
    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