Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Make LinkedResource actually useful #132

Open
wants to merge 2 commits into from

3 participants

Kasper Fabæch Brandt Ivan Muzzolini Jb Evain
Kasper Fabæch Brandt

LinkedResource currently isn't very useful. You cannot set the name in the file table except by specifying the actual path the hash is calculated from.
Unless you change your current working directory to the directory of the assembly, you have to specify the full path to the resource, resulting in that full path being recorded in the assembly - which is definitely never what you want, and breaks terribly if you ever try to deploy such an assembly.
Otherwise if you specify a path that doesn't exists when writing the file you end up with an empty hash. This makes sn.exe (the strong name tool) unable to recalculate the hash as no space is reserved in the assembly.

These changes attempts to fix that by letting the user explicitly specify the name in the file table independently of the file path and the resource name, as well as letting the user specify the hash to be delay calculated (fills in a zero hash) as well as explicitly specifying the hash.

poizan42 added some commits
Kasper Fabæch Brandt poizan42 Make LinkedResource actually useful; allow specifying how to calculat…
…e hash, explicitly setting file name of resource in assembly and allow for delay calculated hash using e.g. sn.exe -Ra
d9fb914
Kasper Fabæch Brandt poizan42 More LinkedResource improvements:
Invalidate old data when HashSource / File is changed.
Detect delay hashed linked resources when reading assembly.
8f6622e
Kasper Fabæch Brandt

Hey @jbevain could I persuade you into taking a quick look at this? I'm trying to create that piece of "external automation" mentioned in this System.Data.SQLite issue, but I would rather not have to maintain my own fork just for that - and it would probably improve my chances of convincing them to use that for the official builds.

Ivan Muzzolini

I just want to vote for poizan42 proposal. I am having the same problem!

Jb Evain
Owner

I'll have a look, thanks for reporting the issue!

Kasper Fabæch Brandt

Uhm bump? Anything I can do to have this merged?

Kasper Fabæch Brandt

@jbevain or anyone else with push access?

Kasper Fabæch Brandt

Bump?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 30, 2013
  1. Kasper Fabæch Brandt

    Make LinkedResource actually useful; allow specifying how to calculat…

    poizan42 authored
    …e hash, explicitly setting file name of resource in assembly and allow for delay calculated hash using e.g. sn.exe -Ra
  2. Kasper Fabæch Brandt

    More LinkedResource improvements:

    poizan42 authored
    Invalidate old data when HashSource / File is changed.
    Detect delay hashed linked resources when reading assembly.
