@@ -789,6 +789,56 @@ namecheck(const char *name)
789
789
return componentcheck (name , component , cp );
790
790
}
791
791
792
+ /*
793
+ * Create symlink contents suitable for symlinking FROM to TO, as a
794
+ * freshly allocated string. FROM should be a relative file name, and
795
+ * is relative to the global variable DIRECTORY. TO can be either
796
+ * relative or absolute.
797
+ */
798
+ #ifdef HAVE_SYMLINK
799
+ static char *
800
+ relname (char const * from , char const * to )
801
+ {
802
+ size_t i ,
803
+ taillen ,
804
+ dotdotetcsize ;
805
+ size_t dir_len = 0 ,
806
+ dotdots = 0 ,
807
+ linksize = SIZE_MAX ;
808
+ char const * f = from ;
809
+ char * result = NULL ;
810
+
811
+ if (* to == '/' )
812
+ {
813
+ /* Make F absolute too. */
814
+ size_t len = strlen (directory );
815
+ bool needslash = len && directory [len - 1 ] != '/' ;
816
+
817
+ linksize = len + needslash + strlen (from ) + 1 ;
818
+ f = result = emalloc (linksize );
819
+ strcpy (result , directory );
820
+ result [len ] = '/' ;
821
+ strcpy (result + len + needslash , from );
822
+ }
823
+ for (i = 0 ; f [i ] && f [i ] == to [i ]; i ++ )
824
+ if (f [i ] == '/' )
825
+ dir_len = i + 1 ;
826
+ for (; f [i ]; i ++ )
827
+ dotdots += f [i ] == '/' && f [i - 1 ] != '/' ;
828
+ taillen = i - dir_len ;
829
+ dotdotetcsize = 3 * dotdots + taillen + 1 ;
830
+ if (dotdotetcsize <= linksize )
831
+ {
832
+ if (!result )
833
+ result = emalloc (dotdotetcsize );
834
+ for (i = 0 ; i < dotdots ; i ++ )
835
+ memcpy (result + 3 * i , "../" , 3 );
836
+ memmove (result + 3 * dotdots , f + dir_len , taillen + 1 );
837
+ }
838
+ return result ;
839
+ }
840
+ #endif /* HAVE_SYMLINK */
841
+
792
842
static void
793
843
dolink (char const * fromfield , char const * tofield , bool staysymlink )
794
844
{
@@ -832,31 +882,17 @@ dolink(char const * fromfield, char const * tofield, bool staysymlink)
832
882
if (link_errno != 0 )
833
883
{
834
884
#ifdef HAVE_SYMLINK
835
- const char * s = fromfield ;
836
- const char * t ;
837
- char * p ;
838
- size_t dotdots = 0 ;
839
- char * symlinkcontents ;
840
- int symlink_errno ;
885
+ bool absolute = * fromfield == '/' ;
886
+ char * linkalloc = absolute ? NULL : relname (fromfield , tofield );
887
+ char const * contents = absolute ? fromfield : linkalloc ;
888
+ int symlink_errno = symlink (contents , tofield ) == 0 ? 0 : errno ;
841
889
842
- do
843
- t = s ;
844
- while ((s = strchr (s , '/' ))
845
- && strncmp (fromfield , tofield , ++ s - fromfield ) == 0 );
846
-
847
- for (s = tofield + (t - fromfield ); * s ; s ++ )
848
- dotdots += * s == '/' ;
849
- symlinkcontents = emalloc (3 * dotdots + strlen (t ) + 1 );
850
- for (p = symlinkcontents ; dotdots -- != 0 ; p += 3 )
851
- memcpy (p , "../" , 3 );
852
- strcpy (p , t );
853
- symlink_errno = symlink (symlinkcontents , tofield ) == 0 ? 0 : errno ;
854
890
if (symlink_errno == ENOENT && !todirs_made )
855
891
{
856
892
mkdirs (tofield , true);
857
- symlink_errno = symlink (symlinkcontents , tofield ) == 0 ? 0 : errno ;
893
+ symlink_errno = symlink (contents , tofield ) == 0 ? 0 : errno ;
858
894
}
859
- free (symlinkcontents );
895
+ free (linkalloc );
860
896
if (symlink_errno == 0 )
861
897
{
862
898
if (link_errno != ENOTSUP )
0 commit comments