/*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
//
// Create an (empty) builder
//
-CodeDirectory::Builder::Builder()
- : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mDir(NULL)
+CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm)
+ : mFlags(0),
+ mHashType(digestAlgorithm),
+ mSpecialSlots(0),
+ mCodeSlots(0),
+ mScatter(NULL),
+ mScatterSize(0),
+ mDir(NULL)
{
- memset(mSpecial, 0, sizeof(mSpecial));
+ mDigestLength = MakeHash<Builder>(this)->digestLength();
+ mSpecial = (unsigned char *)calloc(cdSlotMax, mDigestLength);
+}
+
+CodeDirectory::Builder::~Builder()
+{
+ ::free(mSpecial);
+ ::free(mScatter);
}
//
// Set the source for one special slot
//
-void CodeDirectory::Builder::special(size_t slot, CFDataRef data)
+void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data)
{
assert(slot <= cdSlotMax);
- Hash hash;
- hash(CFDataGetBytePtr(data), CFDataGetLength(data));
- hash.finish(mSpecial[slot]);
+ MakeHash<Builder> hash(this);
+ hash->update(CFDataGetBytePtr(data), CFDataGetLength(data));
+ hash->finish(specialSlot(slot));
if (slot >= mSpecialSlots)
mSpecialSlots = slot;
}
+//
+// Allocate a Scatter vector
+//
+CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count)
+{
+ mScatterSize = (count + 1) * sizeof(Scatter);
+ if (!(mScatter = (Scatter *)::realloc(mScatter, mScatterSize)))
+ UnixError::throwMe(ENOMEM);
+ ::memset(mScatter, 0, mScatterSize);
+ return mScatter;
+}
+
+
+//
+// Calculate the size we'll need for the CodeDirectory as described so far
+//
size_t CodeDirectory::Builder::size()
{
assert(mExec); // must have called executable()
}
size_t offset = sizeof(CodeDirectory);
+ offset += mScatterSize; // scatter vector
offset += mIdentifier.size() + 1; // size of identifier (with null byte)
- offset += (mCodeSlots + mSpecialSlots) * Hash::digestLength; // hash vector
+ offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector
return offset;
}
//
// Take everything added to date and wrap it up in a shiny new CodeDirectory.
//
-// Note that this doesn't include or generate the signature. You're free to
-// modify the result. But this function determines the memory layout, so the
-// sizes and counts should be correct on entry.
+// Note that this only constructs a CodeDirectory; it does not touch any subsidiary
+// structures (resource tables, etc.), nor does it create any signature to secure
+// the CodeDirectory.
+// The returned CodeDirectory object is yours, and you may modify it as desired.
+// But the memory layout is set here, so the various sizes and counts should be good
+// when you call build().
+// It's up to us to order the dynamic fields as we wish; but note that we currently
+// don't pad them, and so they should be allocated in non-increasing order of required
+// alignment. Make sure to keep the code here in sync with the size-calculating code above.
//
CodeDirectory *CodeDirectory::Builder::build()
{
mDir->nSpecialSlots = mSpecialSlots;
mDir->nCodeSlots = mCodeSlots;
mDir->codeLimit = mExecLength;
- mDir->hashSize = Hash::digestLength;
- mDir->hashType = cdHashTypeDefault;
+ mDir->hashType = mHashType;
+ mDir->hashSize = mDigestLength;
if (mPageSize) {
int pglog;
assert(frexp(mPageSize, &pglog) == 0.5); // must be power of 2
// locate and fill flex fields
size_t offset = sizeof(CodeDirectory);
+
+ if (mScatter) {
+ mDir->scatterOffset = offset;
+ memcpy(mDir->scatterVector(), mScatter, mScatterSize);
+ offset += mScatterSize;
+ }
+
mDir->identOffset = offset;
memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
offset += identLength;
// (add new flexibly-allocated fields here)
- mDir->hashOffset = offset + mSpecialSlots * Hash::digestLength;
- offset += (mSpecialSlots + mCodeSlots) * Hash::digestLength;
+ mDir->hashOffset = offset + mSpecialSlots * mDigestLength;
+ offset += (mSpecialSlots + mCodeSlots) * mDigestLength;
assert(offset == total); // matches allocated size
// fill special slots
- memset((*mDir)[-mSpecialSlots], 0, mDir->hashSize * mSpecialSlots);
+ memset((*mDir)[-mSpecialSlots], 0, mDigestLength * mSpecialSlots);
for (size_t slot = 1; slot <= mSpecialSlots; ++slot)
- memcpy((*mDir)[-slot], &mSpecial[slot], Hash::digestLength);
+ memcpy((*mDir)[-slot], specialSlot(slot), mDigestLength);
// fill code slots
mExec.seek(mExecOffset);
size_t remaining = mExecLength;
for (unsigned int slot = 0; slot < mCodeSlots; ++slot) {
size_t thisPage = min(mPageSize, remaining);
- hash(mExec, (*mDir)[slot], thisPage);
+ MakeHash<Builder> hasher(this);
+ generateHash(hasher, mExec, (*mDir)[slot], thisPage);
remaining -= thisPage;
}