This page is out of date. Refresh to see the latest.
27 Mono.Cecil/AssemblyReader.cs
View
@@ -627,12 +627,27 @@ public Collection<Resource> ReadResources ()
Assembly = (AssemblyNameReference) GetTypeReferenceScope (implementation),
};
} else if (implementation.TokenType == TokenType.File) {
- var file_record = ReadFileRecord (implementation.RID);
-
- resource = new LinkedResource (name, flags) {
- File = file_record.Col2,
- hash = ReadBlob (file_record.Col3)
- };
+ var file_record = ReadFileRecord (implementation.RID);
+
+ var hash = ReadBlob(file_record.Col3);
+ var linkedRes = new LinkedResource (name, flags) {
+ ResourceFileName = file_record.Col2,
+ };
+ resource = linkedRes;
+ bool explicitHash = true;
+ if (hash.Length == 20) {
+ explicitHash = false;
+ foreach (byte b in hash) {
+ if (b != 0) {
+ explicitHash = true;
+ break;
+ }
+ }
+ }
+ if (explicitHash)
+ linkedRes.Hash = hash;
+ else
+ linkedRes.HashSource = LinkedResourceHashSource.Delay;
} else
throw new NotSupportedException ();
12 Mono.Cecil/AssemblyWriter.cs
View
@@ -1002,15 +1002,15 @@ void AddResources ()
uint AddLinkedResource (LinkedResource resource)
{
- var table = GetTable<FileTable> (Table.File);
-
- var hash = resource.Hash.IsNullOrEmpty ()
- ? CryptoService.ComputeHash (resource.File)
- : resource.Hash;
+ var table = GetTable<FileTable> (Table.File);
+
+ if (resource.HashSource == LinkedResourceHashSource.File)
+ resource.UseCurrentFileHash();
+ var hash = resource.Hash;
return (uint) table.AddRow (new FileRow (
FileAttributes.ContainsNoMetaData,
- GetStringIndex (resource.File),
+ GetStringIndex (resource.ResourceFileName),
GetBlobIndex (hash)));
}
138 Mono.Cecil/LinkedResource.cs
View
@@ -24,37 +24,149 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-namespace Mono.Cecil {
-
- public sealed class LinkedResource : Resource {
+//
+
+using System.IO;
+using System;
+namespace Mono.Cecil {
+
+ /// <summary>
+ /// Specifies how to calculate the hash of a linked resource.
+ /// </summary>
+ public enum LinkedResourceHashSource {
+ /// <summary>
+ /// The hash is calculated from the file specified in the File property of the LinkedResource.
+ /// </summary>
+ File,
+ /// <summary>
+ /// The hash is not calculated, but space is reserved in the assembly for later calculation with a tool such as sn.exe.
+ /// </summary>
+ Delay,
+ /// <summary>
+ /// The hash is explicitly provided.
+ /// </summary>
+ Explicit }
- internal byte [] hash;
- string file;
+ public sealed class LinkedResource : Resource {
+
+ private byte[] hash;
+ private string file;
+ private string resourceFileName;
+ private LinkedResourceHashSource hashSource;
+ private DateTime fileTime;
+
+ private void CalculateHash()
+ {
+ if (hashSource == LinkedResourceHashSource.File) {
+ try {
+ //Ensure Write+Delete lock on file.
+ using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) {
+ DateTime lastWriteTime = System.IO.File.GetLastWriteTimeUtc(file);
+ if (hash == null || lastWriteTime > fileTime) {
+ fileTime = lastWriteTime;
+ hash = CryptoService.ComputeHash(file);
+ }
+ }
+ }
+ catch (FileNotFoundException e) {
+ throw new FileNotFoundException("Cannot calculate hash for nonexistant file.", file, e);
+ }
+ }
+ else if (hash == null && hashSource == LinkedResourceHashSource.Delay)
+ hash = new byte[20];
+ }
- public byte [] Hash {
- get { return hash; }
+ /// <summary>
+ /// Returns the current hash value. Modifying the returned array is undefined unless hashSource is
+ /// LinkedResourceHashSource.Explicit.
+ /// </summary>
+ public byte[] Hash {
+ get {
+ CalculateHash();
+ return hash;
+ }
+ set {
+ hashSource = LinkedResourceHashSource.Explicit;
+ hash = value;
+ }
}
+ /// <summary>
+ /// The file path to calculate the hash from. Only used when HashSource == LinkedResourceHashSource.File.
+ /// Setting this value will force HashSource to LinkedResourceHashSource.File.
+ /// </summary>
public string File {
get { return file; }
- set { file = value; }
- }
+ set {
+ if (value == file)
+ return;
+ file = value;
+ hash = null;
+ hashSource = LinkedResourceHashSource.File;
+ }
+ }
+
+ public string ResourceFileName {
+ get { return resourceFileName; }
+ set { resourceFileName = value; }
+ }
+
+ public LinkedResourceHashSource HashSource {
+ get { return hashSource; }
+ set {
+ if (value == hashSource)
+ return;
+ if (value != LinkedResourceHashSource.Explicit)
+ hash = null;
+ hashSource = value;
+ }
+ }
public override ResourceType ResourceType {
get { return ResourceType.Linked; }
+ }
+
+ /// <summary>
+ /// Calculate the hash of the specified file right now instead of delaying until assembly write.
+ /// The HashSource will get changed to LinkedResourceHashSource.Explicit.
+ /// </summary>
+ /// <param name="fileName">The file to calculate hash from. Uses the current File if not specified.</param>
+ public void UseCurrentFileHash(string fileName = null)
+ {
+ if (fileName != null)
+ File = fileName;
+ hashSource = LinkedResourceHashSource.File;
+ CalculateHash();
+ hashSource = LinkedResourceHashSource.Explicit;
+ }
+
+ public LinkedResource (string name, ManifestResourceAttributes flags)
+ : base (name, flags)
+ {
+ this.resourceFileName = name;
+ this.hashSource = LinkedResourceHashSource.Delay;
+ }
+
+ public LinkedResource (string name, ManifestResourceAttributes flags, string resourceFileName, byte[] hash)
+ : base (name, flags)
+ {
+ this.resourceFileName = name;
+ this.hash = hash;
+ this.hashSource = LinkedResourceHashSource.Explicit;
}
- public LinkedResource (string name, ManifestResourceAttributes flags)
+ public LinkedResource (string name, ManifestResourceAttributes flags, string resourceFileName, LinkedResourceHashSource hashSource)
: base (name, flags)
{
+ this.resourceFileName = resourceFileName;
+ this.hashSource = hashSource;
}
public LinkedResource (string name, ManifestResourceAttributes flags, string file)
: base (name, flags)
{
- this.file = file;
+ this.file = file;
+ this.resourceFileName = Path.GetFileName(file);
}
}
}
Something went wrong with that request. Please try again.