[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / tools / gacutil / driver.cs
blob47c4ac8df96bd44da12af6c98d5309da235cbc89
1 //
2 // Mono.Tools.GacUtil
3 //
4 // Author(s):
5 // Todd Berman <tberman@sevenl.net>
6 // Jackson Harper <jackson@ximian.com>
7 //
8 // Copyright 2003, 2004 Todd Berman
9 // Copyright 2004 Novell, Inc (http://www.novell.com)
13 using System;
14 using System.IO;
15 using System.Diagnostics;
16 using System.Text;
17 using System.Collections;
18 using System.Globalization;
19 using System.Runtime.InteropServices;
20 using System.Security.Cryptography;
22 using Mono.Security;
23 using Mono.Security.Cryptography;
25 using IKVM.Reflection;
27 namespace Mono.Tools {
29 public class Driver {
31 private enum Command {
32 Unknown,
33 Install,
34 InstallFromList,
35 Uninstall,
36 UninstallFromList,
37 UninstallSpecific,
38 List,
39 Help
42 private enum VerificationResult
44 StrongNamed,
45 WeakNamed,
46 DelaySigned,
47 Skipped
50 private static bool silent;
51 static bool in_bootstrap;
52 private static Universe _universe;
54 public static int Main (string [] args)
56 if (args.Length == 0)
57 Usage ();
59 Command command = Command.Unknown;
60 string command_str = null;
62 string libdir;
63 string name, package, gacdir, root;
64 name = package = root = gacdir = null;
65 bool check_refs = false;
67 // Check for silent arg first so we can suppress
68 // warnings during command line parsing
69 if (Array.IndexOf (args, "/silent") > -1 || Array.IndexOf (args, "-silent") > -1)
70 silent = true;
72 for (int i=0; i<args.Length; i++) {
73 if (IsSwitch (args [i])) {
75 // for cmd line compatibility with other gacutils
76 // we always force it though
77 if (args [i] == "-f" || args [i] == "/f")
78 continue;
80 // Ignore this option for now, although we might implement it someday
81 if (args [i] == "/r") {
82 WriteLine ("WARNING: gacutil does not support traced references." +
83 "This option is being ignored.");
84 i += 3;
85 continue;
88 // This is already handled we just dont want to choke on it
89 if (args [i] == "-silent" || args [i] == "/silent")
90 continue;
92 if (args [i] == "-check_refs" || args [i] == "/check_refs") {
93 check_refs = true;
94 continue;
97 if (args [i] == "-bootstrap" || args [i] == "/bootstrap") {
98 in_bootstrap = true;
99 continue;
102 if (command == Command.Unknown) {
103 command = GetCommand (args [i]);
104 if (command != Command.Unknown) {
105 command_str = args [i];
106 continue;
110 if (i + 1 >= args.Length) {
111 Console.WriteLine ("Option " + args [i] + " takes 1 argument");
112 return 1;
115 switch (args [i]) {
116 case "-package":
117 case "/package":
118 package = args [++i];
119 continue;
120 case "-root":
121 case "/root":
122 root = args [++i];
123 continue;
124 case "-gacdir":
125 case "/gacdir":
126 gacdir = args [++i];
127 continue;
128 case "/nologo":
129 case "-nologo":
130 // we currently don't display a
131 // logo banner, so ignore it
132 // for command-line compatibility
133 // with MS gacutil
134 continue;
137 if (name == null)
138 name = args [i];
139 else
140 name += args [i];
143 if (command == Command.Unknown && IsSwitch (args [0])) {
144 Console.WriteLine ("Unknown command: " + args [0]);
145 return 1;
146 } else if (command == Command.Unknown) {
147 Usage ();
148 } else if (command == Command.Help) {
149 ShowHelp (true);
150 return 1;
153 if (gacdir == null) {
154 gacdir = GetGacDir ();
155 libdir = GetLibDir ();
156 } else {
157 gacdir = EnsureLib (gacdir);
158 libdir = Path.Combine (gacdir, "mono");
159 gacdir = Path.Combine (libdir, "gac");
162 string link_gacdir = gacdir;
163 string link_libdir = libdir;
164 if (root != null) {
165 libdir = Path.Combine (root, "mono");
166 gacdir = Path.Combine (libdir, "gac");
169 LoadConfig (silent);
171 switch (command) {
172 case Command.Install:
173 if (name == null) {
174 WriteLine ("Option " + command_str + " takes 1 argument");
175 return 1;
177 if (!Install (check_refs, name, package, gacdir, link_gacdir, libdir, link_libdir))
178 return 1;
179 break;
180 case Command.InstallFromList:
181 if (name == null) {
182 WriteLine ("Option " + command_str + " takes 1 argument");
183 return 1;
185 if (!InstallFromList (check_refs, name, package, gacdir, link_gacdir, libdir, link_libdir))
186 return 1;
187 break;
188 case Command.Uninstall:
189 if (name == null) {
190 WriteLine ("Option " + command_str + " takes 1 argument");
191 return 1;
193 int uninstallCount = 0;
194 int uninstallFailures = 0;
195 Uninstall (name, package, gacdir, libdir, false,
196 ref uninstallCount, ref uninstallFailures);
197 WriteLine ("Assemblies uninstalled = {0}", uninstallCount);
198 WriteLine ("Failures = {0}", uninstallFailures);
199 if (uninstallFailures > 0)
200 return 1;
201 break;
202 case Command.UninstallFromList:
203 if (name == null) {
204 WriteLine ("Option " + command_str + " takes 1 argument");
205 return 1;
207 if (!UninstallFromList (name, package, gacdir, libdir))
208 return 1;
209 break;
210 case Command.UninstallSpecific:
211 if (name == null) {
212 WriteLine ("Option " + command_str + " takes 1 argument");
213 return 1;
215 if (!UninstallSpecific (name, package, gacdir, libdir))
216 return 1;
217 break;
218 case Command.List:
219 List (name, gacdir);
220 break;
223 return 0;
226 static void Copy (string source, string target, bool v)
228 try {
229 File.Delete (target);
230 } catch {}
231 File.Copy (source, target, v);
234 private static bool Install (bool check_refs, string name, string package,
235 string gacdir, string link_gacdir, string libdir, string link_libdir)
237 string failure_msg = "Failure adding assembly {0} to the cache: ";
238 ArrayList resources;
240 if (!File.Exists (name)) {
241 WriteLine (string.Format (failure_msg, name) + "The system cannot find the file specified.");
242 return false;
245 Assembly assembly = null;
246 AssemblyName an = null;
248 try {
249 assembly = ReflectionOnlyLoadFrom (name);
250 } catch {
251 WriteLine (string.Format (failure_msg, name) + "The file specified is not a valid assembly.");
252 return false;
255 an = assembly.GetName ();
257 switch (VerifyStrongName (an, name)) {
258 case VerificationResult.StrongNamed:
259 case VerificationResult.Skipped:
260 break;
261 case VerificationResult.WeakNamed:
262 WriteLine (string.Format (failure_msg, name) + "Attempt to install an assembly without a strong name"
263 + (in_bootstrap ? "(continuing anyway)" : string.Empty));
264 if (!in_bootstrap)
265 return false;
266 break;
267 case VerificationResult.DelaySigned:
268 WriteLine (string.Format (failure_msg, name) + "Strong name cannot be verified for delay-signed assembly"
269 + (in_bootstrap ? "(continuing anyway)" : string.Empty));
270 if (!in_bootstrap)
271 return false;
272 break;
275 resources = new ArrayList ();
276 foreach (string res_name in assembly.GetManifestResourceNames ()) {
277 ManifestResourceInfo res_info = assembly.GetManifestResourceInfo (res_name);
279 if ((res_info.ResourceLocation & ResourceLocation.Embedded) == 0) {
280 if (!File.Exists (res_info.FileName)) {
281 WriteLine (string.Format (failure_msg, name) + "The system cannot find resource " + res_info.FileName);
282 return false;
285 resources.Add (res_info);
289 if (check_refs && !CheckReferencedAssemblies (an)) {
290 WriteLine (string.Format (failure_msg, name) +
291 "Attempt to install an assembly that " +
292 "references non strong named assemblies " +
293 "with -check_refs enabled.");
294 return false;
297 string [] siblings = { ".config", ".mdb" };
298 string version_token = an.Version + "_" +
299 an.CultureInfo.Name.ToLower (CultureInfo.InvariantCulture) + "_" +
300 GetStringToken (an.GetPublicKeyToken ());
301 string full_path = Path.Combine (Path.Combine (gacdir, an.Name), version_token);
302 string asmb_file = Path.GetFileName (name);
303 string asmb_path = Path.Combine (full_path, asmb_file);
304 string asmb_name = assembly.GetName ().Name;
306 if (Path.GetFileNameWithoutExtension (asmb_file) != asmb_name) {
307 WriteLine (string.Format (failure_msg, name) +
308 string.Format ("the filename \"{0}\" doesn't match the assembly name \"{1}\"",
309 asmb_file, asmb_name));
310 return false;
313 try {
314 if (Directory.Exists (full_path)) {
315 // Wipe out the directory. This way we ensure old assemblies
316 // config files, and AOTd files are removed.
317 Directory.Delete (full_path, true);
319 Directory.CreateDirectory (full_path);
320 } catch {
321 WriteLine (string.Format (failure_msg, name) +
322 "gac directories could not be created, " +
323 "possibly permission issues.");
324 return false;
327 Copy (name, asmb_path, true);
329 var name_pdb = Path.ChangeExtension (name, ".pdb");
330 if (File.Exists (name_pdb)) {
331 Copy (name_pdb, Path.ChangeExtension (asmb_path, ".pdb"), true);
334 foreach (string ext in siblings) {
335 string sibling = String.Concat (name, ext);
336 if (File.Exists (sibling))
337 Copy (sibling, String.Concat (asmb_path, ext), true);
340 foreach (ManifestResourceInfo resource_info in resources) {
341 try {
342 Copy (resource_info.FileName, Path.Combine (full_path, Path.GetFileName (resource_info.FileName)), true);
343 } catch {
344 WriteLine ("ERROR: Could not install resource file " + resource_info.FileName);
345 Environment.Exit (1);
349 if (package != null) {
350 string ref_dir = Path.Combine (libdir, package);
351 string ref_path = Path.Combine (ref_dir, asmb_file);
353 if (File.Exists (ref_path))
354 File.Delete (ref_path);
355 try {
356 Directory.CreateDirectory (ref_dir);
357 } catch {
358 WriteLine ("ERROR: Could not create package dir file.");
359 Environment.Exit (1);
361 if (Path.DirectorySeparatorChar == '/') {
362 string pkg_path_abs = Path.Combine (gacdir, Path.Combine (an.Name, Path.Combine (version_token, asmb_file)));
363 string pkg_path = AbsoluteToRelativePath (ref_dir, pkg_path_abs);
364 symlink (pkg_path, ref_path);
366 var pdb_pkg_path = Path.ChangeExtension (pkg_path, ".pdb");
367 var pdb_ref_path = Path.ChangeExtension (ref_path, ".pdb");
369 if (File.Exists (pdb_pkg_path)) {
370 symlink (pdb_pkg_path, pdb_ref_path);
371 } else {
372 try {
373 File.Delete (pdb_ref_path);
374 } catch {
375 // Ignore error, just delete files that should not be there.
379 foreach (string ext in siblings) {
380 string sibling = String.Concat (pkg_path, ext);
381 string sref = String.Concat (ref_path, ext);
383 if (File.Exists (sibling))
384 symlink (sibling, sref);
385 else {
386 try {
387 File.Delete (sref);
388 } catch {
389 // Ignore error, just delete files that should not be there.
393 WriteLine ("Package exported to: {0} -> {1}", ref_path, pkg_path);
394 } else {
395 // string link_path = Path.Combine (Path.Combine (link_gacdir, an.Name), version_token);
397 // We can't use 'link_path' here, since it need not be a valid path at the time 'gacutil'
398 // is run, esp. when invoked in a DESTDIR install.
399 Copy (name, ref_path, true);
400 WriteLine ("Package exported to: " + ref_path);
404 WriteLine ("Installed {0} into the gac ({1})", name,
405 gacdir);
407 return true;
410 //from MonoDevelop.Core.FileService
411 unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath)
413 if (!Path.IsPathRooted (absPath) || string.IsNullOrEmpty (baseDirectoryPath))
414 return absPath;
416 absPath = Path.GetFullPath (absPath);
417 baseDirectoryPath = Path.GetFullPath (baseDirectoryPath).TrimEnd (Path.DirectorySeparatorChar);
419 fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) {
420 var bEnd = bPtr + baseDirectoryPath.Length;
421 var aEnd = aPtr + absPath.Length;
422 char* lastStartA = aEnd;
423 char* lastStartB = bEnd;
425 int indx = 0;
426 // search common base path
427 var a = aPtr;
428 var b = bPtr;
429 while (a < aEnd) {
430 if (*a != *b)
431 break;
432 if (IsSeparator (*a)) {
433 indx++;
434 lastStartA = a + 1;
435 lastStartB = b;
437 a++;
438 b++;
439 if (b >= bEnd) {
440 if (a >= aEnd || IsSeparator (*a)) {
441 indx++;
442 lastStartA = a + 1;
443 lastStartB = b;
445 break;
448 if (indx == 0)
449 return absPath;
451 if (lastStartA >= aEnd)
452 return ".";
454 // handle case a: some/path b: some/path/deeper...
455 if (a >= aEnd) {
456 if (IsSeparator (*b)) {
457 lastStartA = a + 1;
458 lastStartB = b;
462 // look how many levels to go up into the base path
463 int goUpCount = 0;
464 while (lastStartB < bEnd) {
465 if (IsSeparator (*lastStartB))
466 goUpCount++;
467 lastStartB++;
469 var size = goUpCount * 2 + goUpCount + aEnd - lastStartA;
470 var result = new char [size];
471 fixed (char* rPtr = result) {
472 // go paths up
473 var r = rPtr;
474 for (int i = 0; i < goUpCount; i++) {
475 *(r++) = '.';
476 *(r++) = '.';
477 *(r++) = Path.DirectorySeparatorChar;
479 // copy the remaining absulute path
480 while (lastStartA < aEnd)
481 *(r++) = *(lastStartA++);
483 return new string (result);
487 static bool IsSeparator (char ch)
489 return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar;
492 private static void Uninstall (string name, string package, string gacdir, string libdir, bool listMode, ref int uninstalled, ref int failures)
494 string [] assembly_pieces = name.Split (new char[] { ',' });
495 Hashtable asm_info = new Hashtable ();
497 foreach (string item in assembly_pieces) {
498 if (item == String.Empty) continue;
499 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
500 if(pieces.Length == 1)
501 asm_info ["assembly"] = pieces [0];
502 else
503 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
506 string assembly_name = (string) asm_info ["assembly"];
507 string asmdir = Path.Combine (gacdir, assembly_name);
508 if (!Directory.Exists (asmdir)) {
509 if (listMode) {
510 failures++;
511 WriteLine ("Assembly: " + name);
513 WriteLine ("No assemblies found that match: " + name);
514 return;
517 string searchString = GetSearchString (asm_info);
518 string [] directories = Directory.GetDirectories (asmdir, searchString);
520 if (directories.Length == 0) {
521 if (listMode) {
522 failures++;
523 WriteLine ("Assembly: " + name);
524 WriteLine ("No assemblies found that match: " + name);
526 return;
529 for (int i = 0; i < directories.Length; i++) {
530 if (listMode && i > 0)
531 break;
533 string dir = directories [i];
534 string extension = null;
536 if (File.Exists (Path.Combine (dir, assembly_name + ".dll"))) {
537 extension = ".dll";
538 } else if (File.Exists (Path.Combine (dir, assembly_name + ".exe"))) {
539 extension = ".exe";
540 } else {
541 failures++;
542 WriteLine("Cannot find the assembly: " + assembly_name);
543 continue;
546 string assembly_filename = assembly_name + extension;
548 AssemblyName an = AssemblyName.GetAssemblyName (
549 Path.Combine (dir, assembly_filename));
550 WriteLine ("Assembly: " + an.FullName);
552 Directory.Delete (dir, true);
553 if (package != null) {
554 string link_dir = Path.Combine (libdir, package);
555 string link = Path.Combine (link_dir, assembly_filename);
557 try {
558 File.Delete (link);
559 } catch {
560 // The file might not exist, happens with
561 // the debugger on make uninstall
564 if (Directory.GetFiles (link_dir).Length == 0) {
565 WriteLine ("Cleaning package directory, it is empty.");
566 try {
567 Directory.Delete (link_dir);
568 } catch {
569 // Workaround: GetFiles does not list Symlinks
574 uninstalled++;
575 WriteLine ("Uninstalled: " + an.FullName);
578 if (Directory.GetDirectories (asmdir).Length == 0) {
579 WriteLine ("Cleaning assembly dir, it is empty");
580 try {
581 Directory.Delete (asmdir);
582 } catch {
583 // Workaround: GetFiles does not list Symlinks
588 private static bool UninstallSpecific (string name, string package,
589 string gacdir, string libdir)
591 string failure_msg = "Failure to remove assembly from the cache: ";
593 if (!File.Exists (name)) {
594 WriteLine (failure_msg + "The system cannot find the file specified.");
595 return false;
598 AssemblyName an = null;
600 try {
601 an = AssemblyName.GetAssemblyName (name);
602 } catch {
603 WriteLine (failure_msg + "The file specified is not a valid assembly.");
604 return false;
607 int uninstallCount = 0;
608 int uninstallFailures = 0;
609 Uninstall (an.FullName.Replace (" ", String.Empty),
610 package, gacdir, libdir, true, ref uninstallCount,
611 ref uninstallFailures);
612 WriteLine ("Assemblies uninstalled = {0}", uninstallCount);
613 WriteLine ("Failures = {0}", uninstallFailures);
614 return (uninstallFailures == 0);
617 private static void List (string name, string gacdir)
619 WriteLine ("The following assemblies are installed into the GAC:");
621 if (name != null) {
622 FilteredList (name, gacdir);
623 return;
626 int count = 0;
627 DirectoryInfo gacinfo = new DirectoryInfo (gacdir);
628 foreach (DirectoryInfo parent in gacinfo.GetDirectories ()) {
629 foreach (DirectoryInfo dir in parent.GetDirectories ()) {
630 string asmb = Path.Combine (Path.Combine (parent.FullName, dir.Name), parent.Name) + ".dll";
631 if (File.Exists (asmb)) {
632 WriteLine (AsmbNameFromVersionString (parent.Name, dir.Name));
633 count++;
637 WriteLine ("Number of items = " + count);
640 private static void FilteredList (string name, string gacdir)
642 string [] assembly_pieces = name.Split (new char[] { ',' });
643 Hashtable asm_info = new Hashtable ();
645 foreach (string item in assembly_pieces) {
646 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
647 if(pieces.Length == 1)
648 asm_info ["assembly"] = pieces [0];
649 else
650 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
653 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
654 if (!Directory.Exists (asmdir)) {
655 WriteLine ("Number of items = 0");
656 return;
658 string search = GetSearchString (asm_info);
659 string [] dir_list = Directory.GetDirectories (asmdir, search);
661 int count = 0;
662 foreach (string dir in dir_list) {
663 string asmb = Path.Combine (dir, (string) asm_info ["assembly"]) + ".dll";
664 if (File.Exists (asmb)) {
665 WriteLine (AsmbNameFromVersionString ((string) asm_info ["assembly"],
666 new DirectoryInfo (dir).Name));
667 count++;
670 WriteLine ("Number of items = " + count);
673 private static bool InstallFromList (bool check_refs, string list_file, string package,
674 string gacdir, string link_gacdir, string libdir, string link_libdir)
676 StreamReader s = null;
677 int processed, failed;
678 string listdir = Path.GetDirectoryName (
679 Path.GetFullPath (list_file));
681 processed = failed = 0;
683 try {
684 s = new StreamReader (list_file);
686 string line;
687 while ((line = s.ReadLine ()) != null) {
688 string file = line.Trim ();
689 if (file.Length == 0)
690 continue;
692 string assemblyPath = Path.Combine (listdir,
693 file);
695 if (!Install (check_refs, assemblyPath, package, gacdir,
696 link_gacdir, libdir, link_libdir))
697 failed++;
698 processed++;
701 WriteLine ("Assemblies processed = {0}", processed);
702 WriteLine ("Assemblies installed = {0}", processed - failed);
703 WriteLine ("Failures = {0}", failed);
705 return (failed == 0);
706 } catch (IOException) {
707 WriteLine ("Failed to open assemblies list file " + list_file + ".");
708 return false;
709 } finally {
710 if (s != null)
711 s.Close ();
715 private static bool UninstallFromList (string list_file, string package,
716 string gacdir, string libdir)
718 StreamReader s = null;
719 int failed, uninstalled;
721 failed = uninstalled = 0;
723 try {
724 s = new StreamReader (list_file);
726 string line;
727 while ((line = s.ReadLine ()) != null) {
728 string name = line.Trim ();
729 if (name.Length == 0)
730 continue;
731 Uninstall (line, package, gacdir, libdir,
732 true, ref uninstalled, ref failed);
735 WriteLine ("Assemblies processed = {0}", uninstalled+failed);
736 WriteLine ("Assemblies uninstalled = {0}", uninstalled);
737 WriteLine ("Failures = {0}", failed);
739 return (failed == 0);
740 } catch (IOException) {
741 WriteLine ("Failed to open assemblies list file " + list_file + ".");
742 return false;
743 } finally {
744 if (s != null)
745 s.Close ();
749 private static Universe GetUniverse () {
750 if (_universe == null) {
751 _universe = new Universe (UniverseOptions.MetadataOnly);
753 return _universe;
756 private static Assembly ReflectionOnlyLoadFrom (string fileName)
758 return GetUniverse ().LoadFile (fileName);
760 private static AssemblyName GetCorlibName ()
762 return GetUniverse ().Mscorlib.GetName ();
765 private static bool CheckReferencedAssemblies (AssemblyName an)
767 try {
768 Assembly a = ReflectionOnlyLoadFrom (an.CodeBase);
769 AssemblyName corlib = GetCorlibName ();
771 foreach (AssemblyName ref_an in a.GetReferencedAssemblies ()) {
772 if (ref_an.Name == corlib.Name) // Just do a string compare so we can install on diff versions
773 continue;
774 byte [] pt = ref_an.GetPublicKeyToken ();
775 if (pt == null || pt.Length == 0) {
776 WriteLine ("Assembly " + ref_an.Name + " is not strong named.");
777 return false;
780 } catch (Exception e) {
781 WriteLine (e.ToString ()); // This should be removed pre beta3
782 return false;
785 return true;
788 private static string GetSearchString (Hashtable asm_info)
790 if (asm_info.Keys.Count == 1)
791 return "*";
792 string version, culture, token;
794 version = asm_info ["version"] as string;
795 version = (version == null ? "*" : version + "*");
796 culture = asm_info ["culture"] as string;
797 culture = (culture == null ? "*" : (culture == "neutral") ? String.Empty : culture.ToLower (CultureInfo.InvariantCulture));
798 token = asm_info ["publickeytoken"] as string;
799 token = (token == null ? "*" : token.ToLower (CultureInfo.InvariantCulture));
801 return String.Format ("{0}_{1}_{2}", version, culture, token);
804 private static string AsmbNameFromVersionString (string name, string str)
806 string [] pieces = str.Split ('_');
807 return String.Format ("{0}, Version={1}, Culture={2}, PublicKeyToken={3}",
808 name, pieces [0], (pieces [1] == String.Empty ? "neutral" : pieces [1]),
809 pieces [2]);
812 static bool LoadConfig (bool quiet)
814 System.Reflection.MethodInfo config = typeof (System.Environment).GetMethod ("GetMachineConfigPath",
815 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
817 if (config != null) {
818 string path = (string) config.Invoke (null, null);
820 bool exist = File.Exists (path);
821 if (!quiet && !exist)
822 Console.WriteLine ("Couldn't find machine.config");
824 StrongNameManager.LoadConfig (path);
825 return exist;
826 } else if (!quiet)
827 Console.WriteLine ("Couldn't resolve machine.config location (corlib issue)");
829 // default CSP
830 return false;
833 // modified copy from sn
834 private static VerificationResult VerifyStrongName (AssemblyName an, string assemblyFile)
836 byte [] publicKey = StrongNameManager.GetMappedPublicKey (an.GetPublicKeyToken ());
837 if ((publicKey == null) || (publicKey.Length < 12)) {
838 // no mapping
839 publicKey = an.GetPublicKey ();
840 if ((publicKey == null) || (publicKey.Length < 12))
841 return VerificationResult.WeakNamed;
844 // Note: MustVerify is based on the original token (by design). Public key
845 // remapping won't affect if the assembly is verified or not.
846 if (StrongNameManager.MustVerify (new System.Reflection.AssemblyName (an.FullName))) {
847 RSA rsa = CryptoConvert.FromCapiPublicKeyBlob (publicKey, 12);
848 StrongName sn = new StrongName (rsa);
849 if (sn.Verify (assemblyFile)) {
850 return VerificationResult.StrongNamed;
851 } else {
852 return VerificationResult.DelaySigned;
854 } else {
855 return VerificationResult.Skipped;
859 private static bool IsSwitch (string arg)
861 return (arg [0] == '-' || (arg [0] == '/' && !arg.EndsWith (".dll") && !arg.EndsWith (".exe") && arg.IndexOf ('/', 1) < 0 ) );
864 private static Command GetCommand (string arg)
866 Command c = Command.Unknown;
868 switch (arg) {
869 case "-i":
870 case "/i":
871 case "--install":
872 c = Command.Install;
873 break;
874 case "-il":
875 case "/il":
876 case "--install-from-list":
877 c = Command.InstallFromList;
878 break;
879 case "-u":
880 case "/u":
881 case "/uf":
882 case "--uninstall":
883 c = Command.Uninstall;
884 break;
885 case "-ul":
886 case "/ul":
887 case "--uninstall-from-list":
888 c = Command.UninstallFromList;
889 break;
890 case "-us":
891 case "/us":
892 case "--uninstall-specific":
893 c = Command.UninstallSpecific;
894 break;
895 case "-l":
896 case "/l":
897 case "--list":
898 c = Command.List;
899 break;
900 case "-?":
901 case "/?":
902 case "--help":
903 c = Command.Help;
904 break;
906 return c;
909 [DllImport ("libc", SetLastError=true)]
910 public static extern int symlink (string oldpath, string newpath);
912 private static string GetGacDir () {
913 System.Reflection.PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
914 System.Reflection.BindingFlags.Static|System.Reflection.BindingFlags.NonPublic);
915 if (gac == null) {
916 WriteLine ("ERROR: Mono runtime not detected, please use " +
917 "the mono runtime for gacutil.exe");
918 Environment.Exit (1);
920 System.Reflection.MethodInfo get_gac = gac.GetGetMethod (true);
921 return (string) get_gac.Invoke (null, null);
924 private static string GetLibDir () {
925 System.Reflection.MethodInfo libdir = typeof (System.Environment).GetMethod ("internalGetGacPath",
926 System.Reflection.BindingFlags.Static|System.Reflection.BindingFlags.NonPublic);
927 if (libdir == null) {
928 WriteLine ("ERROR: Mono runtime not detected, please use " +
929 "the mono runtime for gacutil.exe");
930 Environment.Exit (1);
932 return Path.Combine ((string)libdir.Invoke (null, null), "mono");
935 private static string GetStringToken (byte[] tok)
937 StringBuilder sb = new StringBuilder ();
938 for (int i = 0; i < tok.Length ; i++)
939 sb.Append (tok[i].ToString ("x2"));
940 return sb.ToString ();
943 private static string EnsureLib (string dir)
945 DirectoryInfo d = new DirectoryInfo (dir);
946 if (d.Name == "lib")
947 return dir;
948 return Path.Combine (dir, "lib");
951 private static void WriteLine ()
953 if (silent)
954 return;
955 Console.WriteLine ();
958 private static void WriteLine (string line)
960 if (silent)
961 return;
962 Console.WriteLine (line);
965 private static void WriteLine (string line, params object [] p)
967 if (silent)
968 return;
969 Console.WriteLine (line, p);
972 private static void Usage ()
974 ShowHelp (false);
975 Environment.Exit (1);
978 private static void ShowHelp (bool detailed)
980 WriteLine ("Usage: gacutil.exe <commands> [ <options> ]");
981 WriteLine ("Commands:");
983 WriteLine ("-i <assembly_path> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
984 WriteLine ("\tInstalls an assembly into the global assembly cache.");
985 if (detailed) {
986 WriteLine ("\t<assembly_path> is the name of the file that contains the " +
987 "\tassembly manifest\n" +
988 "\tExample: -i myDll.dll");
990 WriteLine ();
992 WriteLine ("-il <assembly_list_file> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
993 WriteLine ("\tInstalls one or more assemblies into the global assembly cache.");
994 if (detailed) {
995 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
996 "\tassembly file paths on separate lines.\n" +
997 "\tExample -il assembly_list.txt\n" +
998 "\t\tassembly_list.txt contents:\n" +
999 "\t\tassembly1.dll\n" +
1000 "\t\tassembly2.dll");
1002 WriteLine ();
1004 WriteLine ("-u <assembly_display_name> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1005 WriteLine ("\tUninstalls an assembly from the global assembly cache.");
1006 if (detailed) {
1007 WriteLine ("\t<assembly_display_name> is the name of the assembly (partial or\n" +
1008 "\tfully qualified) to remove from the global assembly cache. If a \n" +
1009 "\tpartial name is specified all matching assemblies will be uninstalled.\n" +
1010 "\tExample: -u myDll,Version=1.2.1.0");
1012 WriteLine ();
1014 WriteLine ("-ul <assembly_list_file> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1015 WriteLine ("\tUninstalls one or more assemblies from the global assembly cache.");
1016 if (detailed) {
1017 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
1018 "\tassembly names on separate lines.\n" +
1019 "\tExample -ul assembly_list.txt\n" +
1020 "\t\tassembly_list.txt contents:\n" +
1021 "\t\tassembly1,Version=1.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef\n" +
1022 "\t\tassembly2,Version=2.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef");
1024 WriteLine ();
1026 WriteLine ("-us <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1027 WriteLine ("\tUninstalls an assembly using the specifed assemblies full name.");
1028 if (detailed) {
1029 WriteLine ("\t<assembly path> is the path to an assembly. The full assembly name\n" +
1030 "\tis retrieved from the specified assembly if there is an assembly in\n" +
1031 "\tthe GAC with a matching name, it is removed.\n" +
1032 "\tExample: -us myDll.dll");
1034 WriteLine ();
1036 WriteLine ("-l [assembly_name] [-root ROOTDIR] [-gacdir GACDIR]");
1037 WriteLine ("\tLists the contents of the global assembly cache.");
1038 if (detailed) {
1039 WriteLine ("\tWhen the <assembly_name> parameter is specified only matching\n" +
1040 "\tassemblies are listed.");
1042 WriteLine ();
1044 WriteLine ("-?");
1045 WriteLine ("\tDisplays a detailed help screen");
1046 WriteLine ();
1048 if (!detailed)
1049 return;
1051 WriteLine ("Options:");
1052 WriteLine ("-package <NAME>");
1053 WriteLine ("\tUsed to create a directory in prefix/lib/mono with the name NAME, and a\n" +
1054 "\tsymlink is created from NAME/assembly_name to the assembly on the GAC.\n" +
1055 "\tThis is used so developers can reference a set of libraries at once.");
1056 WriteLine ();
1058 WriteLine ("-gacdir <GACDIR>");
1059 WriteLine ("\tUsed to specify the GACs base directory. Once an assembly has been installed\n" +
1060 "\tto a non standard gacdir the MONO_GAC_PREFIX environment variable must be used\n" +
1061 "\tto access the assembly.");
1062 WriteLine ();
1064 WriteLine ("-root <ROOTDIR>");
1065 WriteLine ("\tUsed by developers integrating this with automake tools or packaging tools\n" +
1066 "\tthat require a prefix directory to be specified. The root represents the\n" +
1067 "\t\"libdir\" component of a prefix (typically prefix/lib).");
1068 WriteLine ();
1070 WriteLine ("-check_refs");
1071 WriteLine ("\tUsed to ensure that the assembly being installed into the GAC does not\n" +
1072 "\treference any non strong named assemblies. Assemblies being installed to\n" +
1073 "\tthe GAC should not reference non strong named assemblies, however the is\n" +
1074 "\tan optional check.");
1076 WriteLine ();
1077 WriteLine ("Ignored Options:");
1078 WriteLine ("-f");
1079 WriteLine ("\tThe Mono gacutil ignores the -f option to maintain commandline compatibility with");
1080 WriteLine ("\tother gacutils. gacutil will always force the installation of a new assembly.");
1082 WriteLine ();
1083 WriteLine ("-r <reference_scheme> <reference_id> <description>");
1084 WriteLine ("\tThe Mono gacutil has not implemented traced references and will emit a warning");
1085 WriteLine ("\twhen this option is used.");