@@ -801,6 +801,56 @@ namecheck(const char *name)
801
801
return componentcheck (name ,component ,cp );
802
802
}
803
803
804
+ /*
805
+ * Create symlink contents suitable for symlinking FROM to TO, as a
806
+ * freshly allocated string. FROM should be a relative file name, and
807
+ * is relative to the global variable DIRECTORY. TO can be either
808
+ * relative or absolute.
809
+ */
810
+ #ifdef HAVE_SYMLINK
811
+ static char *
812
+ relname (char const * from ,char const * to )
813
+ {
814
+ size_t i ,
815
+ taillen ,
816
+ dotdotetcsize ;
817
+ size_t dir_len = 0 ,
818
+ dotdots = 0 ,
819
+ linksize = SIZE_MAX ;
820
+ char const * f = from ;
821
+ char * result = NULL ;
822
+
823
+ if (* to == '/' )
824
+ {
825
+ /* Make F absolute too. */
826
+ size_t len = strlen (directory );
827
+ bool needslash = len && directory [len - 1 ]!= '/' ;
828
+
829
+ linksize = len + needslash + strlen (from )+ 1 ;
830
+ f = result = emalloc (linksize );
831
+ strcpy (result ,directory );
832
+ result [len ]= '/' ;
833
+ strcpy (result + len + needslash ,from );
834
+ }
835
+ for (i = 0 ;f [i ]&& f [i ]== to [i ];i ++ )
836
+ if (f [i ]== '/' )
837
+ dir_len = i + 1 ;
838
+ for (;f [i ];i ++ )
839
+ dotdots += f [i ]== '/' && f [i - 1 ]!= '/' ;
840
+ taillen = i - dir_len ;
841
+ dotdotetcsize = 3 * dotdots + taillen + 1 ;
842
+ if (dotdotetcsize <=linksize )
843
+ {
844
+ if (!result )
845
+ result = emalloc (dotdotetcsize );
846
+ for (i = 0 ;i < dotdots ;i ++ )
847
+ memcpy (result + 3 * i ,"../" ,3 );
848
+ memmove (result + 3 * dotdots ,f + dir_len ,taillen + 1 );
849
+ }
850
+ return result ;
851
+ }
852
+ #endif /* HAVE_SYMLINK */
853
+
804
854
static void
805
855
dolink (char const * fromfield ,char const * tofield ,bool staysymlink )
806
856
{
@@ -844,31 +894,17 @@ dolink(char const * fromfield, char const * tofield, bool staysymlink)
844
894
if (link_errno != 0 )
845
895
{
846
896
#ifdef HAVE_SYMLINK
847
- const char * s = fromfield ;
848
- const char * t ;
849
- char * p ;
850
- size_t dotdots = 0 ;
851
- char * symlinkcontents ;
852
- int symlink_errno ;
897
+ bool absolute = * fromfield == '/' ;
898
+ char * linkalloc = absolute ?NULL :relname (fromfield ,tofield );
899
+ char const * contents = absolute ?fromfield :linkalloc ;
900
+ int symlink_errno = symlink (contents ,tofield )== 0 ?0 :errno ;
853
901
854
- do
855
- t = s ;
856
- while ((s = strchr (s ,'/' ))
857
- && strncmp (fromfield ,tofield ,++ s - fromfield )== 0 );
858
-
859
- for (s = tofield + (t - fromfield );* s ;s ++ )
860
- dotdots += * s == '/' ;
861
- symlinkcontents = emalloc (3 * dotdots + strlen (t )+ 1 );
862
- for (p = symlinkcontents ;dotdots -- != 0 ;p += 3 )
863
- memcpy (p ,"../" ,3 );
864
- strcpy (p ,t );
865
- symlink_errno = symlink (symlinkcontents ,tofield )== 0 ?0 :errno ;
866
902
if (symlink_errno == ENOENT && !todirs_made )
867
903
{
868
904
mkdirs (tofield , true);
869
- symlink_errno = symlink (symlinkcontents ,tofield )== 0 ?0 :errno ;
905
+ symlink_errno = symlink (contents ,tofield )== 0 ?0 :errno ;
870
906
}
871
- free (symlinkcontents );
907
+ free (linkalloc );
872
908
if (symlink_errno == 0 )
873
909
{
874
910
if (link_errno != ENOTSUP )