<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>hfs/hfscompress.c</filename>
    </added>
    <added>
      <filename>hfs/xattr.c</filename>
    </added>
    <added>
      <filename>includes/hfs/hfscompress.h</filename>
    </added>
    <added>
      <filename>includes/partial/firmwaremaster.h</filename>
    </added>
    <added>
      <filename>includes/partial/partial.h</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -232,6 +232,7 @@ size_t memFileWrite(AbstractFile* file, const void* data, size_t len) {
   }
   
   if((info-&gt;offset + (size_t)len) &gt; (*(info-&gt;bufferSize))) {
+		memset(((uint8_t*)(*(info-&gt;buffer))) + *(info-&gt;bufferSize), 0, (info-&gt;offset + (size_t)len) - *(info-&gt;bufferSize));
 		*(info-&gt;bufferSize) = info-&gt;offset + (size_t)len;
 	}
       </diff>
      <filename>common/abstractfile.c</filename>
    </modified>
    <modified>
      <diff>@@ -41,7 +41,7 @@ int main(int argc, char* argv[]) {
 	TestByteOrder();
 	
 	if(argc &lt; 4) {
-		printf(&quot;usage: %s [extract|build|iso|dmg] &lt;in&gt; &lt;out&gt; (-k &lt;key&gt;) (partition)\n&quot;, argv[0]);
+		printf(&quot;usage: %s [extract|build|build2048|res|iso|dmg] &lt;in&gt; &lt;out&gt; (-k &lt;key&gt;) (partition)\n&quot;, argv[0]);
 		return 0;
 	}
 
@@ -72,7 +72,11 @@ int main(int argc, char* argv[]) {
 		}
 		extractDmg(in, out, partNum);
 	} else if(strcmp(argv[1], &quot;build&quot;) == 0) {
-		buildDmg(in, out);
+		buildDmg(in, out, SECTOR_SIZE);
+	} else if(strcmp(argv[1], &quot;build2048&quot;) == 0) {
+		buildDmg(in, out, 2048);
+	} else if(strcmp(argv[1], &quot;res&quot;) == 0) {
+		outResources(in, out);
 	} else if(strcmp(argv[1], &quot;iso&quot;) == 0) {
 		convertToISO(in, out);
 	} else if(strcmp(argv[1], &quot;dmg&quot;) == 0) {</diff>
      <filename>dmg/dmg.c</filename>
    </modified>
    <modified>
      <diff>@@ -85,7 +85,7 @@ uint32_t calculateMasterChecksum(ResourceKey* resources) {
 	return result;  
 }
 
-int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {	
+int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, unsigned int BlockSize) {	
 	io_func* io;
 	Volume* volume;  
 	
@@ -127,15 +127,15 @@ int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	
 	printf(&quot;Creating and writing DDM and partition map...\n&quot;); fflush(stdout);
 	
-	DDM = createDriverDescriptorMap((volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE);
+	DDM = createDriverDescriptorMap((volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE, BlockSize);
 	
-	partitions = createApplePartitionMap((volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE, HFSX_VOLUME_TYPE);
+	partitions = createApplePartitionMap((volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE, HFSX_VOLUME_TYPE, BlockSize);
 	
-	writeDriverDescriptorMap(abstractOut, DDM, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources);
+	int pNum = writeDriverDescriptorMap(-1, abstractOut, DDM, BlockSize, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources);
 	free(DDM);
-	writeApplePartitionMap(abstractOut, partitions, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources, &amp;nsiz);
+	pNum = writeApplePartitionMap(pNum, abstractOut, partitions, BlockSize, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources, &amp;nsiz);
 	free(partitions);
-	writeATAPI(abstractOut, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources, &amp;nsiz);
+	pNum = writeATAPI(pNum, abstractOut, BlockSize, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources, &amp;nsiz);
 	
 	memset(&amp;uncompressedToken, 0, sizeof(uncompressedToken));
 	SHA1Init(&amp;(uncompressedToken.sha1));
@@ -144,15 +144,16 @@ int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	
 	abstractIn-&gt;seek(abstractIn, 0);
 	blkx = insertBLKX(abstractOut, abstractIn, USER_OFFSET, (volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE,
-				2, CHECKSUM_CRC32, &amp;BlockSHA1CRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, volume);
+				pNum, CHECKSUM_CRC32, &amp;BlockSHA1CRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, volume, 1);
 	
 	blkx-&gt;checksum.data[0] = uncompressedToken.crc;
 	printf(&quot;Inserting main blkx...\n&quot;); fflush(stdout);
-	
-	resources = insertData(resources, &quot;blkx&quot;, 2, &quot;Mac_OS_X (Apple_HFSX : 3)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
+
+	char pName[100];
+	sprintf(pName, &quot;Mac_OS_X (Apple_HFSX : %d)&quot;, pNum + 1);	
+	resources = insertData(resources, &quot;blkx&quot;, pNum, pName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
 	free(blkx);
-	
-	
+
 	printf(&quot;Inserting cSum data...\n&quot;); fflush(stdout);
 	
 	csum.version = 1;
@@ -178,13 +179,20 @@ int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	if(nsiz == NULL) {
 		nsiz = myNSiz;
 	} else {
-		myNSiz-&gt;next = nsiz-&gt;next;
-		nsiz-&gt;next = myNSiz;
+		NSizResource* curNsiz = nsiz;
+		while(curNsiz-&gt;next != NULL)
+		{
+			curNsiz = curNsiz-&gt;next;
+		}
+		curNsiz-&gt;next = myNSiz;
 	}
 	
+	pNum++;
+
 	printf(&quot;Writing free partition...\n&quot;); fflush(stdout);
 	
-	writeFreePartition(abstractOut, (volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE, &amp;resources);
+	pNum = writeFreePartition(pNum, abstractOut, USER_OFFSET + (volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE, 
+			(FREE_SIZE + (BlockSize / SECTOR_SIZE / 2)) / (BlockSize / SECTOR_SIZE) * (BlockSize / SECTOR_SIZE), &amp;resources);
 	
 	dataForkChecksum = dataForkToken.crc;
 	
@@ -192,7 +200,7 @@ int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	curResource = resources;
 	while(curResource-&gt;next != NULL)
 		curResource = curResource-&gt;next;
-    
+
 	curResource-&gt;next = writeNSiz(nsiz);
 	curResource = curResource-&gt;next;
 	releaseNSiz(nsiz);
@@ -238,7 +246,8 @@ int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	printf(&quot;Master checksum: %x\n&quot;, koly.fUDIFMasterChecksum.data[0]); fflush(stdout); 
 	
 	koly.fUDIFImageVariant = kUDIFDeviceImageType;
-	koly.fUDIFSectorCount = EXTRA_SIZE + (volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE;
+	koly.fUDIFSectorCount = (volumeHeader-&gt;totalBlocks * volumeHeader-&gt;blockSize)/SECTOR_SIZE
+		+ ((EXTRA_SIZE + (BlockSize / SECTOR_SIZE / 2)) / (BlockSize / SECTOR_SIZE) * (BlockSize / SECTOR_SIZE));
 	koly.reserved2 = 0;
 	koly.reserved3 = 0;
 	koly.reserved4 = 0;
@@ -307,7 +316,7 @@ int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 	
 	if(DDM-&gt;sbSig == DRIVER_DESCRIPTOR_SIGNATURE) {
 		BlockSize = DDM-&gt;sbBlkSize;
-		writeDriverDescriptorMap(abstractOut, DDM, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources);
+		int pNum = writeDriverDescriptorMap(-1, abstractOut, DDM, BlockSize, &amp;CRCProxy, (void*) (&amp;dataForkToken), &amp;resources);
 		free(DDM);
 		
 		printf(&quot;Processing partition map...\n&quot;); fflush(stdout);
@@ -338,7 +347,7 @@ int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 			
 			abstractIn-&gt;seek(abstractIn, partitions[i].pmPyPartStart * BlockSize);
 			blkx = insertBLKX(abstractOut, abstractIn, partitions[i].pmPyPartStart, partitions[i].pmPartBlkCnt, i, CHECKSUM_CRC32,
-						&amp;BlockCRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, NULL);
+						&amp;BlockCRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, NULL, 1);
 			
 			blkx-&gt;checksum.data[0] = uncompressedToken.crc;	
 			resources = insertData(resources, &quot;blkx&quot;, i, partitionName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
@@ -379,7 +388,7 @@ int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut) {
 		
 		abstractIn-&gt;seek(abstractIn, 0);
 		blkx = insertBLKX(abstractOut, abstractIn, 0, fileLength/SECTOR_SIZE, ENTIRE_DEVICE_DESCRIPTOR, CHECKSUM_CRC32,
-					&amp;BlockCRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, NULL);
+					&amp;BlockCRC, &amp;uncompressedToken, &amp;CRCProxy, &amp;dataForkToken, NULL, 1);
 		resources = insertData(resources, &quot;blkx&quot;, 0, &quot;whole disk (unknown partition : 0)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
 		free(blkx);
 		</diff>
      <filename>dmg/dmglib.c</filename>
    </modified>
    <modified>
      <diff>@@ -8,9 +8,20 @@
 
 #define SECTORS_AT_A_TIME 0x200
 
+// Okay, this value sucks. You shouldn't touch it because it affects how many ignore sections get added to the blkx list
+// If the blkx list gets too fragmented with ignore sections, then the copy list in certain versions of the iPhone's
+// asr becomes too big. Due to Apple's BUGGY CODE, this causes asr to segfault! This is because the copy list becomes
+// too large for the initial buffer allocated, and realloc is called by asr. Unfortunately, after the realloc, the initial
+// pointer is still used by asr for a little while! Frakking noob mistake.
+
+// The only reason why it works at all is their really idiotic algorithm to determine where to put ignore blocks. It's
+// certainly nothing reasonable like &quot;put in an ignore block if you encounter more than X blank sectors&quot; (like mine)
+// There's always a large-ish one at the end, and a tiny 2 sector one at the end too, to take care of the space after
+// the backup volume header. No frakking clue how they go about determining how to do that.
+
 BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorNumber, uint32_t numSectors, uint32_t blocksDescriptor,
 			uint32_t checksumType, ChecksumFunc uncompressedChk, void* uncompressedChkToken, ChecksumFunc compressedChk,
-			void* compressedChkToken, Volume* volume) {
+			void* compressedChkToken, Volume* volume, int addComment) {
 	BLKXTable* blkx;
 	
 	uint32_t roomForRuns;
@@ -23,8 +34,9 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
 	size_t have;
 	int ret;
 	
-	z_stream strm;
-	
+	int IGNORE_THRESHOLD = 100000;
+
+	z_stream strm;	
 	
 	blkx = (BLKXTable*) malloc(sizeof(BLKXTable) + (2 * sizeof(BLKXRun)));
 	roomForRuns = 2;
@@ -56,6 +68,24 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
 	curRun = 0;
 	curSector = 0;
 	
+	uint64_t startOff = in-&gt;tell(in);
+
+	if(addComment)
+	{
+		blkx-&gt;runs[curRun].type = BLOCK_COMMENT;
+		blkx-&gt;runs[curRun].reserved = 0x2B626567;
+		blkx-&gt;runs[curRun].sectorStart = curSector;
+		blkx-&gt;runs[curRun].sectorCount = 0;
+		blkx-&gt;runs[curRun].compOffset = out-&gt;tell(out) - blkx-&gt;dataStart;
+		blkx-&gt;runs[curRun].compLength = 0;
+		curRun++;
+
+		if(curRun &gt;= roomForRuns) {
+			roomForRuns &lt;&lt;= 1;
+			blkx = (BLKXTable*) realloc(blkx, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
+		}
+	}
+
 	while(numSectors &gt; 0) {
 		if(curRun &gt;= roomForRuns) {
 			roomForRuns &lt;&lt;= 1;
@@ -72,11 +102,102 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
 		strm.zfree = Z_NULL;
 		strm.opaque = Z_NULL;
 		
+		int amountRead;
+		{
+			size_t sectorsToSkip = 0;
+			size_t processed = 0;
+
+			while(processed &lt; numSectors)
+			{
+				blkx-&gt;runs[curRun].sectorCount = ((numSectors - processed) &gt; SECTORS_AT_A_TIME) ? SECTORS_AT_A_TIME : (numSectors - processed);
+
+				//printf(&quot;Currently at %&quot; PRId64 &quot;\n&quot;, curOff);
+				in-&gt;seek(in, startOff + (blkx-&gt;sectorCount - numSectors + processed) * SECTOR_SIZE);
+				ASSERT((amountRead = in-&gt;read(in, inBuffer, blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE)) == (blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE), &quot;mRead&quot;);
+
+				if(!addComment)
+					break;
+
+				processed += amountRead / SECTOR_SIZE;
+
+				size_t* checkBuffer = (size_t*) inBuffer;
+				size_t counter;
+				size_t counter_max = amountRead / sizeof(size_t);
+				for(counter = 0; counter &lt; counter_max; counter++)
+				{
+					if(checkBuffer[counter] != 0) {
+						//printf(&quot;Not empty at %&quot; PRId64 &quot; / %&quot; PRId64 &quot;\n&quot;, (int64_t)(counter * sizeof(size_t)) + curOff, (int64_t)((counter * sizeof(size_t)) / SECTOR_SIZE + sectorsToSkip + blkx-&gt;runs[curRun].sectorStart));
+						break;
+					}
+				}
+
+				size_t skipInBuffer = (counter * sizeof(size_t)) / SECTOR_SIZE;
+				sectorsToSkip += skipInBuffer;
+
+				//printf(&quot;sectorsToSkip: %d\n&quot;, sectorsToSkip);
+
+				if(counter &lt; counter_max)
+				{
+					if(sectorsToSkip &gt; IGNORE_THRESHOLD)
+					{
+						//printf(&quot;Seeking back to %&quot; PRId64 &quot;\n&quot;, curOff + (skipInBuffer * SECTOR_SIZE));
+						//in-&gt;seek(in, curOff + (skipInBuffer * SECTOR_SIZE));
+					} else {
+						//printf(&quot;Breaking out: %d / %d\n&quot;, (size_t) counter, (size_t) counter_max);
+					}
+					break;
+				}
+			}
+
+			if(sectorsToSkip &gt; IGNORE_THRESHOLD)
+			{
+				int remainder = sectorsToSkip &amp; 0xf;
+
+				if(sectorsToSkip != remainder)
+				{
+					blkx-&gt;runs[curRun].type = BLOCK_IGNORE;
+					blkx-&gt;runs[curRun].reserved = 0;
+					blkx-&gt;runs[curRun].sectorStart = curSector;
+					blkx-&gt;runs[curRun].sectorCount = sectorsToSkip - remainder;
+					blkx-&gt;runs[curRun].compOffset = out-&gt;tell(out) - blkx-&gt;dataStart;
+					blkx-&gt;runs[curRun].compLength = 0;
+
+					printf(&quot;run %d: skipping sectors=%&quot; PRId64 &quot;, left=%d\n&quot;, curRun, (int64_t) sectorsToSkip, numSectors);
+
+					curSector += blkx-&gt;runs[curRun].sectorCount;
+					numSectors -= blkx-&gt;runs[curRun].sectorCount;
+
+					curRun++;
+				}
+
+				if(remainder &gt; 0)
+				{
+					blkx-&gt;runs[curRun].type = BLOCK_IGNORE;
+					blkx-&gt;runs[curRun].reserved = 0;
+					blkx-&gt;runs[curRun].sectorStart = curSector;
+					blkx-&gt;runs[curRun].sectorCount = remainder;
+					blkx-&gt;runs[curRun].compOffset = out-&gt;tell(out) - blkx-&gt;dataStart;
+					blkx-&gt;runs[curRun].compLength = 0;
+
+					printf(&quot;run %d: skipping sectors=%&quot; PRId64 &quot;, left=%d\n&quot;, curRun, (int64_t) sectorsToSkip, numSectors);
+
+					curSector += blkx-&gt;runs[curRun].sectorCount;
+					numSectors -= blkx-&gt;runs[curRun].sectorCount;
+
+					curRun++;
+				}
+
+				IGNORE_THRESHOLD = 0;
+				
+				continue;
+			}
+		}
+
 		printf(&quot;run %d: sectors=%&quot; PRId64 &quot;, left=%d\n&quot;, curRun, blkx-&gt;runs[curRun].sectorCount, numSectors);
+
+		ASSERT(deflateInit(&amp;strm, 1) == Z_OK, &quot;deflateInit&quot;);
 		
-		ASSERT(deflateInit(&amp;strm, Z_DEFAULT_COMPRESSION) == Z_OK, &quot;deflateInit&quot;);
-		
-		ASSERT((strm.avail_in = in-&gt;read(in, inBuffer, blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE)) == (blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE), &quot;mRead&quot;);
+		strm.avail_in = amountRead;
 		strm.next_in = inBuffer;
 		
 		if(uncompressedChk)
@@ -94,7 +215,7 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
 		}
 		have = bufferSize - strm.avail_out;
 		
-		if((have / SECTOR_SIZE) &gt; blkx-&gt;runs[curRun].sectorCount) {
+		if((have / SECTOR_SIZE) &gt;= (blkx-&gt;runs[curRun].sectorCount - 15)) {
 			blkx-&gt;runs[curRun].type = BLOCK_RAW;
 			ASSERT(out-&gt;write(out, inBuffer, blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE) == (blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE), &quot;fwrite&quot;);
 			blkx-&gt;runs[curRun].compLength += blkx-&gt;runs[curRun].sectorCount * SECTOR_SIZE;
@@ -122,7 +243,23 @@ BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorN
 		roomForRuns &lt;&lt;= 1;
 		blkx = (BLKXTable*) realloc(blkx, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
 	}
-	
+
+	if(addComment)
+	{	
+		blkx-&gt;runs[curRun].type = BLOCK_COMMENT;
+		blkx-&gt;runs[curRun].reserved = 0x2B656E64;
+		blkx-&gt;runs[curRun].sectorStart = curSector;
+		blkx-&gt;runs[curRun].sectorCount = 0;
+		blkx-&gt;runs[curRun].compOffset = out-&gt;tell(out) - blkx-&gt;dataStart;
+		blkx-&gt;runs[curRun].compLength = 0;
+		curRun++;
+
+		if(curRun &gt;= roomForRuns) {
+			roomForRuns &lt;&lt;= 1;
+			blkx = (BLKXTable*) realloc(blkx, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
+		}
+	}
+
 	blkx-&gt;runs[curRun].type = BLOCK_TERMINATOR;
 	blkx-&gt;runs[curRun].reserved = 0;
 	blkx-&gt;runs[curRun].sectorStart = curSector;</diff>
      <filename>dmg/io.c</filename>
    </modified>
    <modified>
      <diff>@@ -421,7 +421,7 @@ void flipPartitionMultiple(Partition* partition, char multiple, char out, unsign
 		FLIPENDIAN(partition-&gt;pmBootEntry);
 		FLIPENDIAN(partition-&gt;pmBootEntry2);
 		FLIPENDIAN(partition-&gt;pmBootCksum);
-		FLIPENDIAN(partition-&gt;bootCode);
+		FLIPENDIANLE(partition-&gt;bootCode);
 		
 		if(!multiple) {
 			break;
@@ -472,71 +472,87 @@ void readDriverDescriptorMap(AbstractFile* file, ResourceKey* resources) {
   free(buffer);
 }
 
-DriverDescriptorRecord* createDriverDescriptorMap(uint32_t numSectors) {
+DriverDescriptorRecord* createDriverDescriptorMap(uint32_t numSectors, unsigned int BlockSize) {
   DriverDescriptorRecord* toReturn;
   
-  toReturn = (DriverDescriptorRecord*) malloc(SECTOR_SIZE);
-  memset(toReturn, 0, SECTOR_SIZE);
+  toReturn = (DriverDescriptorRecord*) malloc(BlockSize);
+  memset(toReturn, 0, BlockSize);
   
   toReturn-&gt;sbSig = DRIVER_DESCRIPTOR_SIGNATURE;
-  toReturn-&gt;sbBlkSize = SECTOR_SIZE;
-  toReturn-&gt;sbBlkCount = numSectors + EXTRA_SIZE;
+  toReturn-&gt;sbBlkSize = BlockSize;
+  toReturn-&gt;sbBlkCount = (numSectors + EXTRA_SIZE + (BlockSize / SECTOR_SIZE / 2)) / (BlockSize / SECTOR_SIZE);
   toReturn-&gt;sbDevType = 0;
   toReturn-&gt;sbDevId = 0;
   toReturn-&gt;sbData = 0;
+/*
   toReturn-&gt;sbDrvrCount = 1;
-  toReturn-&gt;ddBlock = ATAPI_OFFSET;
+  toReturn-&gt;ddBlock = (ATAPI_OFFSET * SECTOR_SIZE) / BlockSize;
   toReturn-&gt;ddSize = 0x4;
   toReturn-&gt;ddType = 0x701;
+*/
+  toReturn-&gt;sbDrvrCount = 0;
+  toReturn-&gt;ddBlock = 0;
+  toReturn-&gt;ddSize = 0;
+  toReturn-&gt;ddType = 0;
 
   return toReturn;
 }
 
-void writeDriverDescriptorMap(AbstractFile* file, DriverDescriptorRecord* DDM, ChecksumFunc dataForkChecksum, void* dataForkToken,
+int writeDriverDescriptorMap(int pNum, AbstractFile* file, DriverDescriptorRecord* DDM, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken,
 				ResourceKey **resources) {
   AbstractFile* bufferFile;
   BLKXTable* blkx;
   ChecksumToken uncompressedToken;
   DriverDescriptorRecord* buffer;
   
-  buffer = (DriverDescriptorRecord*) malloc(DDM_SIZE * SECTOR_SIZE);
-  memcpy(buffer, DDM, DDM_SIZE * SECTOR_SIZE);
+  buffer = (DriverDescriptorRecord*) malloc(DDM_SIZE * BlockSize);
+  memcpy(buffer, DDM, DDM_SIZE * BlockSize);
   memset(&amp;uncompressedToken, 0, sizeof(uncompressedToken));
   
   flipDriverDescriptorRecord(buffer, TRUE);
 
-  bufferFile = createAbstractFileFromMemory((void**)&amp;buffer, DDM_SIZE * SECTOR_SIZE);
+  bufferFile = createAbstractFileFromMemory((void**)&amp;buffer, DDM_SIZE * BlockSize);
   
   blkx = insertBLKX(file, bufferFile, DDM_OFFSET, DDM_SIZE, DDM_DESCRIPTOR, CHECKSUM_CRC32, &amp;CRCProxy, &amp;uncompressedToken,
-			dataForkChecksum, dataForkToken, NULL);
+			dataForkChecksum, dataForkToken, NULL, 0);
               
   blkx-&gt;checksum.data[0] = uncompressedToken.crc;
   
-  *resources = insertData(*resources, &quot;blkx&quot;, -1, &quot;Driver Descriptor Map (DDM : 0)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
+  char pName[100];
+  sprintf(pName, &quot;Driver Descriptor Map (DDM : %d)&quot;, pNum + 1);	
+  *resources = insertData(*resources, &quot;blkx&quot;, pNum, pName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
   
   free(buffer);
   bufferFile-&gt;close(bufferFile);
   free(blkx);
+
+  pNum++;
+
+  if((DDM_SIZE * BlockSize / SECTOR_SIZE) - DDM_SIZE &gt; 0)
+    pNum = writeFreePartition(pNum, file, DDM_SIZE, (DDM_SIZE * BlockSize / SECTOR_SIZE) - DDM_SIZE, resources);
+
+  return pNum;
 }
 
-void writeApplePartitionMap(AbstractFile* file, Partition* partitions, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn) {
+int writeApplePartitionMap(int pNum, AbstractFile* file, Partition* partitions, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn) {
   AbstractFile* bufferFile;
   BLKXTable* blkx;
   ChecksumToken uncompressedToken;
   Partition* buffer;
   NSizResource* nsiz;
   CSumResource csum;
-  
-  buffer = (Partition*) malloc(PARTITION_SIZE * SECTOR_SIZE);
-  memcpy(buffer, partitions, PARTITION_SIZE  * SECTOR_SIZE);
+ 
+  size_t realPartitionSize = (PARTITION_SIZE * SECTOR_SIZE) / BlockSize * BlockSize; 
+  buffer = (Partition*) malloc(realPartitionSize);
+  memcpy(buffer, partitions, realPartitionSize);
   memset(&amp;uncompressedToken, 0, sizeof(uncompressedToken));
    
-  flipPartition(buffer, TRUE, SECTOR_SIZE);
+  flipPartition(buffer, TRUE, BlockSize);
 
-  bufferFile = createAbstractFileFromMemory((void**)&amp;buffer, PARTITION_SIZE * SECTOR_SIZE);
+  bufferFile = createAbstractFileFromMemory((void**)&amp;buffer, realPartitionSize);
    
-  blkx = insertBLKX(file, bufferFile, PARTITION_OFFSET, PARTITION_SIZE, 0, CHECKSUM_CRC32,
-              &amp;BlockCRC, &amp;uncompressedToken, dataForkChecksum, dataForkToken, NULL);
+  blkx = insertBLKX(file, bufferFile, PARTITION_OFFSET * BlockSize / SECTOR_SIZE, realPartitionSize / SECTOR_SIZE, pNum, CHECKSUM_CRC32,
+              &amp;BlockCRC, &amp;uncompressedToken, dataForkChecksum, dataForkToken, NULL, 0);
   
   bufferFile-&gt;close(bufferFile);
 
@@ -546,7 +562,9 @@ void writeApplePartitionMap(AbstractFile* file, Partition* partitions, ChecksumF
   csum.type = CHECKSUM_MKBLOCK;
   csum.checksum = uncompressedToken.block;
 
-  *resources = insertData(*resources, &quot;blkx&quot;, 0, &quot;Apple (Apple_partition_map : 1)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
+  char pName[100];
+  sprintf(pName, &quot;Apple (Apple_partition_map : %d)&quot;, pNum + 1);	
+  *resources = insertData(*resources, &quot;blkx&quot;, pNum, pName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
   *resources = insertData(*resources, &quot;cSum&quot;, 0, &quot;&quot;, (const char*) (&amp;csum), sizeof(csum), 0);
   
   nsiz = (NSizResource*) malloc(sizeof(NSizResource));
@@ -566,9 +584,11 @@ void writeApplePartitionMap(AbstractFile* file, Partition* partitions, ChecksumF
   
   free(buffer);
   free(blkx);
+
+  return pNum + 1;
 }
 
-void writeATAPI(AbstractFile* file, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn) {
+int writeATAPI(int pNum, AbstractFile* file, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn) {
   AbstractFile* bufferFile;
   BLKXTable* blkx;
   ChecksumToken uncompressedToken;
@@ -583,8 +603,16 @@ void writeATAPI(AbstractFile* file, ChecksumFunc dataForkChecksum, void* dataFor
   memcpy(atapi, atapi_data, ATAPI_SIZE * SECTOR_SIZE);
   bufferFile = createAbstractFileFromMemory((void**)&amp;atapi, ATAPI_SIZE * SECTOR_SIZE);
 
-  blkx = insertBLKX(file, bufferFile, ATAPI_OFFSET, ATAPI_SIZE, 1, CHECKSUM_CRC32,
-              &amp;BlockCRC, &amp;uncompressedToken, dataForkChecksum, dataForkToken, NULL);
+  if(BlockSize != SECTOR_SIZE)
+  {
+    blkx = insertBLKX(file, bufferFile, ATAPI_OFFSET, BlockSize / SECTOR_SIZE, pNum, CHECKSUM_CRC32,
+                &amp;BlockCRC, &amp;uncompressedToken, dataForkChecksum, dataForkToken, NULL, 0);
+  }
+  else
+  {
+    blkx = insertBLKX(file, bufferFile, ATAPI_OFFSET, ATAPI_SIZE, pNum, CHECKSUM_CRC32,
+                &amp;BlockCRC, &amp;uncompressedToken, dataForkChecksum, dataForkToken, NULL, 0);
+  }
 
   bufferFile-&gt;close(bufferFile);
   free(atapi);
@@ -595,7 +623,9 @@ void writeATAPI(AbstractFile* file, ChecksumFunc dataForkChecksum, void* dataFor
   csum.type = CHECKSUM_MKBLOCK;
   csum.checksum = uncompressedToken.block;
 
-  *resources = insertData(*resources, &quot;blkx&quot;, 1, &quot;Macintosh (Apple_Driver_ATAPI : 2)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
+  char pName[100];
+  sprintf(pName, &quot;Macintosh (Apple_Driver_ATAPI : %d)&quot;, pNum + 1);	
+  *resources = insertData(*resources, &quot;blkx&quot;, pNum, pName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
   *resources = insertData(*resources, &quot;cSum&quot;, 1, &quot;&quot;, (const char*) (&amp;csum), sizeof(csum), 0);
   
   nsiz = (NSizResource*) malloc(sizeof(NSizResource));
@@ -614,6 +644,13 @@ void writeATAPI(AbstractFile* file, ChecksumFunc dataForkChecksum, void* dataFor
   }
   
   free(blkx);
+
+  pNum++;
+
+  if(BlockSize != SECTOR_SIZE &amp;&amp; (USER_OFFSET -  (ATAPI_OFFSET + (BlockSize / SECTOR_SIZE))) &gt; 0)
+    pNum = writeFreePartition(pNum, file, ATAPI_OFFSET + (BlockSize / SECTOR_SIZE), USER_OFFSET - (ATAPI_OFFSET + (BlockSize / SECTOR_SIZE)), resources);
+
+  return pNum;
 }
 
 
@@ -660,11 +697,13 @@ void readApplePartitionMap(AbstractFile* file, ResourceKey* resources, unsigned
   free(partition);
 }
 
-Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType) {
+Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType, unsigned int BlockSize) {
   Partition* partition;
+  Partition* orig;
   
-  partition = (Partition*) malloc(SECTOR_SIZE * PARTITION_SIZE);
-  memset(partition, 0, SECTOR_SIZE * PARTITION_SIZE);
+  size_t realPartitionSize = (PARTITION_SIZE * SECTOR_SIZE) / BlockSize * BlockSize; 
+  orig = partition = (Partition*) malloc(realPartitionSize);
+  memset(partition, 0, realPartitionSize);
   
   partition[0].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
   partition[0].pmSigPad = 0;
@@ -672,9 +711,9 @@ Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType)
   strcpy((char*)partition[0].pmPartName, &quot;Apple&quot;);
   strcpy((char*)partition[0].pmParType, &quot;Apple_partition_map&quot;);
   partition[0].pmPyPartStart = PARTITION_OFFSET;
-  partition[0].pmPartBlkCnt = PARTITION_SIZE;
+  partition[0].pmPartBlkCnt = PARTITION_SIZE / (BlockSize / SECTOR_SIZE);
   partition[0].pmLgDataStart = 0;
-  partition[0].pmDataCnt = PARTITION_SIZE;
+  partition[0].pmDataCnt = partition[0].pmPartBlkCnt;
   partition[0].pmPartStatus = 0x3;
   partition[0].pmLgBootStart = 0x0;
   partition[0].pmBootSize = 0x0;
@@ -685,82 +724,92 @@ Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType)
   partition[0].pmBootCksum = 0x0;
   partition[0].pmProcessor[0] = '\0';
   partition[0].bootCode = 0;
+ 
+  partition = (Partition*)(((char*) partition) + BlockSize);
+  partition[0].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
+  partition[0].pmSigPad = 0;
+  partition[0].pmMapBlkCnt = 0x4;
+  strcpy((char*)partition[0].pmPartName, &quot;Macintosh&quot;);
+  strcpy((char*)partition[0].pmParType, &quot;Apple_Driver_ATAPI&quot;);
+  partition[0].pmPyPartStart = ATAPI_OFFSET / (BlockSize / SECTOR_SIZE);
+  if(BlockSize != SECTOR_SIZE)
+  {
+    partition[0].pmPartBlkCnt = 1;
+  }
+  else
+  {
+    partition[0].pmPartBlkCnt = ATAPI_SIZE;
+  }
+  partition[0].pmLgDataStart = 0;
+  partition[0].pmDataCnt = partition[0].pmPartBlkCnt;
+  partition[0].pmPartStatus = 0x303;
+  partition[0].pmLgBootStart = 0x0;
+  partition[0].pmBootSize = 0x800;
+  partition[0].pmBootAddr = 0x0;
+  partition[0].pmBootAddr2 = 0x0;
+  partition[0].pmBootEntry = 0x0;
+  partition[0].pmBootEntry2 = 0x0;
+  partition[0].pmBootCksum = 0xffff;
+  partition[0].pmProcessor[0] = '\0';
+  partition[0].bootCode = BOOTCODE_DMMY;
+  
+  partition = (Partition*)(((char*) partition) + BlockSize);
+  partition[0].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
+  partition[0].pmSigPad = 0;
+  partition[0].pmMapBlkCnt = 0x4;
+  strcpy((char*)partition[0].pmPartName, &quot;Mac_OS_X&quot;);
+  strcpy((char*)partition[0].pmParType, volumeType);
+  partition[0].pmPyPartStart = USER_OFFSET / (BlockSize / SECTOR_SIZE);
+  partition[0].pmPartBlkCnt = numSectors / (BlockSize / SECTOR_SIZE);
+  partition[0].pmLgDataStart = 0;
+  partition[0].pmDataCnt = partition[0].pmPartBlkCnt;
+  partition[0].pmPartStatus = 0x40000033;
+  partition[0].pmLgBootStart = 0x0;
+  partition[0].pmBootSize = 0x0;
+  partition[0].pmBootAddr = 0x0;
+  partition[0].pmBootAddr2 = 0x0;
+  partition[0].pmBootEntry = 0x0;
+  partition[0].pmBootEntry2 = 0x0;
+  partition[0].pmBootCksum = 0x0;
+  partition[0].pmProcessor[0] = '\0';
+  partition[0].bootCode = 0;
+  
+  partition = (Partition*)(((char*) partition) + BlockSize);
+  partition[0].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
+  partition[0].pmSigPad = 0;
+  partition[0].pmMapBlkCnt = 0x4;
+  partition[0].pmPartName[0] = '\0';
+  strcpy((char*)partition[0].pmParType, &quot;Apple_Free&quot;);
+  partition[0].pmPyPartStart = (USER_OFFSET + numSectors) / (BlockSize / SECTOR_SIZE);
+  partition[0].pmPartBlkCnt = (FREE_SIZE + (BlockSize / SECTOR_SIZE / 2)) / (BlockSize / SECTOR_SIZE);
+  partition[0].pmLgDataStart = 0;
+  partition[0].pmDataCnt = 0x0;
+  partition[0].pmPartStatus = 0x0;
+  partition[0].pmLgBootStart = 0x0;
+  partition[0].pmBootSize = 0x0;
+  partition[0].pmBootAddr = 0x0;
+  partition[0].pmBootAddr2 = 0x0;
+  partition[0].pmBootEntry = 0x0;
+  partition[0].pmBootEntry2 = 0x0;
+  partition[0].pmBootCksum = 0x0;
+  partition[0].pmProcessor[0] = '\0';
+  partition[0].bootCode = 0;
   
-  partition[1].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
-  partition[1].pmSigPad = 0;
-  partition[1].pmMapBlkCnt = 0x4;
-  strcpy((char*)partition[1].pmPartName, &quot;Macintosh&quot;);
-  strcpy((char*)partition[1].pmParType, &quot;Apple_Driver_ATAPI&quot;);
-  partition[1].pmPyPartStart = ATAPI_OFFSET;
-  partition[1].pmPartBlkCnt = ATAPI_SIZE;
-  partition[1].pmLgDataStart = 0;
-  partition[1].pmDataCnt = 0x04;
-  partition[1].pmPartStatus = 0x303;
-  partition[1].pmLgBootStart = 0x0;
-  partition[1].pmBootSize = 0x800;
-  partition[1].pmBootAddr = 0x0;
-  partition[1].pmBootAddr2 = 0x0;
-  partition[1].pmBootEntry = 0x0;
-  partition[1].pmBootEntry2 = 0x0;
-  partition[1].pmBootCksum = 0xffff;
-  partition[1].pmProcessor[0] = '\0';
-  partition[1].bootCode = BOOTCODE_DMMY;
-  
-  partition[2].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
-  partition[2].pmSigPad = 0;
-  partition[2].pmMapBlkCnt = 0x4;
-  strcpy((char*)partition[2].pmPartName, &quot;Mac_OS_X&quot;);
-  strcpy((char*)partition[2].pmParType, volumeType);
-  partition[2].pmPyPartStart = USER_OFFSET;
-  partition[2].pmPartBlkCnt = numSectors;
-  partition[2].pmLgDataStart = 0;
-  partition[2].pmDataCnt = numSectors;
-  partition[2].pmPartStatus = 0x40000033;
-  partition[2].pmLgBootStart = 0x0;
-  partition[2].pmBootSize = 0x0;
-  partition[2].pmBootAddr = 0x0;
-  partition[2].pmBootAddr2 = 0x0;
-  partition[2].pmBootEntry = 0x0;
-  partition[2].pmBootEntry2 = 0x0;
-  partition[2].pmBootCksum = 0x0;
-  partition[2].pmProcessor[0] = '\0';
-  partition[2].bootCode = BOOTCODE_GOON;
-  
-  partition[3].pmSig = APPLE_PARTITION_MAP_SIGNATURE;
-  partition[3].pmSigPad = 0;
-  partition[3].pmMapBlkCnt = 0x4;
-  partition[3].pmPartName[0] = '\0';
-  strcpy((char*)partition[3].pmParType, &quot;Apple_Free&quot;);
-  partition[3].pmPyPartStart = USER_OFFSET + numSectors;
-  partition[3].pmPartBlkCnt = FREE_SIZE;
-  partition[3].pmLgDataStart = 0;
-  partition[3].pmDataCnt = 0x0;
-  partition[3].pmPartStatus = 0x0;
-  partition[3].pmLgBootStart = 0x0;
-  partition[3].pmBootSize = 0x0;
-  partition[3].pmBootAddr = 0x0;
-  partition[3].pmBootAddr2 = 0x0;
-  partition[3].pmBootEntry = 0x0;
-  partition[3].pmBootEntry2 = 0x0;
-  partition[3].pmBootCksum = 0x0;
-  partition[3].pmProcessor[0] = '\0';
-  partition[3].bootCode = 0;
-  
-  return partition;
+  return orig;
 }
 
-void writeFreePartition(AbstractFile* outFile, uint32_t numSectors, ResourceKey** resources) {
+int writeFreePartition(int pNum, AbstractFile* outFile, uint32_t offset, uint32_t numSectors, ResourceKey** resources) {
   BLKXTable* blkx;
   
   blkx = (BLKXTable*) malloc(sizeof(BLKXTable) + (2 * sizeof(BLKXRun)));
   
   blkx-&gt;fUDIFBlocksSignature = UDIF_BLOCK_SIGNATURE;
   blkx-&gt;infoVersion = 1;
-  blkx-&gt;firstSectorNumber = USER_OFFSET + numSectors;
-  blkx-&gt;sectorCount = FREE_SIZE;
+  blkx-&gt;firstSectorNumber = offset;
+  blkx-&gt;sectorCount = numSectors;
   blkx-&gt;dataStart = 0;
   blkx-&gt;decompressBufferRequested = 0;
-  blkx-&gt;blocksDescriptor = 3;
+  blkx-&gt;blocksDescriptor = pNum;
   blkx-&gt;reserved1 = 0;
   blkx-&gt;reserved2 = 0;
   blkx-&gt;reserved3 = 0;
@@ -774,17 +823,20 @@ void writeFreePartition(AbstractFile* outFile, uint32_t numSectors, ResourceKey*
   blkx-&gt;runs[0].type = BLOCK_IGNORE;
   blkx-&gt;runs[0].reserved = 0;
   blkx-&gt;runs[0].sectorStart = 0;
-  blkx-&gt;runs[0].sectorCount = FREE_SIZE;
+  blkx-&gt;runs[0].sectorCount = numSectors;
   blkx-&gt;runs[0].compOffset = outFile-&gt;tell(outFile);
   blkx-&gt;runs[0].compLength = 0;
   blkx-&gt;runs[1].type = BLOCK_TERMINATOR;
   blkx-&gt;runs[1].reserved = 0;
-  blkx-&gt;runs[1].sectorStart = FREE_SIZE;
+  blkx-&gt;runs[1].sectorStart = numSectors;
   blkx-&gt;runs[1].sectorCount = 0;
   blkx-&gt;runs[1].compOffset = blkx-&gt;runs[0].compOffset;
   blkx-&gt;runs[1].compLength = 0;
   
-  *resources = insertData(*resources, &quot;blkx&quot;, 3, &quot; (Apple_Free : 4)&quot;, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
+  char pName[100];
+  sprintf(pName, &quot; (Apple_Free : %d)&quot;, pNum + 1);
+  *resources = insertData(*resources, &quot;blkx&quot;, pNum, pName, (const char*) blkx, sizeof(BLKXTable) + (blkx-&gt;blocksRunCount * sizeof(BLKXRun)), ATTRIBUTE_HDIUTIL);
 
   free(blkx);
+  return pNum + 1;
 }</diff>
      <filename>dmg/partition.c</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ static char plstData[1032] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const char* plistHeader = &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;UTF-8\&quot;?&gt;\n&lt;!DOCTYPE plist PUBLIC \&quot;-//Apple Computer//DTD PLIST 1.0//EN\&quot; \&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd\&quot;&gt;\n&lt;plist version=\&quot;1.0\&quot;&gt;\n&lt;dict&gt;\n&quot;;
+const char* plistHeader = &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;UTF-8\&quot;?&gt;\n&lt;!DOCTYPE plist PUBLIC \&quot;-//Apple//DTD PLIST 1.0//EN\&quot; \&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd\&quot;&gt;\n&lt;plist version=\&quot;1.0\&quot;&gt;\n&lt;dict&gt;\n&quot;;
 const char* plistFooter = &quot;&lt;/dict&gt;\n&lt;/plist&gt;\n&quot;;
 
 static void flipSizeResource(unsigned char* data, char out) {
@@ -103,24 +103,23 @@ static void flipSizeResource(unsigned char* data, char out) {
   
   size = (SizeResource*) data;
   
-  FLIPENDIAN(size-&gt;version);
-  FLIPENDIAN(size-&gt;isHFS);
-  FLIPENDIAN(size-&gt;unknown2);
-  FLIPENDIAN(size-&gt;unknown3);
-  FLIPENDIAN(size-&gt;volumeModified);
-  FLIPENDIAN(size-&gt;unknown4);
-  FLIPENDIAN(size-&gt;volumeSignature);
-  FLIPENDIAN(size-&gt;sizePresent);
+  FLIPENDIANLE(size-&gt;version);
+  FLIPENDIANLE(size-&gt;isHFS);
+  FLIPENDIANLE(size-&gt;unknown2);
+  FLIPENDIANLE(size-&gt;unknown3);
+  FLIPENDIANLE(size-&gt;volumeModified);
+  FLIPENDIANLE(size-&gt;unknown4);
+  FLIPENDIANLE(size-&gt;volumeSignature);
+  FLIPENDIANLE(size-&gt;sizePresent);
 }
 
 static void flipCSumResource(unsigned char* data, char out) {
   CSumResource* cSum;
-  
   cSum = (CSumResource*) data;
   
-  FLIPENDIAN(cSum-&gt;version);
-  FLIPENDIAN(cSum-&gt;type);
-  FLIPENDIAN(cSum-&gt;checksum);
+  FLIPENDIANLE(cSum-&gt;version);
+  FLIPENDIANLE(cSum-&gt;type);
+  FLIPENDIANLE(cSum-&gt;checksum);
 }
 
 
@@ -170,17 +169,22 @@ static void flipBLKX(unsigned char* data, char out) {
     FLIPENDIAN(blkx-&gt;blocksRunCount);
     for(i = 0; i &lt; blkx-&gt;blocksRunCount; i++) {
       flipBLKXRun(&amp;(blkx-&gt;runs[i]));
-    }
-    
-    /*printf(&quot;fUDIFBlocksSignature: 0x%x\n&quot;, blkx-&gt;fUDIFBlocksSignature);
+    } 
+  }
+/*
+    printf(&quot;fUDIFBlocksSignature: 0x%x\n&quot;, blkx-&gt;fUDIFBlocksSignature);
     printf(&quot;infoVersion: 0x%x\n&quot;, blkx-&gt;infoVersion);
     printf(&quot;firstSectorNumber: 0x%llx\n&quot;, blkx-&gt;firstSectorNumber);
     printf(&quot;sectorCount: 0x%llx\n&quot;, blkx-&gt;sectorCount);
     printf(&quot;dataStart: 0x%llx\n&quot;, blkx-&gt;dataStart);
     printf(&quot;decompressBufferRequested: 0x%x\n&quot;, blkx-&gt;decompressBufferRequested);
     printf(&quot;blocksDescriptor: 0x%x\n&quot;, blkx-&gt;blocksDescriptor);
-    printf(&quot;blocksRunCount: 0x%x\n&quot;, blkx-&gt;blocksRunCount);*/
-  }
+    printf(&quot;blocksRunCount: 0x%x\n&quot;, blkx-&gt;blocksRunCount);
+
+    for(i = 0; i &lt; 0x20; i++)
+    {
+	    printf(&quot;checksum[%d]: %x\n&quot;, i, blkx-&gt;checksum.data[i]);
+    }*/
 }
 
 static char* getXMLString(char** location) {
@@ -412,7 +416,7 @@ static void writeNSizResource(NSizResource* data, char* buffer) {
   sprintf(itemBuffer, &quot;\t&lt;key&gt;version&lt;/key&gt;\n\t&lt;integer&gt;%d&lt;/integer&gt;\n&quot;, (int32_t)(data-&gt;version));
   strcat(buffer, itemBuffer);
   if(data-&gt;isVolume) {
-    sprintf(itemBuffer, &quot;\t&lt;key&gt;bytes&lt;/key&gt;\n\t&lt;integer&gt;%d&lt;/integer&gt;\n&quot;, (int32_t)(data-&gt;volumeSignature));
+    sprintf(itemBuffer, &quot;\t&lt;key&gt;volume-signature&lt;/key&gt;\n\t&lt;integer&gt;%d&lt;/integer&gt;\n&quot;, (int32_t)(data-&gt;volumeSignature));
     strcat(buffer, itemBuffer);
   }
   strcat(buffer, plistFooter);
@@ -521,6 +525,24 @@ void releaseNSiz(NSizResource* nSiz) {
   }
 }
 
+void outResources(AbstractFile* file, AbstractFile* out)
+{
+	char* xml;
+	UDIFResourceFile resourceFile;
+	off_t fileLength;
+
+	fileLength = file-&gt;getLength(file);
+	file-&gt;seek(file, fileLength - sizeof(UDIFResourceFile));
+	readUDIFResourceFile(file, &amp;resourceFile);
+	xml = (char*) malloc((size_t)resourceFile.fUDIFXMLLength);
+	file-&gt;seek(file, (off_t)(resourceFile.fUDIFXMLOffset));
+	ASSERT(file-&gt;read(file, xml, (size_t)resourceFile.fUDIFXMLLength) == (size_t)resourceFile.fUDIFXMLLength, &quot;fread&quot;);
+	ASSERT(out-&gt;write(out, xml, (size_t)resourceFile.fUDIFXMLLength) == (size_t)resourceFile.fUDIFXMLLength, &quot;fwrite&quot;);
+
+	file-&gt;close(file);
+	out-&gt;close(out);
+}
+
 ResourceKey* readResources(AbstractFile* file, UDIFResourceFile* resourceFile) {
   char* xml;
   char* curLoc;
@@ -624,7 +646,7 @@ ResourceKey* readResources(AbstractFile* file, UDIFResourceFile* resourceFile) {
   return toReturn;
 }
 
-static void writeResourceData(AbstractFile* file, ResourceData* data, FlipDataFunc flipData, int tabLength) {
+static void writeResourceData(AbstractFile* file, ResourceData* data, ResourceKey* curResource, FlipDataFunc flipData, int tabLength) {
   unsigned char* dataBuf;
   char* tabs;
   int i;
@@ -637,6 +659,10 @@ static void writeResourceData(AbstractFile* file, ResourceData* data, FlipDataFu
   
   abstractFilePrint(file, &quot;%s&lt;dict&gt;\n&quot;, tabs);
   abstractFilePrint(file, &quot;%s\t&lt;key&gt;Attributes&lt;/key&gt;\n%s\t&lt;string&gt;0x%04x&lt;/string&gt;\n&quot;, tabs, tabs, data-&gt;attributes);
+
+  if(strcmp((char*) curResource-&gt;key, &quot;blkx&quot;) == 0)
+    abstractFilePrint(file, &quot;%s\t&lt;key&gt;CFName&lt;/key&gt;\n%s\t&lt;string&gt;%s&lt;/string&gt;\n&quot;, tabs, tabs, data-&gt;name);
+
   abstractFilePrint(file, &quot;%s\t&lt;key&gt;Data&lt;/key&gt;\n%s\t&lt;data&gt;\n&quot;, tabs, tabs);
   
   if(flipData) {
@@ -669,8 +695,8 @@ void writeResources(AbstractFile* file, ResourceKey* resources) {
     abstractFilePrint(file, &quot;\t\t&lt;key&gt;%s&lt;/key&gt;\n\t\t&lt;array&gt;\n&quot;, curResource-&gt;key);
     curData = curResource-&gt;data;
     while(curData != NULL) {
-      writeResourceData(file, curData, curResource-&gt;flipData, 3);
-      curData = curData-&gt;next;
+	    writeResourceData(file, curData, curResource, curResource-&gt;flipData, 3);
+	    curData = curData-&gt;next;
     }
     abstractFilePrint(file, &quot;\t\t&lt;/array&gt;\n&quot;, curResource-&gt;key);
     curResource = curResource-&gt;next;
@@ -837,6 +863,7 @@ ResourceKey* makeSize(HFSPlusVolumeHeader* volumeHeader) {
   memset(&amp;size, 0, sizeof(SizeResource));
   size.version = 5;
   size.isHFS = 1;
+  size.unknown1 = 0;
   size.unknown2 = 0;
   size.unknown3 = 0;
   size.volumeModified = volumeHeader-&gt;modifyDate;
@@ -845,6 +872,6 @@ ResourceKey* makeSize(HFSPlusVolumeHeader* volumeHeader) {
   size.sizePresent = 1;
 
   printf(&quot;making size data\n&quot;);  
-  return insertData(NULL, &quot;size&quot;, 0, &quot;&quot;, (const char*)(&amp;size), sizeof(SizeResource), 0); 
+  return insertData(NULL, &quot;size&quot;, 2, &quot;&quot;, (const char*)(&amp;size), sizeof(SizeResource), 0); 
 }
 </diff>
      <filename>dmg/resources.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,15 @@
+INCLUDE(FindZLIB)
+
+IF(NOT ZLIB_FOUND)
+	message(FATAL_ERROR &quot;zlib is required for hfs!&quot;)
+ENDIF(NOT ZLIB_FOUND)
+
+include_directories(${ZLIB_INCLUDE_DIR})
+link_directories(${ZLIB_LIBRARIES})
+
 link_directories (${PROJECT_BINARY_DIR}/common)
-add_library(hfs btree.c catalog.c extents.c fastunicodecompare.c flatfile.c hfslib.c rawfile.c utility.c volume.c)
-target_link_libraries(hfs common)
+add_library(hfs btree.c catalog.c extents.c xattr.c fastunicodecompare.c flatfile.c hfslib.c rawfile.c utility.c volume.c hfscompress.c)
+target_link_libraries(hfs common z)
 
 add_executable(hfsplus hfs.c)
 target_link_libraries (hfsplus hfs)</diff>
      <filename>hfs/CMakeLists.txt</filename>
    </modified>
    <modified>
      <diff>@@ -36,8 +36,10 @@ BTHeaderRec* readBTHeaderRec(io_func* io) {
  
   headerRec = (BTHeaderRec*) malloc(sizeof(BTHeaderRec));
   
-  if(!READ(io, sizeof(BTNodeDescriptor), sizeof(BTHeaderRec), headerRec))
+  if(!READ(io, sizeof(BTNodeDescriptor), sizeof(BTHeaderRec), headerRec)) {
+    free(headerRec);
     return NULL;
+  }
     
   FLIPENDIAN(headerRec-&gt;treeDepth);
   FLIPENDIAN(headerRec-&gt;rootNode);
@@ -239,11 +241,23 @@ static void* searchNode(BTree* tree, uint32_t root, BTKey* searchKey, int *exact
       
     free(descriptor);
     return READ_DATA(tree, lastRecordDataOffset, tree-&gt;io);
-  } else {
+  } else if(descriptor-&gt;kind == kBTIndexNode) {
   
     free(descriptor);
     return searchNode(tree, getNodeNumberFromPointerRecord(lastRecordDataOffset, tree-&gt;io), searchKey, exact, nodeNumber, recordNumber);
-  }      
+  } else {
+    if(nodeNumber != NULL)
+      *nodeNumber = root;
+      
+    if(recordNumber != NULL)
+      *recordNumber = i;
+    
+    if(exact != NULL)
+      *exact = FALSE;
+
+    free(descriptor);
+    return NULL;
+  }
 }
 
 void* search(BTree* tree, BTKey* searchKey, int *exact, uint32_t *nodeNumber, int *recordNumber) {
@@ -466,6 +480,7 @@ static uint32_t traverseNode(uint32_t nodeNum, BTree* tree, unsigned char* map,
         printf(&quot;\n&quot;); fflush(stdout);
       }
       free(previousKey);
+      previousKey = NULL;
     }
     
     if(displayTree) {
@@ -503,6 +518,8 @@ static uint32_t traverseNode(uint32_t nodeNum, BTree* tree, unsigned char* map,
     lastrecordDataOffset = recordDataOffset;
   }
   
+  if(previousKey != NULL) free(previousKey);
+
   free(descriptor);
   
   return count;
@@ -629,7 +646,10 @@ int debugBTree(BTree* tree, int displayTree) {
   } else {
     printf(&quot;Performing tree traversal...\n&quot;); fflush(stdout);
     traverseCount = traverseNode(tree-&gt;headerRec-&gt;rootNode, tree, map, 0, &amp;retFirstKey, &amp;retLastKey, heightTable, &amp;errorCount, displayTree);
-    
+
+    free(retFirstKey);
+    free(retLastKey);
+
     printf(&quot;Performing linear traversal...\n&quot;); fflush(stdout);
     linearCount = linearCheck(heightTable, map, tree, &amp;errorCount);
   }
@@ -765,6 +785,7 @@ static int growBTree(BTree* tree) {
   
   if(byteNumber &lt; (tree-&gt;headerRec-&gt;nodeSize - 256)) {
     ASSERT(writeBTHeaderRec(tree), &quot;writeBTHeaderREc&quot;);
+    free(buffer);
     return TRUE;
   } else {
     byteNumber -= tree-&gt;headerRec-&gt;nodeSize - 256;
@@ -1292,7 +1313,9 @@ static int increaseHeight(BTree* tree, uint32_t newNode) {
 
   ASSERT(writeBTNodeDescriptor(&amp;newDescriptor, tree-&gt;headerRec-&gt;rootNode, tree), &quot;writeBTNodeDescriptor&quot;);
   ASSERT(writeBTHeaderRec(tree), &quot;writeBTHeaderRec&quot;);
-  
+
+  free(oldRootKey);
+  free(newNodeKey); 
   return TRUE;
 }
 </diff>
      <filename>hfs/btree.c</filename>
    </modified>
    <modified>
      <diff>@@ -344,76 +344,93 @@ HFSPlusCatalogRecord* getRecordByCNID(HFSCatalogNodeID CNID, Volume* volume) {
 }
 
 CatalogRecordList* getFolderContents(HFSCatalogNodeID CNID, Volume* volume) {
-  BTree* tree;
-  HFSPlusCatalogThread* record; 
-  HFSPlusCatalogKey key;
-  uint32_t nodeNumber;
-  int recordNumber;
-  
-  BTNodeDescriptor* descriptor;
-  off_t recordOffset;
-  off_t recordDataOffset;
-  HFSPlusCatalogKey* currentKey;
-  
-  CatalogRecordList* list;
-  CatalogRecordList* lastItem;
-  CatalogRecordList* item;
-  
-  tree = volume-&gt;catalogTree;
-  
-  key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
-  key.parentID = CNID;
-  key.nodeName.length = 0;
-  
-  list = NULL;
-  
-  record = (HFSPlusCatalogThread*) search(tree, (BTKey*)(&amp;key), NULL, &amp;nodeNumber, &amp;recordNumber);
-  
-  if(record == NULL)
-    return NULL;
-  
-  free(record);
-  
-  ++recordNumber;
-  
-  while(nodeNumber != 0) {    
-    descriptor = readBTNodeDescriptor(nodeNumber, tree);
-       
-    while(recordNumber &lt; descriptor-&gt;numRecords) {
-      recordOffset = getRecordOffset(recordNumber, nodeNumber, tree);
-      currentKey = (HFSPlusCatalogKey*) READ_KEY(tree, recordOffset, tree-&gt;io);
-      recordDataOffset = recordOffset + currentKey-&gt;keyLength + sizeof(currentKey-&gt;keyLength);
-      
-      if(currentKey-&gt;parentID == CNID) {
-        item = (CatalogRecordList*) malloc(sizeof(CatalogRecordList));
-        item-&gt;name = currentKey-&gt;nodeName;
-        item-&gt;record = (HFSPlusCatalogRecord*) READ_DATA(tree, recordDataOffset, tree-&gt;io);
-        item-&gt;next = NULL;
-
-        if(list == NULL) {
-          list = item;
-        } else {
-          lastItem-&gt;next = item;
-        }
-        
-        lastItem = item;
-        free(currentKey);
-      } else {
-        free(currentKey);
-        free(descriptor);
-        return list;
-      }
-      
-      recordNumber++;
-    }
-    
-    nodeNumber = descriptor-&gt;fLink;
-    recordNumber = 0;
-	
-	free(descriptor);
-  }
-  
-  return list;
+	BTree* tree;
+	HFSPlusCatalogThread* record; 
+	HFSPlusCatalogKey key;
+	uint32_t nodeNumber;
+	int recordNumber;
+
+	BTNodeDescriptor* descriptor;
+	off_t recordOffset;
+	off_t recordDataOffset;
+	HFSPlusCatalogKey* currentKey;
+
+	CatalogRecordList* list;
+	CatalogRecordList* lastItem;
+	CatalogRecordList* item;
+
+	char pathBuffer[1024];
+	HFSPlusCatalogRecord* toReturn;
+	HFSPlusCatalogKey nkey;
+	int exact;
+
+	tree = volume-&gt;catalogTree;
+
+	key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
+	key.parentID = CNID;
+	key.nodeName.length = 0;
+
+	list = NULL;
+
+	record = (HFSPlusCatalogThread*) search(tree, (BTKey*)(&amp;key), NULL, &amp;nodeNumber, &amp;recordNumber);
+
+	if(record == NULL)
+		return NULL;
+
+	free(record);
+
+	++recordNumber;
+
+	while(nodeNumber != 0) {    
+		descriptor = readBTNodeDescriptor(nodeNumber, tree);
+
+		while(recordNumber &lt; descriptor-&gt;numRecords) {
+			recordOffset = getRecordOffset(recordNumber, nodeNumber, tree);
+			currentKey = (HFSPlusCatalogKey*) READ_KEY(tree, recordOffset, tree-&gt;io);
+			recordDataOffset = recordOffset + currentKey-&gt;keyLength + sizeof(currentKey-&gt;keyLength);
+
+			if(currentKey-&gt;parentID == CNID) {
+				item = (CatalogRecordList*) malloc(sizeof(CatalogRecordList));
+				item-&gt;name = currentKey-&gt;nodeName;
+				item-&gt;record = (HFSPlusCatalogRecord*) READ_DATA(tree, recordDataOffset, tree-&gt;io);
+
+				if(item-&gt;record-&gt;recordType == kHFSPlusFileRecord &amp;&amp; (((HFSPlusCatalogFile*)item-&gt;record)-&gt;userInfo.fileType) == kHardLinkFileType) {
+					sprintf(pathBuffer, &quot;iNode%d&quot;, ((HFSPlusCatalogFile*)item-&gt;record)-&gt;permissions.special.iNodeNum);
+					nkey.parentID = volume-&gt;metadataDir;
+					ASCIIToUnicode(pathBuffer, &amp;nkey.nodeName); 
+					nkey.keyLength = sizeof(nkey.parentID) + sizeof(nkey.nodeName.length) + (sizeof(uint16_t) * nkey.nodeName.length);
+
+					toReturn = (HFSPlusCatalogRecord*) search(volume-&gt;catalogTree, (BTKey*)(&amp;nkey), &amp;exact, NULL, NULL);
+
+					free(item-&gt;record);
+					item-&gt;record = toReturn;
+				}
+				item-&gt;next = NULL;
+
+				if(list == NULL) {
+					list = item;
+				} else {
+					lastItem-&gt;next = item;
+				}
+
+				lastItem = item;
+				free(currentKey);
+			} else {
+				free(currentKey);
+				free(descriptor);
+				return list;
+			}
+
+			recordNumber++;
+		}
+
+		nodeNumber = descriptor-&gt;fLink;
+		recordNumber = 0;
+
+		free(descriptor);
+	}
+
+	return list;
 }
 
 void releaseCatalogRecordList(CatalogRecordList* list) {
@@ -430,6 +447,8 @@ HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNode
 	io_func* io;
 	char pathBuffer[1024];
 	HFSPlusCatalogRecord* toReturn;
+	HFSPlusCatalogKey nkey;
+	int exact;
 
 	if(record-&gt;recordType == kHFSPlusFileRecord &amp;&amp; (((HFSPlusCatalogFile*)record)-&gt;permissions.fileMode &amp; S_IFLNK) == S_IFLNK) {
 		io = openRawFile(((HFSPlusCatalogFile*)record)-&gt;fileID, &amp;(((HFSPlusCatalogFile*)record)-&gt;dataFork), record, volume);
@@ -439,11 +458,43 @@ HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNode
 		toReturn = getRecordFromPath3(pathBuffer, volume, NULL, key, TRUE, TRUE, parentID);
 		free(record);
 		return toReturn;
+	} else if(record-&gt;recordType == kHFSPlusFileRecord &amp;&amp; (((HFSPlusCatalogFile*)record)-&gt;userInfo.fileType) == kHardLinkFileType) {
+		sprintf(pathBuffer, &quot;iNode%d&quot;, ((HFSPlusCatalogFile*)record)-&gt;permissions.special.iNodeNum);
+		nkey.parentID = volume-&gt;metadataDir;
+    		ASCIIToUnicode(pathBuffer, &amp;nkey.nodeName); 
+		nkey.keyLength = sizeof(nkey.parentID) + sizeof(nkey.nodeName.length) + (sizeof(uint16_t) * nkey.nodeName.length);
+
+		toReturn = (HFSPlusCatalogRecord*) search(volume-&gt;catalogTree, (BTKey*)(&amp;nkey), &amp;exact, NULL, NULL);
+
+		free(record);
+
+		return toReturn;
 	} else {
 		return record;
 	}
 }
 
+static const uint16_t METADATA_DIR[] = {0, 0, 0, 0, 'H', 'F', 'S', '+', ' ', 'P', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'D', 'a', 't', 'a'};
+
+HFSCatalogNodeID getMetadataDirectoryID(Volume* volume) {
+	HFSPlusCatalogKey key;
+	HFSPlusCatalogFolder* record;
+	int exact;
+	HFSCatalogNodeID id;
+
+	key.nodeName.length = sizeof(METADATA_DIR) / sizeof(uint16_t);
+	key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length) + sizeof(METADATA_DIR);
+	key.parentID = kHFSRootFolderID;
+	memcpy(key.nodeName.unicode, METADATA_DIR, sizeof(METADATA_DIR));
+
+	record = (HFSPlusCatalogFolder*) search(volume-&gt;catalogTree, (BTKey*)(&amp;key), &amp;exact, NULL, NULL);
+	id = record-&gt;folderID;
+
+	free(record);
+
+	return id;
+}
+
 HFSPlusCatalogRecord* getRecordFromPath(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey) {
 	return getRecordFromPath2(path, volume, name, retKey, TRUE);
 }
@@ -741,69 +792,92 @@ int move(const char* source, const char* dest, Volume* volume) {
 }
 
 int removeFile(const char* fileName, Volume* volume) {
-  HFSPlusCatalogRecord* record;
-  HFSPlusCatalogKey key;
-  io_func* io;
-  HFSPlusCatalogFolder* parentFolder;
-
-  record = getRecordFromPath3(fileName, volume, NULL, &amp;key, TRUE, FALSE, kHFSRootFolderID);
-  if(record != NULL) {
-    parentFolder = (HFSPlusCatalogFolder*) getRecordByCNID(key.parentID, volume);
-    if(parentFolder != NULL) {
-	if(parentFolder-&gt;recordType != kHFSPlusFolderRecord) {
-		ASSERT(FALSE, &quot;parent not folder&quot;);
-		free(parentFolder);
-		return FALSE;
-	}
-    } else {
-	ASSERT(FALSE, &quot;can't find parent&quot;);
-	return FALSE;
-    }
+	HFSPlusCatalogRecord* record;
+	HFSPlusCatalogKey key;
+	io_func* io;
+	HFSPlusCatalogFolder* parentFolder;
+
+	record = getRecordFromPath3(fileName, volume, NULL, &amp;key, TRUE, FALSE, kHFSRootFolderID);
+	if(record != NULL) {
+		parentFolder = (HFSPlusCatalogFolder*) getRecordByCNID(key.parentID, volume);
+		if(parentFolder != NULL) {
+			if(parentFolder-&gt;recordType != kHFSPlusFolderRecord) {
+				ASSERT(FALSE, &quot;parent not folder&quot;);
+				free(parentFolder);
+				return FALSE;
+			}
+		} else {
+			ASSERT(FALSE, &quot;can't find parent&quot;);
+			return FALSE;
+		}
 
-    if(record-&gt;recordType == kHFSPlusFileRecord) {
-      io = openRawFile(((HFSPlusCatalogFile*)record)-&gt;fileID, &amp;((HFSPlusCatalogFile*)record)-&gt;dataFork, record, volume);
-      allocate((RawFile*)io-&gt;data, 0);
-      CLOSE(io);
+		if(record-&gt;recordType == kHFSPlusFileRecord) {
+			io = openRawFile(((HFSPlusCatalogFile*)record)-&gt;fileID, &amp;((HFSPlusCatalogFile*)record)-&gt;dataFork, record, volume);
+			allocate((RawFile*)io-&gt;data, 0);
+			CLOSE(io);
+
+			removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
+			XAttrList* next;
+			XAttrList* attrs = getAllExtendedAttributes(((HFSPlusCatalogFile*)record)-&gt;fileID, volume);
+			if(attrs != NULL) {
+				while(attrs != NULL) {
+					next = attrs-&gt;next;
+					unsetAttribute(volume, ((HFSPlusCatalogFile*)record)-&gt;fileID, attrs-&gt;name);
+					free(attrs-&gt;name);
+					free(attrs);
+					attrs = next;
+				}	
+			}	
+
+
+			key.nodeName.length = 0;
+			key.parentID = ((HFSPlusCatalogFile*)record)-&gt;fileID;
+			key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
+			removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
+
+			volume-&gt;volumeHeader-&gt;fileCount--;
+		} else {
+			if(((HFSPlusCatalogFolder*)record)-&gt;valence &gt; 0) {
+				free(record);
+				free(parentFolder);
+				ASSERT(FALSE, &quot;folder not empty&quot;);
+				return FALSE;
+			} else {
+				removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
+				XAttrList* next;
+				XAttrList* attrs = getAllExtendedAttributes(((HFSPlusCatalogFolder*)record)-&gt;folderID, volume);
+				if(attrs != NULL) {
+					while(attrs != NULL) {
+						next = attrs-&gt;next;
+						unsetAttribute(volume, ((HFSPlusCatalogFolder*)record)-&gt;folderID, attrs-&gt;name);
+						free(attrs-&gt;name);
+						free(attrs);
+						attrs = next;
+					}	
+				}	
+
+				key.nodeName.length = 0;
+				key.parentID = ((HFSPlusCatalogFolder*)record)-&gt;folderID;
+				key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
+				removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
+			}
+
+			parentFolder-&gt;folderCount--;
+			volume-&gt;volumeHeader-&gt;folderCount--;
+		}
+		parentFolder-&gt;valence--;
+		updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder);
+		updateVolume(volume);
 
-      removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
-      
-      key.nodeName.length = 0;
-      key.parentID = ((HFSPlusCatalogFile*)record)-&gt;fileID;
-      key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
-      removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
-      
-      volume-&gt;volumeHeader-&gt;fileCount--;
-    } else {
-      if(((HFSPlusCatalogFolder*)record)-&gt;valence &gt; 0) {
 		free(record);
 		free(parentFolder);
-		ASSERT(FALSE, &quot;folder not empty&quot;);
-        return FALSE;
-      } else {
-        removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
-        
-        key.nodeName.length = 0;
-        key.parentID = ((HFSPlusCatalogFolder*)record)-&gt;folderID;
-        key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
-        removeFromBTree(volume-&gt;catalogTree, (BTKey*)(&amp;key));
-      }
-      
-	  parentFolder-&gt;folderCount--;
-      volume-&gt;volumeHeader-&gt;folderCount--;
-    }
-    parentFolder-&gt;valence--;
-    updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder);
-    updateVolume(volume);
 
-	free(record);
-	free(parentFolder);
-	
-    return TRUE;
-  } else {
-	free(parentFolder);
-	ASSERT(FALSE, &quot;cannot find record&quot;);
-    return FALSE;
-  }
+		return TRUE;
+	} else {
+		free(parentFolder);
+		ASSERT(FALSE, &quot;cannot find record&quot;);
+		return FALSE;
+	}
 }
 
 int makeSymlink(const char* pathName, const char* target, Volume* volume) {</diff>
      <filename>hfs/catalog.c</filename>
    </modified>
    <modified>
      <diff>@@ -222,6 +222,40 @@ void cmd_grow(Volume* volume, int argc, const char *argv[]) {
 	printf(&quot;grew volume: %&quot; PRId64 &quot;\n&quot;, newSize);
 }
 
+void cmd_getattr(Volume* volume, int argc, const char *argv[]) {
+	HFSPlusCatalogRecord* record;
+
+	if(argc &lt; 3) {
+		printf(&quot;Not enough arguments&quot;);
+		return;
+	}
+
+	record = getRecordFromPath(argv[1], volume, NULL, NULL);
+
+	if(record != NULL) {
+		HFSCatalogNodeID id;
+		uint8_t* data;
+		size_t size;
+		if(record-&gt;recordType == kHFSPlusFileRecord)
+			id = ((HFSPlusCatalogFile*)record)-&gt;fileID;
+		else
+			id = ((HFSPlusCatalogFolder*)record)-&gt;folderID;
+
+		size = getAttribute(volume, id, argv[2], &amp;data);
+
+		if(size &gt; 0) {
+			fwrite(data, size, 1, stdout);
+			free(data);
+		} else {
+			printf(&quot;No such attribute\n&quot;);
+		}
+	} else {
+		printf(&quot;No such file or directory\n&quot;);
+	}
+	
+	free(record);
+}
+
 void TestByteOrder()
 {
 	short int word = 0x0001;
@@ -281,6 +315,8 @@ int main(int argc, const char *argv[]) {
 			cmd_addall(volume, argc - 2, argv + 2);
 		} else if(strcmp(argv[2], &quot;grow&quot;) == 0) {
 			cmd_grow(volume, argc - 2, argv + 2);
+		} else if(strcmp(argv[2], &quot;getattr&quot;) == 0) {
+			cmd_getattr(volume, argc - 2, argv + 2);
 		} else if(strcmp(argv[2], &quot;debug&quot;) == 0) {
 			if(argc &gt; 3 &amp;&amp; strcmp(argv[3], &quot;verbose&quot;) == 0) {
 				debugBTree(volume-&gt;catalogTree, TRUE);</diff>
      <filename>hfs/hfs.c</filename>
    </modified>
    <modified>
      <diff>@@ -5,12 +5,19 @@
 #include &lt;sys/types.h&gt;
 #include &quot;common.h&quot;
 #include &lt;hfs/hfsplus.h&gt;
+#include &lt;hfs/hfscompress.h&gt;
 #include &quot;abstractfile.h&quot;
 #include &lt;sys/stat.h&gt;
 #include &lt;inttypes.h&gt;
 
 #define BUFSIZE 1024*1024
 
+static int silence = 0;
+
+void hfs_setsilence(int s) {
+	silence = s;
+}
+
 void writeToFile(HFSPlusCatalogFile* file, AbstractFile* output, Volume* volume) {
 	unsigned char* buffer;
 	io_func* io;
@@ -19,16 +26,27 @@ void writeToFile(HFSPlusCatalogFile* file, AbstractFile* output, Volume* volume)
 	
 	buffer = (unsigned char*) malloc(BUFSIZE);
 
-	io = openRawFile(file-&gt;fileID, &amp;file-&gt;dataFork, (HFSPlusCatalogRecord*)file, volume);
-	if(io == NULL) {
-		hfs_panic(&quot;error opening file&quot;);
-		free(buffer);
-		return;
-	}
-	
-	curPosition = 0;
-	bytesLeft = file-&gt;dataFork.logicalSize;
-	
+	if(file-&gt;permissions.ownerFlags &amp; UF_COMPRESSED) {
+		io = openHFSPlusCompressed(volume, file);
+		if(io == NULL) {
+			hfs_panic(&quot;error opening file&quot;);
+			free(buffer);
+			return;
+		}
+
+		curPosition = 0;
+		bytesLeft = ((HFSPlusCompressed*) io-&gt;data)-&gt;decmpfs-&gt;size;
+	} else {
+		io = openRawFile(file-&gt;fileID, &amp;file-&gt;dataFork, (HFSPlusCatalogRecord*)file, volume);
+		if(io == NULL) {
+			hfs_panic(&quot;error opening file&quot;);
+			free(buffer);
+			return;
+		}
+
+		curPosition = 0;
+		bytesLeft = file-&gt;dataFork.logicalSize;
+	}	
 	while(bytesLeft &gt; 0) {
 		if(bytesLeft &gt; BUFSIZE) {
 			if(!READ(io, curPosition, BUFSIZE, buffer)) {
@@ -65,16 +83,24 @@ void writeToHFSFile(HFSPlusCatalogFile* file, AbstractFile* input, Volume* volum
 	
 	bytesLeft = input-&gt;getLength(input);
 
-	io = openRawFile(file-&gt;fileID, &amp;file-&gt;dataFork, (HFSPlusCatalogRecord*)file, volume);
-	if(io == NULL) {
-		hfs_panic(&quot;error opening file&quot;);
-		free(buffer);
-		return;
+	if(file-&gt;permissions.ownerFlags &amp; UF_COMPRESSED) {
+		io = openHFSPlusCompressed(volume, file);
+		if(io == NULL) {
+			hfs_panic(&quot;error opening file&quot;);
+			free(buffer);
+			return;
+		}
+	} else {
+		io = openRawFile(file-&gt;fileID, &amp;file-&gt;dataFork, (HFSPlusCatalogRecord*)file, volume);
+		if(io == NULL) {
+			hfs_panic(&quot;error opening file&quot;);
+			free(buffer);
+			return;
+		}
+		allocate((RawFile*)io-&gt;data, bytesLeft);
 	}
 	
-	curPosition = 0;
-	
-	allocate((RawFile*)io-&gt;data, bytesLeft);
+	curPosition = 0;	
 	
 	while(bytesLeft &gt; 0) {
 		if(bytesLeft &gt; BUFSIZE) {
@@ -475,12 +501,25 @@ int copyAcrossVolumes(Volume* volume1, Volume* volume2, char* path1, char* path2
 	bufferSize = 0;
 	tmpFile = createAbstractFileFromMemoryFile((void**)&amp;buffer, &amp;bufferSize);
 	
-	printf(&quot;retrieving... &quot;); fflush(stdout);
+	if(!silence)
+	{
+		printf(&quot;retrieving... &quot;); fflush(stdout);
+	}
+
 	get_hfs(volume1, path1, tmpFile);
 	tmpFile-&gt;seek(tmpFile, 0);
-	printf(&quot;writing (%ld)... &quot;, (long) tmpFile-&gt;getLength(tmpFile)); fflush(stdout);
+
+	if(!silence)
+	{
+		printf(&quot;writing (%ld)... &quot;, (long) tmpFile-&gt;getLength(tmpFile)); fflush(stdout);
+	}
+
 	ret = add_hfs(volume2, tmpFile, path2);
-	printf(&quot;done\n&quot;);
+
+	if(!silence)
+	{
+		printf(&quot;done\n&quot;);
+	}
 	
 	free(buffer);
 	
@@ -494,6 +533,8 @@ void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
 	HFSPlusCatalogFile* file;
 	time_t fileTime;
 	struct tm *date;
+	HFSPlusDecmpfs* compressData;
+	size_t attrSize;
 	
 	theList = list = getFolderContents(folderID, volume);
 	
@@ -510,15 +551,22 @@ void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
 			printf(&quot;%06o &quot;, file-&gt;permissions.fileMode);
 			printf(&quot;%3d &quot;, file-&gt;permissions.ownerID);
 			printf(&quot;%3d &quot;, file-&gt;permissions.groupID);
-			printf(&quot;%12&quot; PRId64 &quot; &quot;, file-&gt;dataFork.logicalSize);
+			if(file-&gt;permissions.ownerFlags &amp; UF_COMPRESSED) {
+				attrSize = getAttribute(volume, file-&gt;fileID, &quot;com.apple.decmpfs&quot;, (uint8_t**)(&amp;compressData));
+				flipHFSPlusDecmpfs(compressData);
+				printf(&quot;%12&quot; PRId64 &quot; &quot;, compressData-&gt;size);
+				free(compressData);
+			} else {
+				printf(&quot;%12&quot; PRId64 &quot; &quot;, file-&gt;dataFork.logicalSize);
+			}
 			fileTime = APPLE_TO_UNIX_TIME(file-&gt;contentModDate);
 		}
 			
 		date = localtime(&amp;fileTime);
 		if(date != NULL) {
-      printf(&quot;%2d/%2d/%4d %02d:%02d &quot;, date-&gt;tm_mon, date-&gt;tm_mday, date-&gt;tm_year + 1900, date-&gt;tm_hour, date-&gt;tm_min);
+			printf(&quot;%2d/%2d/%4d %02d:%02d &quot;, date-&gt;tm_mon, date-&gt;tm_mday, date-&gt;tm_year + 1900, date-&gt;tm_hour, date-&gt;tm_min);
 		} else {
-      printf(&quot;                 &quot;);
+			printf(&quot;                 &quot;);
 		}
 
 		printUnicode(&amp;list-&gt;name);
@@ -530,14 +578,24 @@ void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
 	releaseCatalogRecordList(theList);
 }
 
-void displayFileLSLine(HFSPlusCatalogFile* file, const char* name) {
+void displayFileLSLine(Volume* volume, HFSPlusCatalogFile* file, const char* name) {
 	time_t fileTime;
 	struct tm *date;
+	HFSPlusDecmpfs* compressData;
 	
 	printf(&quot;%06o &quot;, file-&gt;permissions.fileMode);
 	printf(&quot;%3d &quot;, file-&gt;permissions.ownerID);
 	printf(&quot;%3d &quot;, file-&gt;permissions.groupID);
-	printf(&quot;%12&quot; PRId64 &quot; &quot;, file-&gt;dataFork.logicalSize);
+
+	if(file-&gt;permissions.ownerFlags &amp; UF_COMPRESSED) {
+		getAttribute(volume, file-&gt;fileID, &quot;com.apple.decmpfs&quot;, (uint8_t**)(&amp;compressData));
+		flipHFSPlusDecmpfs(compressData);
+		printf(&quot;%12&quot; PRId64 &quot; &quot;, compressData-&gt;size);
+		free(compressData);
+	} else {
+		printf(&quot;%12&quot; PRId64 &quot; &quot;, file-&gt;dataFork.logicalSize);
+	}
+
 	fileTime = APPLE_TO_UNIX_TIME(file-&gt;contentModDate);
 	date = localtime(&amp;fileTime);
 	if(date != NULL) {
@@ -546,6 +604,19 @@ void displayFileLSLine(HFSPlusCatalogFile* file, const char* name) {
 		printf(&quot;                 &quot;);
 	}
 	printf(&quot;%s\n&quot;, name);
+
+	XAttrList* next;
+	XAttrList* attrs = getAllExtendedAttributes(file-&gt;fileID, volume);
+	if(attrs != NULL) {
+		printf(&quot;Extended attributes\n&quot;);
+		while(attrs != NULL) {
+			next = attrs-&gt;next;
+			printf(&quot;\t%s\n&quot;, attrs-&gt;name);
+			free(attrs-&gt;name);
+			free(attrs);
+			attrs = next;
+		}	
+	}	
 }
 
 void hfs_ls(Volume* volume, const char* path) {
@@ -559,7 +630,7 @@ void hfs_ls(Volume* volume, const char* path) {
 		if(record-&gt;recordType == kHFSPlusFolderRecord)
 			displayFolder(((HFSPlusCatalogFolder*)record)-&gt;folderID, volume);  
 		else
-			displayFileLSLine((HFSPlusCatalogFile*)record, name);
+			displayFileLSLine(volume, (HFSPlusCatalogFile*)record, name);
 	} else {
 		printf(&quot;No such file or directory\n&quot;);
 	}
@@ -610,7 +681,8 @@ void hfs_untar(Volume* volume, AbstractFile* tarFile) {
 		HFSPlusCatalogRecord* record = getRecordFromPath3(fileName, volume, NULL, NULL, TRUE, FALSE, kHFSRootFolderID);
 		if(record) {
 			if(record-&gt;recordType == kHFSPlusFolderRecord || type == 5) {
-				printf(&quot;ignoring %s, type = %d\n&quot;, fileName, type);
+				if(!silence)
+					printf(&quot;ignoring %s, type = %d\n&quot;, fileName, type);
 				free(record);
 				goto loop;
 			} else {
@@ -621,7 +693,8 @@ void hfs_untar(Volume* volume, AbstractFile* tarFile) {
 		}
 
 		if(type == 0) {
-			printf(&quot;file: %s (%04o), size = %d\n&quot;, fileName, mode, size);
+			if(!silence)
+				printf(&quot;file: %s (%04o), size = %d\n&quot;, fileName, mode, size);
 			void* buffer = malloc(size);
 			tarFile-&gt;seek(tarFile, curRecord + 512);
 			tarFile-&gt;read(tarFile, buffer, size);
@@ -629,10 +702,12 @@ void hfs_untar(Volume* volume, AbstractFile* tarFile) {
 			add_hfs(volume, inFile, fileName);
 			free(buffer);
 		} else if(type == 5) {
-			printf(&quot;directory: %s (%04o)\n&quot;, fileName, mode);
+			if(!silence)
+				printf(&quot;directory: %s (%04o)\n&quot;, fileName, mode);
 			newFolder(fileName, volume);
 		} else if(type == 2) {
-			printf(&quot;symlink: %s (%04o) -&gt; %s\n&quot;, fileName, mode, target);
+			if(!silence)
+				printf(&quot;symlink: %s (%04o) -&gt; %s\n&quot;, fileName, mode, target);
 			makeSymlink(fileName, target, volume);
 		}
 </diff>
      <filename>hfs/hfslib.c</filename>
    </modified>
    <modified>
      <diff>@@ -174,6 +174,9 @@ static int rawFileRead(io_func* io,off_t location, size_t size, void *buffer) {
 	volume = rawFile-&gt;volume;
 	blockSize = volume-&gt;volumeHeader-&gt;blockSize;
 
+	if(!rawFile-&gt;extents)
+		return FALSE;
+
 	extent = rawFile-&gt;extents;
 	fileLoc = 0;
 </diff>
      <filename>hfs/rawfile.c</filename>
    </modified>
    <modified>
      <diff>@@ -98,62 +98,76 @@ int updateVolume(Volume* volume) {
 }
 
 Volume* openVolume(io_func* io) {
-  Volume* volume;
-  io_func* file;
-  
-  volume = (Volume*) malloc(sizeof(Volume));
-  volume-&gt;image = io;
-  volume-&gt;extentsTree = NULL;
-  
-  volume-&gt;volumeHeader = readVolumeHeader(io, 1024);
-  if(volume-&gt;volumeHeader == NULL) {
-    free(volume);
-    return NULL;
-  }
-  
-  file = openRawFile(kHFSExtentsFileID, &amp;volume-&gt;volumeHeader-&gt;extentsFile, NULL, volume);
-  if(file == NULL) {
-    free(volume-&gt;volumeHeader);
-    free(volume);
-    return NULL;
-  }
-  
-  volume-&gt;extentsTree = openExtentsTree(file);
-  if(volume-&gt;extentsTree == NULL) {
-    free(volume-&gt;volumeHeader);
-    free(volume);
-    return NULL;
-  }
-  
-  file = openRawFile(kHFSCatalogFileID, &amp;volume-&gt;volumeHeader-&gt;catalogFile, NULL, volume);
-  if(file == NULL) {
-    closeBTree(volume-&gt;extentsTree);
-    free(volume-&gt;volumeHeader);
-    free(volume);
-    return NULL;
-  }
-  
-  volume-&gt;catalogTree = openCatalogTree(file);
-  if(volume-&gt;catalogTree == NULL) {
-    closeBTree(volume-&gt;extentsTree);
-    free(volume-&gt;volumeHeader);
-    free(volume);
-    return NULL;
-  }
-  
-  volume-&gt;allocationFile = openRawFile(kHFSAllocationFileID, &amp;volume-&gt;volumeHeader-&gt;allocationFile, NULL, volume);
-  if(volume-&gt;catalogTree == NULL) {
-    closeBTree(volume-&gt;catalogTree);
-    closeBTree(volume-&gt;extentsTree);
-    free(volume-&gt;volumeHeader);
-    free(volume);
-    return NULL;
-  }
-  
-  return volume;
+	Volume* volume;
+	io_func* file;
+
+	volume = (Volume*) malloc(sizeof(Volume));
+	volume-&gt;image = io;
+	volume-&gt;extentsTree = NULL;
+
+	volume-&gt;volumeHeader = readVolumeHeader(io, 1024);
+	if(volume-&gt;volumeHeader == NULL) {
+		free(volume);
+		return NULL;
+	}
+
+	file = openRawFile(kHFSExtentsFileID, &amp;volume-&gt;volumeHeader-&gt;extentsFile, NULL, volume);
+	if(file == NULL) {
+		free(volume-&gt;volumeHeader);
+		free(volume);
+		return NULL;
+	}
+
+	volume-&gt;extentsTree = openExtentsTree(file);
+	if(volume-&gt;extentsTree == NULL) {
+		free(volume-&gt;volumeHeader);
+		free(volume);
+		return NULL;
+	}
+
+	file = openRawFile(kHFSCatalogFileID, &amp;volume-&gt;volumeHeader-&gt;catalogFile, NULL, volume);
+	if(file == NULL) {
+		closeBTree(volume-&gt;extentsTree);
+		free(volume-&gt;volumeHeader);
+		free(volume);
+		return NULL;
+	}
+
+	volume-&gt;catalogTree = openCatalogTree(file);
+	if(volume-&gt;catalogTree == NULL) {
+		closeBTree(volume-&gt;extentsTree);
+		free(volume-&gt;volumeHeader);
+		free(volume);
+		return NULL;
+	}
+
+	volume-&gt;allocationFile = openRawFile(kHFSAllocationFileID, &amp;volume-&gt;volumeHeader-&gt;allocationFile, NULL, volume);
+	if(volume-&gt;allocationFile == NULL) {
+		closeBTree(volume-&gt;catalogTree);
+		closeBTree(volume-&gt;extentsTree);
+		free(volume-&gt;volumeHeader);
+		free(volume);
+		return NULL;
+	}
+
+	volume-&gt;attrTree = NULL;
+	file = openRawFile(kHFSAttributesFileID, &amp;volume-&gt;volumeHeader-&gt;attributesFile, NULL, volume);
+	if(file != NULL) {
+		volume-&gt;attrTree = openAttributesTree(file);
+		if(!volume-&gt;attrTree) {
+			CLOSE(file);
+		}
+	}
+
+	volume-&gt;metadataDir = getMetadataDirectoryID(volume);
+
+	return volume;
 }
 
 void closeVolume(Volume *volume) {
+  if(volume-&gt;attrTree)
+    closeBTree(volume-&gt;attrTree);
+
   CLOSE(volume-&gt;allocationFile);
   closeBTree(volume-&gt;catalogTree);
   closeBTree(volume-&gt;extentsTree);</diff>
      <filename>hfs/volume.c</filename>
    </modified>
    <modified>
      <diff>@@ -271,7 +271,6 @@ int main(int argc, char* argv[])
 
 	extractedIPSWPath = tmpFilePath;
 	bootImagePath = &quot;restore.img3&quot;;
-	
 
 	fprintf(stdout, &quot;\nGetting iPhone/iPod status...\n&quot;);
 	fflush(stdout);</diff>
      <filename>idevice/idevice.c</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,7 @@
 #define MOBILEDEVICE_H
 
 #define CF_BUILDING_CF_AS_LIB
-#if __APPLE__
-#include &lt;CoreFoundation/CoreFoundation.h&gt;
-#else
 #include &lt;CoreFoundation.h&gt;
-#endif
 typedef unsigned int mach_error_t;
 
 /* Error codes */
@@ -154,26 +150,6 @@ mach_error_t AMRestoreEnableFileLogging(char *path);
 
 mach_error_t AMRestorePerformDFURestore(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info);
 
-mach_error_t AMRestorePerformRecoveryModeRestore(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info);
-
-unsigned int* AMRecoveryModeDeviceGetProgress(struct am_recovery_device *rdev, unsigned int* progress, unsigned int* total);
-
-mach_error_t AMRecoveryModeDeviceSetAutoBoot(struct am_recovery_device *rdev, char autoboot);
-
-mach_error_t AMDeviceEnterRecovery(struct am_device *rdev);
-
-mach_error_t AMDeviceConnect(struct am_device *device);
-
-mach_error_t AMDeviceIsPaired(struct am_device *device);
-
-mach_error_t AMDevicePair(struct am_device *device);
-
-mach_error_t AMDeviceValidatePairing(struct am_device *device);
-
-mach_error_t AMDeviceStartSession(struct am_device *device);
-
-CFStringRef AMDeviceCopyValue(struct am_device *device, unsigned int, const CFStringRef cfstring);
-
 int sendCommandToDevice(am_recovery_device *rdev, CFStringRef cfs, int block);
 int sendFileToDevice(am_recovery_device *rdev, CFStringRef filename);
 </diff>
      <filename>idevice/mobiledevice.h</filename>
    </modified>
    <modified>
      <diff>@@ -30,39 +30,13 @@ typedef mach_error_t (*AMRestoreEnableFileLoggingFunctionType)(char *path);
 
 typedef mach_error_t (*AMRestorePerformDFURestoreFunctionType)(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info);
 
-typedef mach_error_t (*AMRestorePerformRecoveryModeRestoreFunctionType)(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info);
-
 typedef int (__cdecl * cmdsend)  (am_recovery_device *, am_recovery_device *, CFStringRef, int block) __attribute__ ((cdecl));
 
-typedef unsigned int* (*AMRecoveryModeDeviceGetProgressFunctionType)(struct am_recovery_device *rdev, unsigned int* progress, unsigned int* total);
-
-typedef mach_error_t (*AMRecoveryModeDeviceSetAutoBootFunctionType)(struct am_recovery_device *rdev, char autoboot);
-
-typedef mach_error_t (*AMDeviceEnterRecoveryFunctionType)(struct am_device *rdev);
-
-typedef mach_error_t (*AMDeviceConnectFunctionType)(struct am_device *device);
-typedef mach_error_t (*AMDeviceIsPairedFunctionType)(struct am_device *device);
-typedef mach_error_t (*AMDevicePairFunctionType)(struct am_device *device);
-typedef mach_error_t (*AMDeviceValidatePairingFunctionType)(struct am_device *device);
-typedef mach_error_t (*AMDeviceStartSessionFunctionType)(struct am_device *device);
-
-typedef CFStringRef (*AMDeviceCopyValueFunctionType)(struct am_device *device, unsigned int, const CFStringRef cfstring);
-
 static AMDeviceNotificationSubscribeFunctionType AMDeviceNotificationSubscribeFunction = NULL;
 static AMRestoreRegisterForDeviceNotificationsFunctionType AMRestoreRegisterForDeviceNotificationsFunction = NULL;
 static AMRestoreCreateDefaultOptionsFunctionType AMRestoreCreateDefaultOptionsFunction = NULL;
 static AMRestoreEnableFileLoggingFunctionType AMRestoreEnableFileLoggingFunction = NULL;
 static AMRestorePerformDFURestoreFunctionType AMRestorePerformDFURestoreFunction = NULL;
-static AMRestorePerformRecoveryModeRestoreFunctionType AMRestorePerformRecoveryModeRestoreFunction = NULL;
-static AMRecoveryModeDeviceGetProgressFunctionType AMRecoveryModeDeviceGetProgressFunction = NULL;
-static AMRecoveryModeDeviceSetAutoBootFunctionType AMRecoveryModeDeviceSetAutoBootFunction = NULL;
-static AMDeviceEnterRecoveryFunctionType AMDeviceEnterRecoveryFunction = NULL;
-static AMDeviceConnectFunctionType AMDeviceConnectFunction = NULL;
-static AMDeviceIsPairedFunctionType AMDeviceIsPairedFunction = NULL;
-static AMDevicePairFunctionType AMDevicePairFunction = NULL;
-static AMDeviceValidatePairingFunctionType AMDeviceValidatePairingFunction = NULL;
-static AMDeviceStartSessionFunctionType AMDeviceStartSessionFunction = NULL;
-static AMDeviceCopyValueFunctionType AMDeviceCopyValueFunction = NULL;
 static cmdsend   priv_sendCommandToDevice = NULL;
 static cmdsend   priv_sendFileToDevice = NULL;
 
@@ -76,7 +50,6 @@ typedef struct tagDLLOFFSET {
 
 DLLOFFSET OffSetTable[]= {
 //	VerMS		VerLS		GetProductType,	SendCmdO	SendFileO
-	{0x0B90002,	0x00000004,	0x0000ED90,	0x0000F2C0,	0x0000F6F0},
 	{0x0070008,	0x00760000,	0x0000FDA0,	0x00010290,	0x00010630},
 	{0x0070008,	0x00B00000,	0x0000FDF0,	0x000102E0,	0x00010680},
 	{0x0000000,	0x00000000,	0x00000000,	0x00000000,	0x00000000}
@@ -211,15 +184,6 @@ int LoadWindowsDLL() {
 		return -1;
 	}
 	
-	AMRestorePerformRecoveryModeRestoreFunction =
-		(AMRestorePerformRecoveryModeRestoreFunctionType) GetProcAddress(deviceDLL, &quot;AMRestorePerformRecoveryModeRestore&quot;);
-		
-	if(!AMRestorePerformRecoveryModeRestoreFunction	)
-	{
-		XLOG(2, &quot;failed to load AMRestorePerformRecoveryModeRestore&quot;);
-		return -1;
-	}
-
 	AMRestoreEnableFileLoggingFunction =
 		(AMRestoreEnableFileLoggingFunctionType) GetProcAddress(deviceDLL, &quot;AMRestoreEnableFileLogging&quot;);
 		
@@ -229,87 +193,7 @@ int LoadWindowsDLL() {
 		return -1;
 	}
 	
-	AMRecoveryModeDeviceGetProgressFunction =
-		(AMRecoveryModeDeviceGetProgressFunctionType) GetProcAddress(deviceDLL, &quot;AMRecoveryModeDeviceGetProgress&quot;);
-		
-	if(!AMRecoveryModeDeviceGetProgressFunction	)
-	{
-		XLOG(2, &quot;failed to load AMRecoveryModeDeviceGetProgress&quot;);
-		return -1;
-	}
 	
-	AMRecoveryModeDeviceSetAutoBootFunction =
-		(AMRecoveryModeDeviceSetAutoBootFunctionType) GetProcAddress(deviceDLL, &quot;AMRecoveryModeDeviceSetAutoBoot&quot;);
-		
-	if(!AMRecoveryModeDeviceSetAutoBootFunction	)
-	{
-		XLOG(2, &quot;failed to load AMRecoveryModeDeviceSetAutoBoot&quot;);
-		return -1;
-	}
-
-	AMDeviceEnterRecoveryFunction =
-		(AMDeviceEnterRecoveryFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceEnterRecovery&quot;);
-		
-	if(!AMDeviceEnterRecoveryFunction	)
-	{
-		XLOG(2, &quot;failed to load AMDeviceEnterRecovery&quot;);
-		return -1;
-	}
-
-	AMDeviceConnectFunction =
-		(AMDeviceConnectFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceConnect&quot;);
-		
-	if(!AMDeviceConnectFunction)
-	{
-		XLOG(2, &quot;failed to load AMDeviceConnect&quot;);
-		return -1;
-	}
-
-	AMDeviceIsPairedFunction =
-		(AMDeviceIsPairedFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceIsPaired&quot;);
-		
-	if(!AMDeviceIsPairedFunction)
-	{
-		XLOG(2, &quot;failed to load AMDeviceIsPaired&quot;);
-		return -1;
-	}
-
-	AMDevicePairFunction =
-		(AMDevicePairFunctionType) GetProcAddress(deviceDLL, &quot;AMDevicePair&quot;);
-		
-	if(!AMDevicePairFunction)
-	{
-		XLOG(2, &quot;failed to load AMDevicePair&quot;);
-		return -1;
-	}
-
-	AMDeviceValidatePairingFunction =
-		(AMDeviceValidatePairingFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceValidatePairing&quot;);
-		
-	if(!AMDeviceValidatePairingFunction)
-	{
-		XLOG(2, &quot;failed to load AMDeviceValidatePairing&quot;);
-		return -1;
-	}
-
-	AMDeviceStartSessionFunction =
-		(AMDeviceStartSessionFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceStartSession&quot;);
-		
-	if(!AMDeviceStartSessionFunction)
-	{
-		XLOG(2, &quot;failed to load AMDeviceStartSession&quot;);
-		return -1;
-	}
-
-	AMDeviceCopyValueFunction =
-		(AMDeviceCopyValueFunctionType) GetProcAddress(deviceDLL, &quot;AMDeviceCopyValue&quot;);
-		
-	if(!AMDeviceCopyValueFunction)
-	{
-		XLOG(2, &quot;failed to load AMDeviceCopyValue&quot;);
-		return -1;
-	}
-
 	initWindowsPrivateFunctions(deviceDLL);
 			
 	return 0;
@@ -354,65 +238,6 @@ mach_error_t AMRestorePerformDFURestore(struct am_recovery_device *rdev, CFDicti
 	return AMRestorePerformDFURestoreFunction(rdev, opts, callback, user_info);
 }
 
-mach_error_t AMRestorePerformRecoveryModeRestore(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info)
-{
-	XLOG(3, &quot;calling Windows AMRestorePerformRecoveryModeRestore&quot;);
-	return AMRestorePerformRecoveryModeRestoreFunction(rdev, opts, callback, user_info);
-}
-
-mach_error_t AMRecoveryModeDeviceSetAutoBoot(struct am_recovery_device *rdev, char autoboot)
-{
-	XLOG(3, &quot;calling Windows AMRecoveryModeDeviceSetAutoBoot&quot;);
-	return AMRecoveryModeDeviceSetAutoBootFunction(rdev, autoboot);
-}
-
-mach_error_t AMDeviceEnterRecovery(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDeviceEnterRecovery&quot;);
-	return AMDeviceEnterRecoveryFunction(rdev);
-}
-
-mach_error_t AMDeviceConnect(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDeviceConnect&quot;);
-	return AMDeviceConnectFunction(rdev);
-}
-
-mach_error_t AMDeviceIsPaired(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDeviceIsPaired&quot;);
-	return AMDeviceIsPairedFunction(rdev);
-}
-
-mach_error_t AMDevicePair(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDevicePair&quot;);
-	return AMDevicePairFunction(rdev);
-}
-
-mach_error_t AMDeviceValidatePairing(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDeviceValidatePairing&quot;);
-	return AMDeviceValidatePairingFunction(rdev);
-}
-
-mach_error_t AMDeviceStartSession(struct am_device *rdev)
-{
-	XLOG(3, &quot;calling Windows AMDeviceStartSession&quot;);
-	return AMDeviceStartSessionFunction(rdev);
-}
-
-CFStringRef AMDeviceCopyValue(struct am_device *device, unsigned int should_be_zero, const CFStringRef cfstring)
-{
-	XLOG(3, &quot;calling Windows AMDeviceCopyValue&quot;);
-	return AMDeviceCopyValueFunction(device, should_be_zero, cfstring);
-}
-
-unsigned int* AMRecoveryModeDeviceGetProgress(struct am_recovery_device *rdev, unsigned int* progress, unsigned int* total)
-{
-	return AMRecoveryModeDeviceGetProgressFunction(rdev, progress, total);
-}
-
 int sendCommandToDevice(am_recovery_device *rdev, CFStringRef cfs, int block)
 {
 	XLOG(3, &quot;calling Windows sendCommandToDevice %p %p %p %d&quot;, priv_sendCommandToDevice, rdev, cfs, block);</diff>
      <filename>idevice/windows.c</filename>
    </modified>
    <modified>
      <diff>@@ -34,12 +34,12 @@
 #define PARTITION_SIZE 0x3f
 #define ATAPI_SIZE 0x8
 #define FREE_SIZE 0xa
-#define EXTRA_SIZE (DDM_SIZE + PARTITION_SIZE + ATAPI_SIZE + FREE_SIZE)
+#define EXTRA_SIZE (ATAPI_OFFSET + ATAPI_SIZE + FREE_SIZE)
 
 #define DDM_OFFSET 0x0
 #define PARTITION_OFFSET (DDM_SIZE)
-#define ATAPI_OFFSET (DDM_SIZE + PARTITION_SIZE)
-#define USER_OFFSET (DDM_SIZE + PARTITION_SIZE + ATAPI_SIZE)
+#define ATAPI_OFFSET 64
+#define USER_OFFSET (ATAPI_OFFSET + ATAPI_SIZE)
 
 #define BOOTCODE_DMMY 0x444D4D59
 #define BOOTCODE_GOON 0x676F6F6E
@@ -274,6 +274,8 @@ static inline void writeUInt64(AbstractFile* file, uint64_t data) {
 #ifdef __cplusplus
 extern &quot;C&quot; {
 #endif
+	void outResources(AbstractFile* file, AbstractFile* out);
+
 	unsigned char* decodeBase64(char* toDecode, size_t* dataLength);
 	void writeBase64(AbstractFile* file, unsigned char* data, size_t dataLength, int tabLength, int width);
 	char* convertBase64(unsigned char* data, size_t dataLength, int tabLength, int width);
@@ -319,22 +321,22 @@ extern &quot;C&quot; {
 	void flipPartitionMultiple(Partition* partition, char multiple, char out, unsigned int BlockSize);
 
 	void readDriverDescriptorMap(AbstractFile* file, ResourceKey* resources);
-	DriverDescriptorRecord* createDriverDescriptorMap(uint32_t numSectors);
-	void writeDriverDescriptorMap(AbstractFile* file, DriverDescriptorRecord* DDM, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources);
+	DriverDescriptorRecord* createDriverDescriptorMap(uint32_t numSectors, unsigned int BlockSize);
+	int writeDriverDescriptorMap(int pNum, AbstractFile* file, DriverDescriptorRecord* DDM, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources);
 	void readApplePartitionMap(AbstractFile* file, ResourceKey* resources, unsigned int BlockSize);
-	Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType);
-	void writeApplePartitionMap(AbstractFile* file, Partition* partitions, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn);
-	void writeATAPI(AbstractFile* file,  ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn);
-	void writeFreePartition(AbstractFile* outFile, uint32_t numSectors, ResourceKey** resources);
+	Partition* createApplePartitionMap(uint32_t numSectors, const char* volumeType, unsigned int BlockSize);
+	int writeApplePartitionMap(int pNum, AbstractFile* file, Partition* partitions, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn);
+	int writeATAPI(int pNum, AbstractFile* file, unsigned int BlockSize, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn);
+	int writeFreePartition(int pNum, AbstractFile* outFile, uint32_t offset, uint32_t numSectors, ResourceKey** resources);
 
 	void extractBLKX(AbstractFile* in, AbstractFile* out, BLKXTable* blkx);
 	BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorNumber, uint32_t numSectors, uint32_t blocksDescriptor,
 				uint32_t checksumType, ChecksumFunc uncompressedChk, void* uncompressedChkToken, ChecksumFunc compressedChk,
-				void* compressedChkToken, Volume* volume);
+				void* compressedChkToken, Volume* volume, int addComment);
 
 
 	int extractDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, int partNum);
-	int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut);
+	int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, unsigned int BlockSize);
 	int convertToISO(AbstractFile* abstractIn, AbstractFile* abstractOut);
 	int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut);
 #ifdef __cplusplus</diff>
      <filename>includes/dmg/dmg.h</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@
 extern &quot;C&quot; {
 #endif
 	int extractDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, int partNum);
-	int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut);
+	int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, unsigned int BlockSize);
 
 	int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut);
 	int convertToISO(AbstractFile* abstractIn, AbstractFile* abstractOut);</diff>
      <filename>includes/dmg/dmglib.h</filename>
    </modified>
    <modified>
      <diff>@@ -18,6 +18,7 @@ extern &quot;C&quot; {
 
 	void hfs_untar(Volume* volume, AbstractFile* tarFile);
 	void hfs_ls(Volume* volume, const char* path);
+	void hfs_setsilence(int s);
 #ifdef __cplusplus
 }
 #endif</diff>
      <filename>includes/hfs/hfslib.h</filename>
    </modified>
    <modified>
      <diff>@@ -28,6 +28,10 @@ typedef void (*keyPrintFunc)(BTKey* toPrint);
 typedef int (*keyWriteFunc)(off_t offset, BTKey* toWrite, struct io_func_struct* io);
 typedef int (*compareFunc)(BTKey* left, BTKey* right);
 
+#define STR_SIZE(str) (sizeof(uint16_t) + (sizeof(uint16_t) * (str).length))
+
+#ifndef __HFS_FORMAT__
+
 typedef uint32_t HFSCatalogNodeID;
 
 enum {
@@ -44,8 +48,6 @@ enum {
     kHFSFirstUserCatalogNodeID  = 16
 };
 
-#define STR_SIZE(str) (sizeof(uint16_t) + (sizeof(uint16_t) * (str).length))
-
 struct HFSUniStr255 {
     uint16_t  length;
     uint16_t unicode[255];
@@ -261,6 +263,8 @@ struct ExtendedFolderInfo {
 } __attribute__((__packed__));
 typedef struct ExtendedFolderInfo   ExtendedFolderInfo;
 
+#ifndef _STAT_H_
+#ifndef _SYS_STAT_H
 #define S_ISUID 0004000     /* set user id on execution */
 #define S_ISGID 0002000     /* set group id on execution */
 #define S_ISTXT 0001000     /* sticky bit */
@@ -289,6 +293,10 @@ typedef struct ExtendedFolderInfo   ExtendedFolderInfo;
 #define S_IFLNK  0120000    /* symbolic link */
 #define S_IFSOCK 0140000    /* socket */
 #define S_IFWHT  0160000    /* whiteout */
+#endif
+#endif
+
+#define UF_COMPRESSED 040
 
 struct HFSPlusBSDInfo {
     uint32_t  ownerID;
@@ -381,6 +389,58 @@ struct HFSPlusCatalogThread {
 } __attribute__((__packed__));
 typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
 
+enum {
+	kHFSPlusAttrInlineData	= 0x10,
+	kHFSPlusAttrForkData	= 0x20,
+	kHFSPlusAttrExtents	= 0x30
+};
+
+struct HFSPlusAttrForkData {
+	uint32_t 	recordType;
+	uint32_t 	reserved;
+	HFSPlusForkData theFork;
+} __attribute__((__packed__));
+typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
+
+struct HFSPlusAttrExtents {
+	uint32_t 		recordType;
+	uint32_t 		reserved;
+	HFSPlusExtentRecord	extents;
+};
+typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
+
+struct HFSPlusAttrData {
+	uint32_t    recordType;
+	uint32_t    reserved[2];
+	uint32_t    size;
+	uint8_t     data[0];
+} __attribute__((__packed__));
+typedef struct HFSPlusAttrData HFSPlusAttrData;
+
+union HFSPlusAttrRecord {
+	uint32_t 		recordType;
+	HFSPlusAttrData 	attrData;
+	HFSPlusAttrForkData 	forkData;
+	HFSPlusAttrExtents 	overflowExtents;
+};
+typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
+
+struct HFSPlusAttrKey {
+	uint16_t     keyLength;
+	uint16_t     pad;
+	uint32_t     fileID;
+	uint32_t     startBlock;
+	HFSUniStr255 name;
+} __attribute__((__packed__));
+typedef struct HFSPlusAttrKey HFSPlusAttrKey;
+
+enum {
+	kHardLinkFileType = 0x686C6E6B,  /* 'hlnk' */
+	kHFSPlusCreator   = 0x6866732B   /* 'hfs+' */
+};
+
+#endif
+
 struct HFSPlusCatalogRecord {
   int16_t recordType;
   unsigned char data[0];
@@ -394,6 +454,12 @@ struct CatalogRecordList {
 };
 typedef struct CatalogRecordList CatalogRecordList;
 
+struct XAttrList {
+  char* name;
+  struct XAttrList* next;
+};
+typedef struct XAttrList XAttrList;
+
 struct Extent {
   uint32_t startBlock;
   uint32_t blockCount;
@@ -418,7 +484,9 @@ typedef struct {
 
   BTree* extentsTree;
   BTree* catalogTree;
+  BTree* attrTree;
   io_func* allocationFile;
+  HFSCatalogNodeID metadataDir;
 } Volume;
 
 
@@ -457,6 +525,12 @@ extern &quot;C&quot; {
 
 	io_func* openRawFile(HFSCatalogNodeID id, HFSPlusForkData* forkData, HFSPlusCatalogRecord* catalogRecord, Volume* volume);
 
+	BTree* openAttributesTree(io_func* file);
+	size_t getAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t** data);
+	int setAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t* data, size_t size);
+	int unsetAttribute(Volume* volume, uint32_t fileID, const char* name);
+	XAttrList* getAllExtendedAttributes(HFSCatalogNodeID CNID, Volume* volume);
+
 	void flipExtentRecord(HFSPlusExtentRecord* extentRecord);
 
 	BTree* openExtentsTree(io_func* file);
@@ -477,6 +551,7 @@ extern &quot;C&quot; {
 	int chownFile(const char* pathName, uint32_t owner, uint32_t group, Volume* volume);
 	int makeSymlink(const char* pathName, const char* target, Volume* volume);
 
+	HFSCatalogNodeID getMetadataDirectoryID(Volume* volume);
 	HFSPlusCatalogRecord* getRecordByCNID(HFSCatalogNodeID CNID, Volume* volume);
 	HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNodeID parentID, HFSPlusCatalogKey *key, Volume* volume);
 	CatalogRecordList* getFolderContents(HFSCatalogNodeID CNID, Volume* volume);</diff>
      <filename>includes/hfs/hfsplus.h</filename>
    </modified>
    <modified>
      <diff>@@ -42,9 +42,16 @@ typedef struct Info8900 {
 	char 		exploit;
 } Info8900;
 
-AbstractFile* createAbstractFileFrom8900(AbstractFile* file);
-AbstractFile* duplicate8900File(AbstractFile* file, AbstractFile* backing);
-void replaceCertificate8900(AbstractFile* file, AbstractFile* certificate);
-void exploit8900(AbstractFile* file);
+#ifdef __cplusplus
+extern &quot;C&quot; {
+#endif
+	AbstractFile* createAbstractFileFrom8900(AbstractFile* file);
+	AbstractFile* duplicate8900File(AbstractFile* file, AbstractFile* backing);
+	void replaceCertificate8900(AbstractFile* file, AbstractFile* certificate);
+	void exploit8900(AbstractFile* file);
+#ifdef __cplusplus
+}
+#endif
+
 
 #endif</diff>
      <filename>includes/xpwn/8900.h</filename>
    </modified>
    <modified>
      <diff>@@ -16,12 +16,14 @@
 #define IMG3_SHSH_MAGIC 0x53485348
 #define IMG3_CERT_MAGIC 0x43455254
 #define IMG3_KBAG_MAGIC 0x4B424147
+#define IMG3_TYPE_MAGIC 0x54595045
 
 #define IMG3_SIGNATURE IMG3_MAGIC
 
 typedef struct Img3Element Img3Element;
+typedef struct Img3Info Img3Info;
 
-typedef void (*WriteImg3)(AbstractFile* file, Img3Element* element);
+typedef void (*WriteImg3)(AbstractFile* file, Img3Element* element, Img3Info* info);
 typedef void (*FreeImg3)(Img3Element* element);
 
 typedef struct AppleImg3Header {
@@ -55,19 +57,23 @@ struct Img3Element
 	struct Img3Element* next;
 };
 
-typedef struct Img3Info {
+struct Img3Info {
 	AbstractFile* file;
 	Img3Element* root;
 	Img3Element* data;
 	Img3Element* cert;
 	Img3Element* kbag;
+	Img3Element* type;
 	int encrypted;
 	AES_KEY encryptKey;
 	AES_KEY decryptKey;
 	uint8_t iv[16];
 	size_t offset;
+	uint32_t replaceDWord;
 	char dirty;
-} Img3Info;
+	char exploit24k;
+	char exploitN8824k;
+};
 
 #ifdef __cplusplus
 extern &quot;C&quot; {
@@ -75,6 +81,8 @@ extern &quot;C&quot; {
 	AbstractFile* createAbstractFileFromImg3(AbstractFile* file);
 	AbstractFile* duplicateImg3File(AbstractFile* file, AbstractFile* backing);
 	void replaceCertificateImg3(AbstractFile* file, AbstractFile* certificate);
+	void exploit24kpwn(AbstractFile* file);
+	void exploitN8824kpwn(AbstractFile* file);
 #ifdef __cplusplus
 }
 #endif</diff>
      <filename>includes/xpwn/img3.h</filename>
    </modified>
    <modified>
      <diff>@@ -11,6 +11,7 @@ extern &quot;C&quot; {
 #endif
 	AbstractFile* openAbstractFile(AbstractFile* file);
 	AbstractFile* openAbstractFile2(AbstractFile* file, const unsigned int* key, const unsigned int* iv);
+	AbstractFile* openAbstractFile3(AbstractFile* file, const unsigned int* key, const unsigned int* iv, int layers);
 	AbstractFile* duplicateAbstractFile(AbstractFile* file, AbstractFile* backing);
 	AbstractFile* duplicateAbstractFile2(AbstractFile* file, AbstractFile* backing, const unsigned int* key, const unsigned int* iv, AbstractFile* certificate);
 #ifdef __cplusplus</diff>
      <filename>includes/xpwn/nor_files.h</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,7 @@ extern &quot;C&quot; {
 	Dictionary* parseIPSW2(const char* inputIPSW, const char* bundleRoot, char** bundlePath, OutputState** state, int useMemory);
 	int doPatch(StringValue* patchValue, StringValue* fileValue, const char* bundlePath, OutputState** state, unsigned int* key, unsigned int* iv, int useMemory);
 	void doPatchInPlace(Volume* volume, const char* filePath, const char* patchPath);
+	void doPatchInPlaceMemoryPatch(Volume* volume, const char* filePath, void** patch, size_t* patchSize);
 	void fixupBootNeuterArgs(Volume* volume, char unlockBaseband, char selfDestruct, char use39, char use46);
 	void createRestoreOptions(Volume* volume, int SystemPartitionSize, int UpdateBaseband);
 </diff>
      <filename>includes/xpwn/pwnutil.h</filename>
    </modified>
    <modified>
      <diff>@@ -68,7 +68,7 @@ IF(APPLE)
 		DEPENDS xpwn dmg hfs common minizip)
 ELSE(APPLE)
 	ADD_CUSTOM_TARGET(libXPwn.a
-		COMMAND ${CMAKE_C_COMPILER}
+		COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS}
 			-L${PROJECT_BINARY_DIR}/ipsw-patch -L${PROJECT_BINARY_DIR}/dmg -L${PROJECT_BINARY_DIR}/hfs
 			-L${PROJECT_BINARY_DIR}/hfs -L${PROJECT_BINARY_DIR}/minizip -L${PROJECT_BINARY_DIR}/common
 			-Xlinker --whole-archive -lxpwn -ldmg -lhfs -lcommon -lminizip</diff>
      <filename>ipsw-patch/CMakeLists.txt</filename>
    </modified>
    <modified>
      <diff>@@ -194,6 +194,10 @@ void pngError(png_structp png_ptr, png_const_charp error_msg) {
 	exit(0);
 }
 
+void pngWarn(png_structp png_ptr, png_const_charp error_msg) {
+	XLOG(0, &quot;warning: %s\n&quot;, error_msg);
+}
+
 int convertToPNG(AbstractFile* imageWrapper, const unsigned int* key, const unsigned int* iv, const char* png) {
 	AbstractFile* imageFile;
 
@@ -208,7 +212,7 @@ int convertToPNG(AbstractFile* imageWrapper, const unsigned int* key, const unsi
 	}
 	InfoIBootIM* info = (InfoIBootIM*) (imageFile-&gt;data);
 
-	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngError);
+	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngWarn);
 	if (!png_ptr) {
 		return -1;
 	}
@@ -226,11 +230,15 @@ int convertToPNG(AbstractFile* imageWrapper, const unsigned int* key, const unsi
 	int bytes_per_pixel;
 
 	if(info-&gt;header.format == IBOOTIM_ARGB) {
+		XLOG(3, &quot;ARGB&quot;);
 		color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 		bytes_per_pixel = 4;
 	} else if(info-&gt;header.format == IBOOTIM_GREY) {
+		XLOG(3, &quot;Grayscale&quot;);
 		color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
 		bytes_per_pixel = 2;
+	} else {
+		XLOG(3, &quot;Unknown color type!&quot;);
 	}
 
 	png_set_IHDR(png_ptr, info_ptr, info-&gt;header.width, info-&gt;header.height,
@@ -278,7 +286,7 @@ void* replaceBootImage(AbstractFile* imageWrapper, const unsigned int* key, cons
 	}
 	png-&gt;seek(png, 0);
 
-	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngError);
+	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngWarn);
 	if (!png_ptr) {
 		return NULL;
 	}
@@ -324,7 +332,7 @@ void* replaceBootImage(AbstractFile* imageWrapper, const unsigned int* key, cons
 	png_set_expand(png_ptr);
 	png_set_strip_16(png_ptr);
 	png_set_bgr(png_ptr);
-	png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
+	png_set_add_alpha(png_ptr, 0x0, PNG_FILLER_AFTER);
 	png_set_invert_alpha(png_ptr);
 	
 	png_read_update_info(png_ptr, info_ptr);</diff>
      <filename>ipsw-patch/ibootim.c</filename>
    </modified>
    <modified>
      <diff>@@ -2,6 +2,95 @@
 #include &lt;string.h&gt;
 #include &quot;common.h&quot;
 #include &lt;xpwn/img3.h&gt;
+#include &lt;xpwn/libxpwn.h&gt;
+
+static const uint8_t x24kpwn_overflow_data[] = {
+  0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xac, 0x05, 0x81, 0x12,
+  0x00, 0x00, 0x01, 0x02, 0x03, 0x01, 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00,
+  0x00, 0x40, 0x01, 0x00, 0x1c, 0x40, 0x02, 0x22, 0x1c, 0x40, 0x02, 0x22,
+  0x04, 0x09, 0x00, 0x00, 0x2c, 0x40, 0x02, 0x22, 0x6b, 0x73, 0x61, 0x74,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61,
+  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x6b, 0x73, 0x74,
+  0xc0, 0x40, 0x02, 0x22, 0xc0, 0x40, 0x02, 0x22, 0xc8, 0x40, 0x02, 0x22,
+  0xc8, 0x40, 0x02, 0x22, 0x84, 0x53, 0x02, 0x22, 0x00, 0x00, 0x00, 0x38,
+  0x04, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x38,
+  0x10, 0x00, 0x00, 0x38, 0x20, 0x00, 0x00, 0x38, 0x24, 0x00, 0x00, 0x38,
+  0x28, 0x00, 0x00, 0x38, 0x2c, 0x00, 0x00, 0x38, 0x30, 0x00, 0x00, 0x38,
+  0x24, 0xfe, 0x02, 0x22
+};
+
+static const uint8_t x24kpwn_payload_data[] = {
+  0x0d, 0x48, 0x0c, 0x49, 0x08, 0x60, 0x0a, 0x48, 0x08, 0x49, 0x08, 0x60,
+  0x06, 0x48, 0x85, 0x46, 0x0e, 0xb0, 0x00, 0x20, 0x1c, 0xbc, 0x90, 0x46,
+  0x9a, 0x46, 0xa3, 0x46, 0xf0, 0xbc, 0x02, 0xbc, 0x00, 0x20, 0x00, 0x25,
+  0x05, 0x49, 0x08, 0x47, 0xd4, 0xfe, 0x02, 0x22, 0x20, 0x00, 0x00, 0x22,
+  0xAA, 0xBB, 0xCC, 0xDD, 0xfc, 0x40, 0x02, 0x22, 0x40, 0x00, 0x00, 0x38,
+  0xcf, 0x22, 0x00, 0x00
+};
+
+static const uint8_t n8824kpwn_overflow_data[] = {
+	0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x06,
+	0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x20, 0x40, 0x02, 0x84,
+	0x20, 0x40, 0x02, 0x84, 0x04, 0x09, 0x00, 0x00, 0x30, 0x40, 0x02, 0x84,
+	0x6b, 0x73, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6f, 0x6f, 0x74,
+	0x73, 0x74, 0x72, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x32, 0x6b, 0x73, 0x74, 0xc4, 0x40, 0x02, 0x84, 0xc4, 0x40, 0x02, 0x84,
+	0xcc, 0x40, 0x02, 0x84, 0xcc, 0x40, 0x02, 0x84, 0x01, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x01, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x01, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x01, 0x01, 0x07, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x10, 0x83, 0x00, 0x00, 0x10, 0x83,
+	0x00, 0x00, 0x10, 0x80, 0x04, 0x00, 0x10, 0x80, 0x08, 0x00, 0x10, 0x80,
+	0x0c, 0x00, 0x10, 0x80, 0x10, 0x00, 0x10, 0x80, 0x20, 0x00, 0x10, 0x80,
+	0x24, 0x00, 0x10, 0x80, 0x28, 0x00, 0x10, 0x80, 0x2c, 0x00, 0x10, 0x80,
+	0x30, 0x00, 0x10, 0x80, 0xf4, 0x3d, 0x03, 0x84
+};
+
+static const uint8_t n8824kpwn_payload_data[] = {
+	0x09, 0x48, 0x0a, 0x49, 0x01, 0x60, 0x0a, 0x48, 0x0a, 0x49, 0x01, 0x60,
+	0x0b, 0x48, 0x85, 0x46, 0x1c, 0xbc, 0x90, 0x46, 0x9a, 0x46, 0xa3, 0x46,
+	0xf0, 0xbc, 0x01, 0xbc, 0x06, 0x48, 0x00, 0x21, 0x01, 0x60, 0x07, 0x48,
+	0x00, 0x47, 0x00, 0x00, 0xcc, 0x41, 0x02, 0x84, 0x40, 0x00, 0x10, 0x80,
+	0x40, 0x00, 0x00, 0x84, 0xAA, 0xBB, 0xCC, 0xDD, 0x30, 0x3f, 0x03, 0x84,
+	0xfc, 0x3e, 0x03, 0x84, 0x73, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
 
 #ifdef HAVE_HW_CRYPTO
 #include &lt;stdint.h&gt;
@@ -73,9 +162,9 @@ IOReturn doAES(io_connect_t conn, void* inbuf, void *outbuf, uint32_t size, IOAE
 
 #endif
 
-void writeImg3Element(AbstractFile* file, Img3Element* element);
+void writeImg3Element(AbstractFile* file, Img3Element* element, Img3Info* info);
 
-void writeImg3Root(AbstractFile* file, Img3Element* element);
+void writeImg3Root(AbstractFile* file, Img3Element* element, Img3Info* info);
 
 void flipAppleImg3Header(AppleImg3Header* header) {
 	FLIPENDIANLE(header-&gt;magic);
@@ -88,6 +177,11 @@ void flipAppleImg3RootExtra(AppleImg3RootExtra* extra) {
 	FLIPENDIANLE(extra-&gt;name);
 }
 
+flipAppleImg3KBAGHeader(AppleImg3KBAGHeader* data) {
+	FLIPENDIANLE(data-&gt;key_modifier);
+	FLIPENDIANLE(data-&gt;key_bits);
+}
+
 size_t readImg3(AbstractFile* file, void* data, size_t len) {
 	Img3Info* info = (Img3Info*) file-&gt;data;
 	memcpy(data, (void*)((uint8_t*)info-&gt;data-&gt;data + (uint32_t)info-&gt;offset), len);
@@ -141,10 +235,24 @@ void closeImg3(AbstractFile* file) {
 			AES_cbc_encrypt(info-&gt;data-&gt;data, info-&gt;data-&gt;data, (info-&gt;data-&gt;header-&gt;dataSize / 16) * 16, &amp;(info-&gt;encryptKey), ivec, AES_ENCRYPT);
 		}
 
+		if(info-&gt;exploit24k) {
+			info-&gt;replaceDWord = *((uint32_t*) info-&gt;data-&gt;data);
+			FLIPENDIANLE(info-&gt;replaceDWord);
+			*((uint32_t*) info-&gt;data-&gt;data) = 0x22023001;
+			flipEndianLE(info-&gt;data-&gt;data, 4);
+		}
+
+		if(info-&gt;exploitN8824k) {
+			info-&gt;replaceDWord = *((uint32_t*) info-&gt;data-&gt;data);
+			FLIPENDIANLE(info-&gt;replaceDWord);
+			*((uint32_t*) info-&gt;data-&gt;data) = 0x84023001;
+			flipEndianLE(info-&gt;data-&gt;data, 4);
+		}
+
 		info-&gt;file-&gt;seek(info-&gt;file, 0);
 		info-&gt;root-&gt;header-&gt;dataSize = 0;	/* hack to make certain writeImg3Element doesn't preallocate */
 		info-&gt;root-&gt;header-&gt;size = 0;
-		writeImg3Element(info-&gt;file, info-&gt;root);
+		writeImg3Element(info-&gt;file, info-&gt;root, info);
 	}
 
 	info-&gt;root-&gt;free(info-&gt;root);
@@ -237,7 +345,7 @@ void readImg3Root(AbstractFile* file, Img3Element* element) {
 	element-&gt;free = freeImg3Root;
 }
 
-void writeImg3Root(AbstractFile* file, Img3Element* element) {
+void writeImg3Root(AbstractFile* file, Img3Element* element, Img3Info* info) {
 	AppleImg3RootHeader* header;
 	Img3Element* current;
 	off_t curPos;
@@ -255,7 +363,11 @@ void writeImg3Root(AbstractFile* file, Img3Element* element) {
 			header-&gt;extra.shshOffset = (uint32_t)(file-&gt;tell(file) - sizeof(AppleImg3RootHeader));
 		}
 
-		writeImg3Element(file, current);
+		if(current-&gt;header-&gt;magic != IMG3_KBAG_MAGIC || info-&gt;encrypted)
+		{
+			writeImg3Element(file, current, info);
+		}
+
 		current = current-&gt;next;
 	}
 
@@ -273,7 +385,7 @@ void writeImg3Root(AbstractFile* file, Img3Element* element) {
 	file-&gt;seek(file, header-&gt;base.size);
 }
 
-void writeImg3Default(AbstractFile* file, Img3Element* element) {
+void writeImg3Default(AbstractFile* file, Img3Element* element, Img3Info* info) {
 	const char zeros[0x10] = {0};
 	file-&gt;write(file, element-&gt;data, element-&gt;header-&gt;dataSize);
 	if((element-&gt;header-&gt;size - sizeof(AppleImg3Header)) &gt; element-&gt;header-&gt;dataSize) {
@@ -281,16 +393,66 @@ void writeImg3Default(AbstractFile* file, Img3Element* element) {
 	}
 }
 
-void writeImg3Element(AbstractFile* file, Img3Element* element) {
+void writeImg3KBAG(AbstractFile* file, Img3Element* element, Img3Info* info) {
+	flipAppleImg3KBAGHeader((AppleImg3KBAGHeader*) element-&gt;data);
+	writeImg3Default(file, element, info);
+	flipAppleImg3KBAGHeader((AppleImg3KBAGHeader*) element-&gt;data);
+}
+
+void do24kpwn(Img3Info* info, Img3Element* element, off_t curPos, const uint8_t* overflow, size_t overflow_size, const uint8_t* payload, size_t payload_size)
+{
+	off_t sizeRequired = (0x24000 + overflow_size) - curPos;
+	off_t dataRequired = sizeRequired - sizeof(AppleImg3Header);
+	element-&gt;data = realloc(element-&gt;data, dataRequired);
+	memset(((uint8_t*)element-&gt;data) + element-&gt;header-&gt;dataSize, 0, dataRequired - element-&gt;header-&gt;dataSize);
+	uint32_t overflowOffset = 0x24000 - (curPos + sizeof(AppleImg3Header));
+	uint32_t payloadOffset = 0x23000 - (curPos + sizeof(AppleImg3Header));
+
+	memcpy(((uint8_t*)element-&gt;data) + overflowOffset, overflow, overflow_size);
+	memcpy(((uint8_t*)element-&gt;data) + payloadOffset, payload, payload_size);
+
+	uint32_t* i;
+	for(i = (uint32_t*)(((uint8_t*)element-&gt;data) + payloadOffset);
+			i &lt; (uint32_t*)(((uint8_t*)element-&gt;data) + payloadOffset + payload_size);
+			i++) {
+		uint32_t candidate = *i;
+		FLIPENDIANLE(candidate);
+		if(candidate == 0xDDCCBBAA) {
+			candidate = info-&gt;replaceDWord;
+			FLIPENDIANLE(candidate);
+			*i = candidate;
+			break;
+		}
+	}
+
+	element-&gt;header-&gt;size = sizeRequired;
+	element-&gt;header-&gt;dataSize = dataRequired;
+}
+
+void writeImg3Element(AbstractFile* file, Img3Element* element, Img3Info* info) {
 	off_t curPos;
 
+	if(info-&gt;exploit24k &amp;&amp; element-&gt;header-&gt;magic == IMG3_TYPE_MAGIC) {
+		// Drop TYPE tag for exploited LLB, because it throws off our payload calculations
+		// Bootrom shouldn't care anyway, and kernel currently doesn't care
+		return;
+	}
+
 	curPos = file-&gt;tell(file);
 
+	if(element-&gt;header-&gt;magic == IMG3_CERT_MAGIC) {
+		if(info-&gt;exploit24k) {
+			do24kpwn(info, element, curPos, x24kpwn_overflow_data, sizeof(x24kpwn_overflow_data), x24kpwn_payload_data, sizeof(x24kpwn_payload_data));
+		} else if(info-&gt;exploitN8824k) {
+			do24kpwn(info, element, curPos, n8824kpwn_overflow_data, sizeof(n8824kpwn_overflow_data), n8824kpwn_payload_data, sizeof(n8824kpwn_payload_data));
+		}
+	}
+
 	flipAppleImg3Header(element-&gt;header);
 	file-&gt;write(file, element-&gt;header, sizeof(AppleImg3Header));
 	flipAppleImg3Header(element-&gt;header);
 
-	element-&gt;write(file, element);
+	element-&gt;write(file, element, info);
 
 	file-&gt;seek(file, curPos + element-&gt;header-&gt;size);
 }
@@ -315,6 +477,14 @@ Img3Element* readImg3Element(AbstractFile* file) {
 			readImg3Root(file, toReturn);
 			break;
 
+		case IMG3_KBAG_MAGIC:
+			toReturn-&gt;data = (unsigned char*) malloc(header-&gt;dataSize);
+			toReturn-&gt;write = writeImg3KBAG;
+			toReturn-&gt;free = freeImg3Default;
+			file-&gt;read(file, toReturn-&gt;data, header-&gt;dataSize);
+			flipAppleImg3KBAGHeader((AppleImg3KBAGHeader*) toReturn-&gt;data);
+			break;
+
 		default:
 			toReturn-&gt;data = (unsigned char*) malloc(header-&gt;dataSize);
 			toReturn-&gt;write = writeImg3Default;
@@ -345,6 +515,7 @@ AbstractFile* createAbstractFileFromImg3(AbstractFile* file) {
 	info-&gt;data = NULL;
 	info-&gt;cert = NULL;
 	info-&gt;kbag = NULL;
+	info-&gt;type = NULL;
 	info-&gt;encrypted = FALSE;
 
 	current = (Img3Element*) info-&gt;root-&gt;data;
@@ -355,6 +526,9 @@ AbstractFile* createAbstractFileFromImg3(AbstractFile* file) {
 		if(current-&gt;header-&gt;magic == IMG3_CERT_MAGIC) {
 			info-&gt;cert = current;
 		}
+		if(current-&gt;header-&gt;magic == IMG3_TYPE_MAGIC) {
+			info-&gt;type = current;
+		}
 		if(current-&gt;header-&gt;magic == IMG3_KBAG_MAGIC &amp;&amp; ((AppleImg3KBAGHeader*)current-&gt;data)-&gt;key_modifier == 1) {
 			info-&gt;kbag = current;
 		}
@@ -363,6 +537,8 @@ AbstractFile* createAbstractFileFromImg3(AbstractFile* file) {
 
 	info-&gt;offset = 0;
 	info-&gt;dirty = FALSE;
+	info-&gt;exploit24k = FALSE;
+	info-&gt;exploitN8824k = FALSE;
 	info-&gt;encrypted = FALSE;
 
 	toReturn = (AbstractFile*) malloc(sizeof(AbstractFile2));
@@ -385,31 +561,56 @@ AbstractFile* createAbstractFileFromImg3(AbstractFile* file) {
 		keySeed = (uint8_t*) malloc(keySeedLen);
 		memcpy(keySeed, (uint8_t*)((AppleImg3KBAGHeader*)info-&gt;kbag-&gt;data) + sizeof(AppleImg3KBAGHeader), keySeedLen);
 #ifdef HAVE_HW_CRYPTO
+		printf(&quot;Have hardware crypto\n&quot;);
 		CFMutableDictionaryRef dict = IOServiceMatching(&quot;IOAESAccelerator&quot;);
 		io_service_t dev = IOServiceGetMatchingService(kIOMasterPortDefault, dict);
 		io_connect_t conn = 0;
 		IOServiceOpen(dev, mach_task_self(), 0, &amp;conn);
-		doAES(conn, keySeed, keySeed, keySeedLen, GID, NULL, NULL, kIOAESAcceleratorDecrypt);
-		IOServiceClose(conn);
-		IOObjectRelease(dev);
-
-		unsigned int key[keySeedLen - 16];
-		unsigned int iv[16];
 
 		int i;
-		for(i = 0; i &lt; 16; i++)
-			iv[i] = keySeed[i];
+		printf(&quot;KeySeed: &quot;);
+		for(i = 0; i &lt; keySeedLen; i++)
+		{
+			printf(&quot;%02x&quot;, keySeed[i]);
+		}
+		printf(&quot;\n&quot;);
 
-		for(i = 0; i &lt; (keySeedLen - 16); i++)
-			key[i] = keySeed[i + 16];
+		if(doAES(conn, keySeed, keySeed, keySeedLen, GID, NULL, NULL, kIOAESAcceleratorDecrypt) == 0) {
+			unsigned int key[keySeedLen - 16];
+			unsigned int iv[16];
+
+			printf(&quot;IV: &quot;);
+			for(i = 0; i &lt; 16; i++)
+			{
+				iv[i] = keySeed[i];
+				printf(&quot;%02x&quot;, iv[i]);
+			}
+			printf(&quot;\n&quot;);
+
+			printf(&quot;Key: &quot;);
+			for(i = 0; i &lt; (keySeedLen - 16); i++)
+			{
+				key[i] = keySeed[i + 16];
+				printf(&quot;%02x&quot;, key[i]);
+			}
+			printf(&quot;\n&quot;);
+
+			setKeyImg3(abstractFile2, key, iv);
+		}
 
-		setKeyImg3(abstractFile2, key, iv);
+		IOServiceClose(conn);
+		IOObjectRelease(dev);
 #else
 		int i = 0;
+		char outputBuffer[256];
+		char curBuffer[256];
+		outputBuffer[0] = '\0';
 		for(i = 0; i &lt; keySeedLen; i++) {
-			printf(&quot;%02x&quot;, keySeed[i]);
+			sprintf(curBuffer, &quot;%02x&quot;, keySeed[i]);
+			strcat(outputBuffer, curBuffer);
 		}
-		printf(&quot;\n&quot;);
+		strcat(outputBuffer, &quot;\n&quot;);
+		XLOG(4, outputBuffer);
 #endif
 		free(keySeed);
 	}
@@ -451,3 +652,14 @@ AbstractFile* duplicateImg3File(AbstractFile* file, AbstractFile* backing) {
 	return toReturn;
 }
 
+void exploit24kpwn(AbstractFile* file) {
+	Img3Info* info = (Img3Info*) file-&gt;data;
+	info-&gt;exploit24k = TRUE;
+	info-&gt;dirty = TRUE;
+}
+
+void exploitN8824kpwn(AbstractFile* file) {
+	Img3Info* info = (Img3Info*) file-&gt;data;
+	info-&gt;exploitN8824k = TRUE;
+	info-&gt;dirty = TRUE;
+}</diff>
      <filename>ipsw-patch/img3.c</filename>
    </modified>
    <modified>
      <diff>@@ -33,9 +33,11 @@ void libxpwn_loglevel(int logLevel) {
 }
 
 void Log(int level, const char* file, unsigned int line, const char* function, const char* format, ...) {
+#ifdef HARD_LOG
 	static FILE* logFile = NULL;
 	if(logFile == NULL)
 		logFile = fopen(&quot;log.txt&quot;, &quot;w&quot;);
+#endif
 
 	char mainBuffer[1024];
 	char buffer[1024];
@@ -58,8 +60,11 @@ void Log(int level, const char* file, unsigned int line, const char* function, c
 			snprintf(mainBuffer, sizeof(mainBuffer), &quot;%s:%s:%d: %s&quot;, file, function, line, buffer);
 	}
 	logCallback(mainBuffer);
+
+#ifdef HARD_LOG
 	strcat(mainBuffer, &quot;\n&quot;);
 	fwrite(mainBuffer, 1, strlen(mainBuffer), logFile);
 	fflush(logFile);
+#endif
 }
 </diff>
      <filename>ipsw-patch/libxpwn.c</filename>
    </modified>
    <modified>
      <diff>@@ -4,6 +4,7 @@
 #include &quot;abstractfile.h&quot;
 #include &lt;xpwn/lzssfile.h&gt;
 #include &lt;xpwn/lzss.h&gt;
+#include &lt;xpwn/libxpwn.h&gt;
 
 void flipCompHeader(CompHeader* header) {
 	FLIPENDIAN(header-&gt;signature);
@@ -108,13 +109,13 @@ AbstractFile* createAbstractFileFromComp(AbstractFile* file) {
 
 	uint32_t real_uncompressed = decompress_lzss(info-&gt;buffer, compressed, info-&gt;header.length_compressed);
 	if(real_uncompressed != info-&gt;header.length_uncompressed) {
-		printf(&quot;mismatch: %d %d %d %x %x\n&quot;, info-&gt;header.length_compressed, real_uncompressed, info-&gt;header.length_uncompressed, compressed[info-&gt;header.length_compressed - 2], compressed[info-&gt;header.length_compressed - 1]);
+		XLOG(5, &quot;mismatch: %d %d %d %x %x\n&quot;, info-&gt;header.length_compressed, real_uncompressed, info-&gt;header.length_uncompressed, compressed[info-&gt;header.length_compressed - 2], compressed[info-&gt;header.length_compressed - 1]);
 		free(compressed);
 		free(info);
 		return NULL;
 	}
 
-	printf(&quot;match: %d %d %d %x %x\n&quot;, info-&gt;header.length_compressed, real_uncompressed, info-&gt;header.length_uncompressed, compressed[info-&gt;header.length_compressed - 2], compressed[info-&gt;header.length_compressed - 1]);
+	XLOG(5, &quot;match: %d %d %d %x %x\n&quot;, info-&gt;header.length_compressed, real_uncompressed, info-&gt;header.length_uncompressed, compressed[info-&gt;header.length_compressed - 2], compressed[info-&gt;header.length_compressed - 1]);
 	
 	free(compressed);
 </diff>
      <filename>ipsw-patch/lzssfile.c</filename>
    </modified>
    <modified>
      <diff>@@ -343,14 +343,14 @@ int main(int argc, char* argv[]) {
 
 	size_t defaultRootSize = ((IntegerValue*) getValueByKey(info, &quot;RootFilesystemSize&quot;))-&gt;value;
 	minimumRootSize = defaultRootSize * 1000 * 1000;
-	minimumRootSize -= minimumRootSize % 4096;
+	minimumRootSize -= minimumRootSize % 512;
 
 	if(preferredRootSize == 0) {	
 		preferredRootSize = defaultRootSize;
 	}
 
 	rootSize =  preferredRootSize * 1000 * 1000;
-	rootSize -= rootSize % 4096;
+	rootSize -= rootSize % 512;
 
 	if(useMemory) {
 		buffer = malloc(rootSize);
@@ -369,10 +369,10 @@ int main(int argc, char* argv[]) {
 	
 	rootFS = IOFuncFromAbstractFile(openRoot((void**)&amp;buffer, &amp;rootSize));
 	rootVolume = openVolume(rootFS);
-	XLOG(0, &quot;Growing root to minimum: %lu\n&quot;, (unsigned long int) minimumRootSize); fflush(stdout);
+	XLOG(0, &quot;Growing root to minimum: %ld\n&quot;, (long) defaultRootSize); fflush(stdout);
 	grow_hfs(rootVolume, minimumRootSize);
 	if(rootSize &gt; minimumRootSize) {
-		XLOG(0, &quot;Growing root: %lu\n&quot;, (unsigned long int) rootSize); fflush(stdout);
+		XLOG(0, &quot;Growing root: %ld\n&quot;, (long) preferredRootSize); fflush(stdout);
 		grow_hfs(rootVolume, rootSize);
 	}
 	
@@ -476,7 +476,7 @@ int main(int argc, char* argv[]) {
 	closeVolume(rootVolume);
 	CLOSE(rootFS);
 
-	buildDmg(openRoot((void**)&amp;buffer, &amp;rootSize), getFileFromOutputStateForReplace(&amp;outputState, rootFSPathInIPSW));
+	buildDmg(openRoot((void**)&amp;buffer, &amp;rootSize), getFileFromOutputStateForReplace(&amp;outputState, rootFSPathInIPSW), 2048);
 
 	closeRoot(buffer);
 </diff>
      <filename>ipsw-patch/main.c</filename>
    </modified>
    <modified>
      <diff>@@ -67,7 +67,7 @@ AbstractFile* duplicateAbstractFile(AbstractFile* file, AbstractFile* backing) {
 	}
 }
 
-AbstractFile* openAbstractFile2(AbstractFile* file, const unsigned int* key, const unsigned int* iv) {
+AbstractFile* openAbstractFile3(AbstractFile* file, const unsigned int* key, const unsigned int* iv, int layers) {
 	uint32_t signatureBE;
 	uint32_t signatureLE;
 
@@ -81,21 +81,38 @@ AbstractFile* openAbstractFile2(AbstractFile* file, const unsigned int* key, con
 	FLIPENDIANLE(signatureLE);
 	file-&gt;seek(file, 0);
 
+	AbstractFile* cur;
 	if(signatureBE == SIGNATURE_8900) {
-		return openAbstractFile2(createAbstractFileFrom8900(file), key, iv);
+		cur = createAbstractFileFrom8900(file);
 	} else if(signatureLE == IMG2_SIGNATURE) {
-		return openAbstractFile2(createAbstractFileFromImg2(file), key, iv);
+		cur = createAbstractFileFromImg2(file);
 	} else if(signatureLE == IMG3_SIGNATURE) {
 		AbstractFile2* img3 = (AbstractFile2*) createAbstractFileFromImg3(file);
-		img3-&gt;setKey(img3, key, iv);
-		return openAbstractFile((AbstractFile*) img3);
+		if(key &amp;&amp; iv)
+			img3-&gt;setKey(img3, key, iv);
+		cur = (AbstractFile*) img3;
+		key = NULL;
+		iv = NULL;
 	} else if(signatureBE == COMP_SIGNATURE) {
-		return openAbstractFile(createAbstractFileFromComp(file));
+		cur = createAbstractFileFromComp(file);
+		key = NULL;
+		iv = NULL;
 	} else if(signatureBE == IBOOTIM_SIG_UINT) {
-		return openAbstractFile(createAbstractFileFromIBootIM(file));
+		cur = createAbstractFileFromIBootIM(file);
+		key = NULL;
+		iv = NULL;
 	} else {
 		return file;
 	}
+
+	if(layers &lt; 0 || layers &gt; 0)	
+		return openAbstractFile3(cur, key, iv, layers - 1);
+	else
+		return cur;
+}
+
+AbstractFile* openAbstractFile2(AbstractFile* file, const unsigned int* key, const unsigned int* iv) {
+	return openAbstractFile3(file, key, iv, -1);
 }
 
 AbstractFile* duplicateAbstractFile2(AbstractFile* file, AbstractFile* backing, const unsigned int* key, const unsigned int* iv, AbstractFile* certificate) {</diff>
      <filename>ipsw-patch/nor_files.c</filename>
    </modified>
    <modified>
      <diff>@@ -59,6 +59,7 @@ Dictionary* parseIPSW2(const char* inputIPSW, const char* bundleRoot, char** bun
 
 	dir = opendir(bundleRoot);
 	if(dir == NULL) {
+		XLOG(1, &quot;Bundles directory not found\n&quot;);
 		return NULL;
 	}
 
@@ -249,6 +250,52 @@ void doPatchInPlace(Volume* volume, const char* filePath, const char* patchPath)
 	XLOG(0, &quot;success\n&quot;); fflush(stdout);
 }
 
+void doPatchInPlaceMemoryPatch(Volume* volume, const char* filePath, void** patchData, size_t* patchSize) {
+	void* buffer;
+	void* buffer2;
+	size_t bufferSize;
+	size_t bufferSize2;
+	AbstractFile* bufferFile;
+	AbstractFile* patchFile;
+	AbstractFile* out;
+	
+	buffer = malloc(1);
+	bufferSize = 0;
+	bufferFile = createAbstractFileFromMemoryFile((void**)&amp;buffer, &amp;bufferSize);
+
+	XLOG(0, &quot;retrieving...&quot;); fflush(stdout);
+	get_hfs(volume, filePath, bufferFile);
+	bufferFile-&gt;close(bufferFile);
+	
+	XLOG(0, &quot;patching...&quot;); fflush(stdout);
+				
+	patchFile = createAbstractFileFromMemoryFile(patchData, patchSize);
+
+	buffer2 = malloc(1);
+	bufferSize2 = 0;
+	out = duplicateAbstractFile(createAbstractFileFromMemoryFile((void**)&amp;buffer, &amp;bufferSize), createAbstractFileFromMemoryFile((void**)&amp;buffer2, &amp;bufferSize2));
+
+	// reopen the inner package
+	bufferFile = openAbstractFile(createAbstractFileFromMemoryFile((void**)&amp;buffer, &amp;bufferSize));
+	
+	if(!patchFile || !bufferFile || !out) {
+		XLOG(0, &quot;file error\n&quot;);
+		exit(0);
+	}
+
+	if(patch(bufferFile, out, patchFile) != 0) {
+		XLOG(0, &quot;patch failed\n&quot;);
+		exit(0);
+	}
+	
+	XLOG(0, &quot;writing... &quot;); fflush(stdout);
+	add_hfs(volume, createAbstractFileFromMemoryFile((void**)&amp;buffer2, &amp;bufferSize2), filePath);
+	free(buffer2);
+	free(buffer);
+
+	XLOG(0, &quot;success\n&quot;); fflush(stdout);
+}
+
 void createRestoreOptions(Volume* volume, int SystemPartitionSize, int UpdateBaseband) {
 	const char optionsPlist[] = &quot;/usr/local/share/restore/options.plist&quot;;
 	AbstractFile* plistFile;
@@ -325,11 +372,21 @@ void fixupBootNeuterArgs(Volume* volume, char unlockBaseband, char selfDestruct,
 
 int patchSigCheck(AbstractFile* file) {
 	const uint8_t patch[] = {0x01, 0xE0, 0x01, 0x20, 0x40, 0x42, 0x88, 0x23};
+
+	// for 3gs, signature check
+	const uint8_t patch2[] = {0x08, 0xB1, 0x4F, 0xF0, 0xFF, 0x30, 0xA7, 0xF1, 0x10, 0x0D};
 	
+	// for 3gs, prod check
+	const uint8_t patch3[] = {0x03, 0x94, 0xFF, 0xF7, 0x11, 0xFF, 0x04, 0x46};
+
+	// for 3gs, ecid check
+	const uint8_t patch4[] = {0x50, 0x46, 0xFF, 0xF7, 0xB1, 0xFE, 0x04, 0x46};
+
 	size_t length = file-&gt;getLength(file);
-	uint8_t* buffer = (uint8_t*)malloc(length);
+	uint8_t* buffer = (uint8_t*)malloc(length + sizeof(patch2));
 	file-&gt;seek(file, 0);
 	file-&gt;read(file, buffer, length);
+	memset(buffer + length, 0, sizeof(patch2));
 	
 	int retval = FALSE;
 	int i;
@@ -341,6 +398,40 @@ int patchSigCheck(AbstractFile* file) {
 			file-&gt;seek(file, i);
 			file-&gt;write(file, candidate, sizeof(patch));
 			retval = TRUE;
+			XLOG(3, &quot;iBoot armv6 signature check patch success\n&quot;); fflush(stdout);
+			continue;
+		}
+		if(memcmp(candidate, patch2, sizeof(patch2)) == 0) {
+			candidate[2] = 0x0;
+			candidate[3] = 0x20;
+			candidate[4] = 0x0;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch2));
+			retval = TRUE;
+			XLOG(3, &quot;iBoot armv7 signature check patch success\n&quot;); fflush(stdout);
+			continue;
+		}
+		if(memcmp(candidate, patch3, sizeof(patch3)) == 0) {
+			candidate[2] = 0x0;
+			candidate[3] = 0x20;
+			candidate[4] = 0x0;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch3));
+			retval = TRUE;
+			XLOG(3, &quot;iBoot armv7 PROD check patch success\n&quot;); fflush(stdout);
+			continue;
+		}
+		if(memcmp(candidate, patch4, sizeof(patch4)) == 0) {
+			candidate[2] = 0x0;
+			candidate[3] = 0x20;
+			candidate[4] = 0x0;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch4));
+			retval = TRUE;
+			XLOG(3, &quot;iBoot armv7 ECID check patch success\n&quot;); fflush(stdout);
 			continue;
 		}
 	}
@@ -349,37 +440,84 @@ int patchSigCheck(AbstractFile* file) {
 	return retval;
 }
 
+int Do30Patches = TRUE;
+
 int patchKernel(AbstractFile* file) {
+	// codesign
 	const char patch[] = {0x00, 0x00, 0x00, 0x0A, 0x00, 0x40, 0xA0, 0xE3, 0x04, 0x00, 0xA0, 0xE1, 0x90, 0x80, 0xBD, 0xE8};
 
-	const char patch2[] = {0xFF, 0x50, 0xA0, 0xE3, 0x04, 0x00, 0xA0, 0xE1, 0x0A, 0x10, 0xA0, 0xE1};
+	const char patch_old[] = {0xFF, 0x50, 0xA0, 0xE3, 0x04, 0x00, 0xA0, 0xE1, 0x0A, 0x10, 0xA0, 0xE1};
 
+	// 2.0 vm_map max_prot
 	const char patch3[] = {0x99, 0x91, 0x43, 0x2B, 0x91, 0xCD, 0xE7, 0x04, 0x24, 0x1D, 0xB0};
 	
+	// 3.0 vm_map max_prot
+	const char patch2[] = {0x2E, 0xD1, 0x35, 0x98, 0x80, 0x07, 0x33, 0xD4, 0x6B, 0x08, 0x1E, 0x1C};
+
+	// 3.0 illb img3 patch 1
+	const char patch4[] = {0x98, 0x47, 0x00, 0x28, 0x00, 0xD0, 0xAE, 0xE0, 0x06, 0x98};
+
+	// 3.0 illb img3 patch 2
+	const char patch5[] = {0x05, 0x1E, 0x00, 0xD0, 0xA8, 0xE0, 0x03, 0x9B};
+
+	// 3.0 CS enforcement patch
+	const char patch6[] = {0x9C, 0x22, 0x03, 0x59, 0x99, 0x58};
+
+	// 3.0 armv7 vm_map_enter max_prot
+	const char n88patch1[] = {0x93, 0xBB, 0x16, 0xF0, 0x02, 0x0F, 0x40, 0xF0, 0x36, 0x80, 0x63, 0x08};
+
+	// 3.0 armv7 cs patch
+	const char n88patch2[] = {0x05, 0x4B, 0x98, 0x47, 0x00, 0xB1, 0x00, 0x24, 0x20, 0x46, 0x90, 0xBD};
+
+	// 3.0 armv7 cs_enforcement_disable patch
+	const char n88patch3[] = {0xD3, 0xF8, 0x9C, 0x20, 0xDF, 0xF8};
+
+	// 3.0 arm7 img3 prod patch
+	const char n88patch4[] = {0x03, 0x94, 0xFF, 0xF7, 0x29, 0xFF, 0xF8, 0xB1};
+
+	// 3.0 arm7 img3 ecid patch
+	const char n88patch5[] = {0x0C, 0xCA, 0xFF, 0xF7, 0x10, 0xFF, 0x00, 0x38};
+
+	// 3.0 arm7 img3 signature patch
+	const char n88patch6[] = {0x30, 0xE0, 0x4F, 0xF0, 0xFF, 0x30, 0x2D, 0xE0};
+
+	// 3.0 arm7 img3 signature patch
+	const char n88patch_test1[] = {0x67, 0x4B, 0x98, 0x47, 0x00, 0x28};
+
+	// 3.0 arm7 img3 signature patch
+	const char n88patch_test2[] = {0x04, 0x98, 0xFF, 0xF7, 0xD9, 0xFD, 0x04, 0x46};
+
+	// 3.0 arm7 img3 signature patch
+	const char n88patch_test3[] = {0x01, 0x99, 0xFF, 0xF7, 0xBE, 0xFC, 0x00, 0xB3};
+
 	size_t length = file-&gt;getLength(file);
-	uint8_t* buffer = (uint8_t*)malloc(length);
+	uint8_t* buffer = (uint8_t*)malloc(length + sizeof(patch));
 	file-&gt;seek(file, 0);
 	file-&gt;read(file, buffer, length);
+	memset(buffer + length, 0, sizeof(patch));
 	
 	int retval = 0;
 	int i;
 	for(i = 0; i &lt; length; i++) {
 		uint8_t* candidate = &amp;buffer[i];
 		if(memcmp(candidate, patch, sizeof(patch)) == 0) {
+			XLOG(3, &quot;kernel patch1 success\n&quot;); fflush(stdout);
 			candidate[4] = 0x01;
 			file-&gt;seek(file, i);
 			file-&gt;write(file, candidate, sizeof(patch));
 			retval = TRUE;
 			continue;
 		}
-		if(memcmp(candidate, patch2, sizeof(patch2)) == 0) {
-			candidate[0] = 0x00;
+		if(memcmp(candidate, patch_old, sizeof(patch_old)) == 0) {
+			XLOG(3, &quot;kernel patch_old success\n&quot;); fflush(stdout);
+			candidate[0] = 0x0;
 			file-&gt;seek(file, i);
-			file-&gt;write(file, candidate, sizeof(patch2));
+			file-&gt;write(file, candidate, sizeof(patch_old));
 			retval = TRUE;
 			continue;
 		}
 		if(memcmp(candidate, patch3, sizeof(patch3)) == 0) {
+			XLOG(3, &quot;kernel patch3 success\n&quot;); fflush(stdout);
 			candidate[0] = 0x2B;
 			candidate[1] = 0x99;
 			candidate[2] = 0x00;
@@ -389,6 +527,155 @@ int patchKernel(AbstractFile* file) {
 			retval = TRUE;
 			continue;
 		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, patch2, sizeof(patch2)) == 0) {
+			XLOG(3, &quot;kernel patch2 success\n&quot;); fflush(stdout);
+			// NOP out the BMI
+			candidate[6] = 0x00;
+			candidate[7] = 0x28;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch2));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, patch4, sizeof(patch4)) == 0) {
+			XLOG(3, &quot;kernel patch4 success\n&quot;); fflush(stdout);
+			candidate[3] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch4));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, patch5, sizeof(patch5)) == 0) {
+			XLOG(3, &quot;kernel patch5 success\n&quot;); fflush(stdout);
+			candidate[0] = 0x00;
+			candidate[1] = 0x25;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(patch5));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch1, sizeof(n88patch1)) == 0) {
+			XLOG(3, &quot;kernel armv7 vm_map_enter patch success\n&quot;); fflush(stdout);
+			candidate[6] = 0x8B;
+			candidate[7] = 0x46;
+			candidate[8] = 0x8B;
+			candidate[9] = 0x46;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch1));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch2, sizeof(n88patch2)) == 0) {
+			XLOG(3, &quot;kernel armv7 cs patch success\n&quot;); fflush(stdout);
+			candidate[6] = 0x1;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch2));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch4, sizeof(n88patch4)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 prod patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x00;
+			candidate[3] = 0x20;
+			candidate[4] = 0x00;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch4));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch5, sizeof(n88patch5)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 ecid patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x00;
+			candidate[3] = 0x20;
+			candidate[4] = 0x00;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch5));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch6, sizeof(n88patch6)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 signature patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x00;
+			candidate[3] = 0x20;
+			candidate[4] = 0x00;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch6));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch_test1, sizeof(n88patch_test1)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 ParseFirmwareFooter patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x00;
+			candidate[3] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch_test1));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch_test2, sizeof(n88patch_test2)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 CheckMetaTags patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x00;
+			candidate[3] = 0x20;
+			candidate[4] = 0x00;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch_test2));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch_test3, sizeof(n88patch_test3)) == 0) {
+			XLOG(3, &quot;kernel armv7 img3 encrypt SHSH with 89A patch success\n&quot;); fflush(stdout);
+			candidate[2] = 0x01;
+			candidate[3] = 0x20;
+			candidate[4] = 0x01;
+			candidate[5] = 0x20;
+			file-&gt;seek(file, i);
+			file-&gt;write(file, candidate, sizeof(n88patch_test3));
+			retval = TRUE;
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, patch6, sizeof(patch6)) == 0) {
+			if(candidate[7] != 0x4B)
+				continue;
+
+			uint32_t cs_enforcement_disable = *((uint32_t*)(((intptr_t)(&amp;candidate[6] + 0x4) &amp; ~0x3) + (0x4 * candidate[6])));
+			FLIPENDIANLE(cs_enforcement_disable);
+
+			uint32_t offset = cs_enforcement_disable - 0xC0008000;
+
+			XLOG(3, &quot;kernel cs_enforcement_disable at: 0x%X, 0x%X\n&quot;, cs_enforcement_disable, offset); fflush(stdout);
+
+			uint32_t value = 1;
+
+			FLIPENDIANLE(value);
+
+			*((uint32_t*)(buffer + offset)) = value;
+
+			file-&gt;seek(file, offset);
+			file-&gt;write(file, &amp;value, sizeof(value));
+			continue;
+		}
+		if(Do30Patches &amp;&amp; memcmp(candidate, n88patch3, sizeof(n88patch3)) == 0) {
+			uint32_t cs_enforcement_disable = *((uint32_t*)(((intptr_t)(&amp;candidate[4] + 0x4) &amp; ~0x3) + (((candidate[7] &amp; 0xF) &lt;&lt; 8) + candidate[6])));
+			FLIPENDIANLE(cs_enforcement_disable);
+
+			uint32_t offset = cs_enforcement_disable - 0xC0008000;
+
+			XLOG(3, &quot;kernel cs_enforcement_disable at: 0x%X, 0x%X\n&quot;, cs_enforcement_disable, offset); fflush(stdout);
+
+			uint32_t value = 1;
+
+			FLIPENDIANLE(value);
+
+			*((uint32_t*)(buffer + offset)) = value;
+
+			file-&gt;seek(file, offset);
+			file-&gt;write(file, &amp;value, sizeof(value));
+			continue;
+		}
 	}
 	
 	free(buffer);
@@ -400,9 +687,10 @@ int patchDeviceTree(AbstractFile* file) {
 	const char patch2[] = &quot;function-disable_keys&quot;;
 	
 	size_t length = file-&gt;getLength(file);
-	uint8_t* buffer = (uint8_t*)malloc(length);
+	uint8_t* buffer = (uint8_t*)malloc(length + sizeof(patch2));
 	file-&gt;seek(file, 0);
 	file-&gt;read(file, buffer, length);
+	memset(buffer + length, 0, sizeof(patch2));
 	
 	int retval = 0;
 	int i;</diff>
      <filename>ipsw-patch/pwnutil.c</filename>
    </modified>
    <modified>
      <diff>@@ -11,7 +11,7 @@ int main(int argc, char* argv[]) {
 	init_libxpwn();
 
 	if(argc &lt; 3) {
-		printf(&quot;usage: %s &lt;infile&gt; &lt;outfile&gt; [-t &lt;template&gt; [-c &lt;certificate&gt;]] [-k &lt;key&gt;] [-iv &lt;key&gt;]\n&quot;, argv[0]);
+		printf(&quot;usage: %s &lt;infile&gt; &lt;outfile&gt; [-x24k] [-t &lt;template&gt; [-c &lt;certificate&gt;]] [-k &lt;key&gt;] [-iv &lt;key&gt;] [-decrypt]\n&quot;, argv[0]);
 		return 0;
 	}
 
@@ -21,6 +21,8 @@ int main(int argc, char* argv[]) {
 	unsigned int* iv = NULL;
 	int hasKey = FALSE;
 	int hasIV = FALSE;
+	int x24k = FALSE;
+	int doDecrypt = FALSE;
 
 	int argNo = 3;
 	while(argNo &lt; argc) {
@@ -32,6 +34,15 @@ int main(int argc, char* argv[]) {
 			}
 		}
 
+		if(strcmp(argv[argNo], &quot;-decrypt&quot;) == 0) {
+			doDecrypt = TRUE;
+			template = createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;));
+			if(!template) {
+				fprintf(stderr, &quot;error: cannot open template\n&quot;);
+				return 1;
+			}
+		}
+
 		if(strcmp(argv[argNo], &quot;-c&quot;) == 0 &amp;&amp; (argNo + 1) &lt; argc) {
 			certificate = createAbstractFileFromFile(fopen(argv[argNo + 1], &quot;rb&quot;));
 			if(!certificate) {
@@ -52,14 +63,26 @@ int main(int argc, char* argv[]) {
 			hasIV = TRUE;
 		}
 
+		if(strcmp(argv[argNo], &quot;-x24k&quot;) == 0) {
+			x24k = TRUE;
+		}
+
 		argNo++;
 	}
 
 	AbstractFile* inFile;
-	if(hasKey) {
-		inFile = openAbstractFile2(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)), key, iv);
+	if(doDecrypt) {
+		if(hasKey) {
+			inFile = openAbstractFile3(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)), key, iv, 0);
+		} else {
+			inFile = openAbstractFile3(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)), NULL, NULL, 0);
+		}
 	} else {
-		inFile = openAbstractFile(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)));
+		if(hasKey) {
+			inFile = openAbstractFile2(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)), key, iv);
+		} else {
+			inFile = openAbstractFile(createAbstractFileFromFile(fopen(argv[1], &quot;rb&quot;)));
+		}
 	}
 	if(!inFile) {
 		fprintf(stderr, &quot;error: cannot open infile\n&quot;);
@@ -76,7 +99,7 @@ int main(int argc, char* argv[]) {
 	AbstractFile* newFile;
 
 	if(template) {
-		if(hasKey) {
+		if(hasKey &amp;&amp; !doDecrypt) {
 			newFile = duplicateAbstractFile2(template, outFile, key, iv, certificate);
 		} else {
 			newFile = duplicateAbstractFile2(template, outFile, NULL, NULL, certificate);
@@ -89,13 +112,19 @@ int main(int argc, char* argv[]) {
 		newFile = outFile;
 	}
 
-	if(hasKey) {
+	if(hasKey &amp;&amp; !doDecrypt) {
 		if(newFile-&gt;type == AbstractFileTypeImg3) {
 			AbstractFile2* abstractFile2 = (AbstractFile2*) newFile;
 			abstractFile2-&gt;setKey(abstractFile2, key, iv);
 		}
 	}
 
+	if(x24k) {
+		if(newFile-&gt;type == AbstractFileTypeImg3) {
+			exploit24kpwn(newFile);
+		}
+	}
+
 	inDataSize = (size_t) inFile-&gt;getLength(inFile);
 	inData = (char*) malloc(inDataSize);
 	inFile-&gt;read(inFile, inData, inDataSize);</diff>
      <filename>ipsw-patch/xpwntool.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>35b51a01b0f1a0a711896000d8aa7e2660fc2faf</id>
    </parent>
  </parents>
  <author>
    <name>planetbeing</name>
    <email>planetbeing@gmail.com</email>
  </author>
  <url>http://github.com/planetbeing/xpwn/commit/5c8b07519892de6a3a057aa0755b2e368d2a47db</url>
  <id>5c8b07519892de6a3a057aa0755b2e368d2a47db</id>
  <committed-date>2009-07-18T01:19:36-07:00</committed-date>
  <authored-date>2009-07-18T01:19:36-07:00</authored-date>
  <message>Imported a lot of stuff from dev team branch</message>
  <tree>e91e26b96f3ec9e52c741e83343bcc0971f90303</tree>
  <committer>
    <name>planetbeing</name>
    <email>planetbeing@gmail.com</email>
  </committer>
</commit>
