@@ -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 )