[gacutil] Create correct relative package symlinks
authorMichael Hutchinson <m.j.hutchinson@gmail.com>
Wed, 26 Feb 2014 00:28:41 +0000 (19:28 -0500)
committerMichael Hutchinson <m.j.hutchinson@gmail.com>
Wed, 26 Feb 2014 00:32:25 +0000 (19:32 -0500)
BXC17951 - broken softlinks in mono/xbuild/12.0/bin

mcs/tools/gacutil/Makefile
mcs/tools/gacutil/driver.cs

index 5fdea99a02f7b6c3a538b2bca1d5dbebb3c29d56..878830f124886cd0723c47115b443a2f065003ac 100644 (file)
@@ -2,7 +2,7 @@ thisdir = tools/gacutil
 SUBDIRS = 
 include ../../build/rules.make
 
-LOCAL_MCS_FLAGS = -r:Mono.Security.dll 
+LOCAL_MCS_FLAGS = -r:Mono.Security.dll -unsafe
 
 PROGRAM = gacutil.exe
 
index d94fce0d462a3c253858220d7c80f35c3d3834a1..3446b6f74c0afdbc912a571af8cb900b089945f8 100644 (file)
@@ -352,7 +352,8 @@ namespace Mono.Tools {
                                        Environment.Exit (1);
                                }
                                if (Path.DirectorySeparatorChar == '/') {
-                                       string pkg_path = "../gac/" + an.Name + "/" + version_token + "/" + asmb_file;
+                                       string pkg_path_abs = Path.Combine (gacdir, Path.Combine (an.Name, Path.Combine (version_token, asmb_file)));
+                                       string pkg_path = AbsoluteToRelativePath (ref_dir, pkg_path_abs);
                                        symlink (pkg_path, ref_path);
 
                                        foreach (string ext in siblings) {
@@ -385,6 +386,88 @@ namespace Mono.Tools {
                        return true;
                }
 
+               //from MonoDevelop.Core.FileService
+               unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath)
+               {
+                       if (!Path.IsPathRooted (absPath) || string.IsNullOrEmpty (baseDirectoryPath))
+                               return absPath;
+
+                       absPath = Path.GetFullPath (absPath);
+                       baseDirectoryPath = Path.GetFullPath (baseDirectoryPath).TrimEnd (Path.DirectorySeparatorChar);
+
+                       fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) {
+                               var bEnd = bPtr + baseDirectoryPath.Length;
+                               var aEnd = aPtr + absPath.Length;
+                               char* lastStartA = aEnd;
+                               char* lastStartB = bEnd;
+
+                               int indx = 0;
+                               // search common base path
+                               var a = aPtr;
+                               var b = bPtr;
+                               while (a < aEnd) {
+                                       if (*a != *b)
+                                               break;
+                                       if (IsSeparator (*a)) {
+                                               indx++;
+                                               lastStartA = a + 1;
+                                               lastStartB = b;
+                                       }
+                                       a++;
+                                       b++;
+                                       if (b >= bEnd) {
+                                               if (a >= aEnd || IsSeparator (*a)) {
+                                                       indx++;
+                                                       lastStartA = a + 1;
+                                                       lastStartB = b;
+                                               }
+                                               break;
+                                       }
+                               }
+                               if (indx == 0)
+                                       return absPath;
+
+                               if (lastStartA >= aEnd)
+                                       return ".";
+
+                               // handle case a: some/path b: some/path/deeper...
+                               if (a >= aEnd) {
+                                       if (IsSeparator (*b)) {
+                                               lastStartA = a + 1;
+                                               lastStartB = b;
+                                       }
+                               }
+
+                               // look how many levels to go up into the base path
+                               int goUpCount = 0;
+                               while (lastStartB < bEnd) {
+                                       if (IsSeparator (*lastStartB))
+                                               goUpCount++;
+                                       lastStartB++;
+                               }
+                               var size = goUpCount * 2 + goUpCount + aEnd - lastStartA;
+                               var result = new char [size];
+                               fixed (char* rPtr = result) {
+                                       // go paths up
+                                       var r = rPtr;
+                                       for (int i = 0; i < goUpCount; i++) {
+                                               *(r++) = '.';
+                                               *(r++) = '.';
+                                               *(r++) = Path.DirectorySeparatorChar;
+                                       }
+                                       // copy the remaining absulute path
+                                       while (lastStartA < aEnd)
+                                               *(r++) = *(lastStartA++);
+                               }
+                               return new string (result);
+                       }
+               }
+
+               static bool IsSeparator (char ch)
+               {
+                       return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar;
+               }
+
                private static void Uninstall (string name, string package, string gacdir, string libdir, bool listMode, ref int uninstalled, ref int failures)
                {
                        string [] assembly_pieces = name.Split (new char[] { ',' });