Пример #1
0
        public void Save(bool autoHandleDependencies = false)
        {
            lock (this) {
                if (_manifest != null)
                {
                    _pendingChanges = _manifest.Modified || _pendingChanges;
                }
                // Logger.Message("Saving Binary '{0}' : Pending Changes: {1} ", _filename, _pendingChanges);
                if (_pendingChanges)
                {
                    // saves any changes made to the binary.
                    // work on a back up of the file
                    var tmpFilename = _filename.CreateWritableWorkingCopy();

                    try {
                        // remove any digital signatures from the binary before doing anything
                        if (!IsManaged)
                        {
                            StripSignatures(tmpFilename); // this is irrelevant if the binary is managed--we'll be writing out a new one.
                        }
                        // rewrite any native resources that we want to change.

                        if (IsManaged && ILOnly)
                        {
                            // we can only edit the file if it's IL only, mixed mode assemblies can only be strong named, signed and native-resource-edited.
                            // set the strong name key data
                            MutableAssembly.PublicKey = StrongNameKey.ToList();

                            // change any assembly attributes we need to change
                            if (MutableAssembly != null)
                            {
                                if (StrongNameKeyCertificate != null)
                                {
                                    foreach (var ar in MutableAssembly.AssemblyReferences)
                                    {
                                        if (!ar.PublicKeyToken.Any())
                                        {
                                            var dep = FindAssembly(ar.Name.Value, ar.Version.ToString());
                                            if (dep == null)
                                            {
                                                // can't strong name a file that doesn't have its deps all strong named.
                                                throw new ClrPlusException("dependent assembly '{0}-{1}' not available for strong naming".format(ar.Name.Value, ar.Version.ToString()));
                                            }

                                            lock (dep) {
                                                // this should wait until the dependency is finished saving, right?
                                            }

                                            if (dep.MutableAssembly.PublicKey.IsNullOrEmpty())
                                            {
                                                if (autoHandleDependencies)
                                                {
                                                    Console.WriteLine(
                                                        "Warning: Non-strong-named dependent reference found: '{0}-{1}' updating with same strong-name-key.",
                                                        ar.Name, ar.Version);
                                                    dep.StrongNameKeyCertificate = StrongNameKeyCertificate;
                                                    dep.SigningCertificate       = SigningCertificate;

                                                    dep.AssemblyCopyright = AssemblyCopyright;
                                                    dep.AssemblyCompany   = AssemblyCompany;
                                                    dep.AssemblyProduct   = AssemblyProduct;

                                                    dep.Save();
                                                }
                                                else
                                                {
                                                    throw new ClrPlusException("dependent assembly '{0}-{1}' not strong named".format(ar.Name.Value, ar.Version.ToString()));
                                                }
                                            }
                                            (ar as Microsoft.Cci.MutableCodeModel.AssemblyReference).PublicKeyToken = dep.MutableAssembly.PublicKeyToken.ToList();
                                            (ar as Microsoft.Cci.MutableCodeModel.AssemblyReference).PublicKey      = dep.MutableAssembly.PublicKey;
                                        }
                                    }
                                }

                                // we should see if we can get assembly attributes, since sometimes they can be set, but not the native ones.
                                try {
                                    foreach (var a in MutableAssembly.AssemblyAttributes)
                                    {
                                        var attributeArgument = (a.Arguments.FirstOrDefault() as MetadataConstant);
                                        if (attributeArgument != null)
                                        {
                                            var attributeName = a.Type.ToString();
                                            switch (attributeName)
                                            {
                                            case "System.Reflection.AssemblyTitleAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyTitle) ? string.Empty : AssemblyTitle;
                                                break;

                                            case "System.Reflection.AssemblyDescriptionAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyDescription) ? string.Empty : AssemblyDescription;
                                                break;

                                            case "System.Reflection.AssemblyCompanyAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyCompany) ? string.Empty : AssemblyCompany;
                                                break;

                                            case "System.Reflection.AssemblyProductAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyProduct) ? string.Empty : AssemblyProduct;
                                                break;

                                            case "System.Reflection.AssemblyVersionAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyVersion) ? string.Empty : AssemblyVersion;
                                                break;

                                            case "System.Reflection.AssemblyFileVersionAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyFileVersion) ? string.Empty : AssemblyFileVersion;
                                                break;

                                            case "System.Reflection.AssemblyCopyrightAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyCopyright) ? string.Empty : AssemblyCopyright;
                                                break;

                                            case "System.Reflection.AssemblyTrademarkAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(AssemblyTrademark) ? string.Empty : AssemblyTrademark;
                                                break;

                                            case "BugTrackerAttribute":
                                                attributeArgument.Value = string.IsNullOrEmpty(BugTracker) ? string.Empty : BugTracker;
                                                break;
                                            }
                                        }
                                    }
                                } catch {
                                    // hmm. carry on.
                                }
                            }

                            // save it to disk
                            using (var peStream = File.Create(tmpFilename)) {
                                PeWriter.WritePeToStream(MutableAssembly, _host, peStream);
                            }
                        }

                        // update native metadata
                        try {
                            var ri = new ResourceInfo();

                            ri.Load(tmpFilename);

                            if (_manifest != null && _manifest.Modified)
                            {
                                // GS01: We only support one manifest right now.
                                // so we're gonna remove the extra ones.
                                // figure out the bigger case later.
                                var manifestKeys = ri.Resources.Keys.Where(each => each.ResourceType == ResourceTypes.RT_MANIFEST).ToArray();
                                foreach (var k in manifestKeys)
                                {
                                    ri.Resources.Remove(k);
                                }

                                var manifestResource = new ManifestResource();
                                manifestResource.ManifestText = _manifest.ToString();
                                ri.Resources.Add(new ResourceId(ResourceTypes.RT_MANIFEST), new List <Resource> {
                                    manifestResource
                                });
                                manifestResource.SaveTo(tmpFilename);
                            }

                            VersionResource versionResource;
                            StringTable     versionStringTable;

                            var versionKey = ri.Resources.Keys.Where(each => each.ResourceType == ResourceTypes.RT_VERSION).FirstOrDefault();
                            if (versionKey != null)
                            {
                                versionResource    = ri.Resources[versionKey].First() as VersionResource;
                                versionStringTable = (versionResource["StringFileInfo"] as StringFileInfo).Strings.Values.First();
                            }
                            else
                            {
                                versionResource = new VersionResource();
                                ri.Resources.Add(new ResourceId(ResourceTypes.RT_VERSION), new List <Resource> {
                                    versionResource
                                });

                                var sfi = new StringFileInfo();
                                versionResource["StringFileInfo"] = sfi;
                                sfi.Strings["040904b0"]           = (versionStringTable = new StringTable("040904b0"));

                                var vfi = new VarFileInfo();
                                versionResource["VarFileInfo"] = vfi;
                                var translation = new VarTable("Translation");
                                vfi.Vars["Translation"] = translation;
                                translation[0x0409]     = 0x04b0;
                            }

                            versionResource.FileVersion    = FileVersion;
                            versionResource.ProductVersion = ProductVersion;

                            versionStringTable["ProductName"]      = ProductName;
                            versionStringTable["CompanyName"]      = CompanyName;
                            versionStringTable["FileDescription"]  = FileDescription;
                            versionStringTable["Comments"]         = _comments;
                            versionStringTable["Assembly Version"] = _assemblyVersion;
                            versionStringTable["FileVersion"]      = _fileVersion;
                            versionStringTable["ProductVersion"]   = _productVersion;
                            versionStringTable["InternalName"]     = _internalName;
                            versionStringTable["OriginalFilename"] = _originalFilename;
                            versionStringTable["LegalCopyright"]   = _legalCopyright;
                            versionStringTable["LegalTrademarks"]  = _legalTrademarks;
                            versionStringTable["BugTracker"]       = _bugTracker;

                            versionResource.SaveTo(tmpFilename);
                        } catch (Exception e) {
                            Console.WriteLine("{0} -- {1}", e.Message, e.StackTrace);
                        }

                        // strong name the binary
                        if (IsManaged && StrongNameKeyCertificate != null && (StrongNameKeyCertificate.Certificate.PrivateKey is RSACryptoServiceProvider))
                        {
                            ApplyStrongName(tmpFilename, StrongNameKeyCertificate);
                        }

                        // sign the binary
                        if (_signingCertificate != null)
                        {
                            SignFile(tmpFilename, SigningCertificate.Certificate);
                        }

                        _filename.TryHardToDelete();
                        File.Move(tmpFilename, _filename);
                    } catch (Exception e) {
#if TODO
                        Logger.Error(e);
#endif
                        // get rid of whatever we tried
                        tmpFilename.TryHardToDelete();

                        // as you were...
                        throw;
                    }
                }
                _pendingChanges = false;
                if (_manifest != null)
                {
                    _manifest.Modified = false;
                }
            }
        }