@@ -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 )
0 commit comments