--- toast 2004/02/14 07:52:25 1.296 +++ toast 2004/02/21 04:36:07 1.297 @@ -3,7 +3,7 @@ ############################################################################## # # # This entire file is toast, a program for installing and managing software. # -# Copyright (C) 2003-2003 Jacques Frechet. # +# Copyright (C) 2003-2004 Jacques Frechet. # # Note that this file contains Version 2 of the GNU General Public License, # # which includes its own copyright notice. # # # @@ -255,6 +255,7 @@ "showurls" => true, "infodir" => true, "protect" => true, + "relative" => false, "debugrewrite" => false, ); @@ -501,6 +502,12 @@ ln($source, $target) unless -e($target) || -l($target); } +sub relln($$) +{ + my($src, $target) = @_; + ln($src =~ m|^/| ? findrelpath(dirname($target), $src) : $src, $target); +} + ############################################################################## sub safestat($) @@ -1031,6 +1038,61 @@ return path(pwd, $path); } +sub findrelpath($$) +{ + my($from, $to) = @_; + + # allow last component of $to to be missing or not a directory + my(@append); + if(!-d($to)) + { + push(@append, basename($to)); + $to = dirname($to); + } + + # walk from $to all the way to /, leaving a trail of bread crumbs + my($dir, $lastdi, @names, %ditonameidx) = ($to, ""); + for(1..1024) + { + my($d, $i) = safestat($dir); + my($di) = "$d $i"; + $ditonameidx{$di} = $#names unless exists($ditonameidx{$di}); + last if $dir eq "/"; + $dir = path($dir, ".."); + last if whiledir # figure out how to get down one level from here + { + my($pd, $pi) = safestat(path($dir, $_)); + return true unless "$pd $pi" eq $di; + push(@names, $_); + return false; + } $dir; + last if $di eq $lastdi; + $lastdi = $di; + } + + # walk up from $from towards / looking for bread crumbs + ($dir, $lastdi) = ($from, ""); + my(@result); + for(1..1024) + { + my($d, $i) = safestat($dir); + my($di) = "$d $i"; + last if $di eq $lastdi; + $lastdi = $di; + if(exists($ditonameidx{$di})) + { + my($nameidx) = $ditonameidx{$di}; + push(@result, reverse(@names[0..$nameidx])); + push(@result, @append); + return scalar(@result) == 0 ? "." : path(@result); + } + $dir = path($dir, ".."); + push(@result, ".."); + } + + error("no relative path from $from to $to"); +} + ############################################################################## sub validname($) @@ -3298,7 +3360,11 @@ optmd($dir); safechmod(0777, $dir); }, - sub { ln($_, displace(optpath(armdir, $_[0]))) }, + sub + { + my($target) = displace(optpath(armdir, $_[0])); + relative ? relln($_, $target) : ln($_, $target); + }, sub { safechmod($mode, optpath(armdir, $_[0])) } ); @@ -3353,8 +3419,7 @@ my($armfile) = path(armdir, $rel); # BUG: $rel is sometimes undefined? while(-e($armfile) || -l($armfile)) { - my($target) = readlink($armfile); - return replace($armfile) if defined($target) && $target eq $_; + return replace($armfile) if optsamefile($armfile, $_); $armfile = addoff($armfile); } return true; @@ -5712,11 +5777,27 @@ =item S<B<--protect> | B<--noprotect>> If B<protect> is enabled, B<toast arm> will attempt to ensure that -armdir and its subdirectories are read-only, changing existing modes if -necessary. If B<protect> is disabled, B<toast arm> will make B<armdir> +B<armdir> and its subdirectories are read-only, changing existing modes +if necessary. If B<protect> is disabled, B<toast arm> will make B<armdir> and its subdirectories read-write, assuming the current umask allows it. This option never affects the permissions of files or symbolic links. +Default: enabled. +=item S<B<--relative>> | B<--norelative>> + +If B<relative> is enabled, symbolic links created by B<toast arm> +will use canonical relative paths computed from the actual layout of +the filesystem when the command runs. If B<relative> is disabled, +the target of each symbolic link will start with the absolute path to +B<storedir>, exactly as given on the command line (or configuration file +or whatnot), even if the resulting path is not canonical. A "canonical +path" means a path that follows the "real" filesystem layout without going +through any links. Both methods should work just fine except in unusual +situations, so feel free to use whichever setting you think looks nicer. +This option only affects newly-created links, never existing links, even +when an existing link is moved to change the stacking order of a package. +Default: disabled. + =item S<B<--debugrewrite> | B<--nodebugrewrite>> If B<debugrewrite> is enabled, B<toast build> will always generate broken @@ -5810,6 +5891,7 @@ Known bugs: + - Berkeley/Sleepycat DB is broken again - autofind hangs in httphead() when going through tinyproxy? - autofind mishandles http redirects (e.g. http://toastball.net/toast) - gtk+ doesn't seem to build properly when it is already armed