int dsreference_equal(dsreference *r1, dsreference *r2) { /* Compare UUID first, most unique. */ if (!IsNullUuid(r1->uuid) && !IsNullUuid(r2->uuid)) { if (memcmp(&r1->uuid, &r2->uuid, sizeof(dsuuid_t)) != 0) return 0; } if (r1->dn != NULL && r2->dn != NULL) { if (!dsdata_equal(r1->dn, r2->dn)) return 0; } if (r1->name != NULL && r2->name != NULL) { if (!dsdata_equal(r1->name, r2->name)) return 0; } if (r1->dsid != r2->dsid) return 0; if (r1->serial != r2->serial) return 0; if (r1->vers != r2->vers) return 0; if (r1->timestamp != r2->timestamp) return 0; return 1; }
int GptAllocFileCopy(HGPT hGPT, char *pszFileName, EFI_PARTITION_ENTRY *pNewEntry) { int i; int iPartition; QWORD qwLBA; int iErr; // To be cleaned up before return char *pSect = (char *)NULL; // End of clean-up zone int nSect; FILE *hf = NULL; // Compute the number of partition entries per sector. // int iEntryPerSect = hGPT->iSectorSize / sizeof(EFI_PARTITION_ENTRY); // Allocate a buffer to access drive data. pSect = (char *)malloc(hGPT->iSectorSize); if (!pSect) GptAllocFileCopyFail(-4); // Open the partition image file hf = fopen(pszFileName, "rb"); if (!hf) GptAllocFileCopyFail(-10); // Compute the number of sectors necessary. nSect = (int)((_filelength(_fileno(hf)) + hGPT->iSectorSize - 1) / hGPT->iSectorSize); // Search the smallest contiguous block of free sectors large enough. pNewEntry->EndingLBA = nSect; iPartition = GptAllocSectors(hGPT, pNewEntry); // Side effect: pNewEntry->PartitionTypeGUID = 0; if (iPartition < 0) GptAllocFileCopyFail(iPartition); #ifdef _DEBUG if (iVerbose) { printf("Allocating partition entry #%d for copying from file %s\n", iPartition, pszFileName); } #endif // Write the partition contents for (i=0, qwLBA=pNewEntry->StartingLBA; i<nSect; i++, qwLBA++) { size_t stRead; stRead = fread(pSect, 1, hGPT->iSectorSize, hf); if (stRead < (size_t)(hGPT->iSectorSize)) memset(pSect+stRead, 0, hGPT->iSectorSize-stRead); // ~~jfl 2001/12/19 Use the partition type GUID specified in the file, if any. if (i==0) { EFI_BOOT_PROGRAM_HEADER *pHdr = (EFI_BOOT_PROGRAM_HEADER *)pSect; if (CheckCrc(hGPT->iSectorSize, &(pHdr->Header))) { if (!memcmp(((char *)&(pHdr->Header.Signature))+3, "MBR32", 5)) { pNewEntry->PartitionTypeGUID = guidMbrBackup; // If it's inside the GPT, then it's the backup! } else // Assume it's a relay or a boot program (Including the boot menu). { // Both have a partition entry behind the header. pNewEntry->PartitionTypeGUID = pHdr->Partition.PartitionTypeGUID; } } else if ( (!memcmp(((char *)&(pHdr->Header.Signature))+3, "Relay", 5)) && (!uuidcmp(&(pHdr->Partition.PartitionTypeGUID), &guidRelay)) ) // It's a relay, but with the header incomplete (CRC not set yet). { pNewEntry->PartitionTypeGUID = guidRelay; // ~~jfl 2002/01/03 Update the partition header while we have it. uuid_create((uuid_t *)&(pHdr->Partition.UniquePartitionGUID)); // Generate a new GUID SetCrc(&(pHdr->Header)); } else if (IsMBR(pSect)) // Master Boot Record. Assume it's a hard disk. { pNewEntry->PartitionTypeGUID = guidHardDiskImage; } if (IsNullUuid((uuid_t*)&(pNewEntry->PartitionTypeGUID))) // Assume anything else is a floppy. { pNewEntry->PartitionTypeGUID = guidFloppyImage; } } iErr = GptBlockWrite(hGPT, qwLBA, 1, pSect); if (iErr) GptAllocFileCopyFail(-3); } copy_return: // Cleanup fclose(hf); free(pSect); return iPartition; }
int GptAllocSectors(HGPT hGPT, EFI_PARTITION_ENTRY *pNewEntry) { int iPartition; int iNewPartition = -1; QWORD qwFirst = qwZero; QWORD qwLast = qwZero; // To be cleaned up before return QWORD *pqwFirst = (QWORD *)NULL; QWORD *pqwLast = (QWORD *)NULL; char *pGptEntryBuf = (char *)NULL; // End of clean-up zone EFI_PARTITION_ENTRY *pPartEntry; DWORD dwGptSect; int iIndex; int iErr; int j; DWORD dwNewSector; int iNewIndex; int nBlocks = 1; #ifdef _DEBUG char szBuf1[20]; char szBuf2[20]; #endif QWORD qwForceSect = pNewEntry->StartingLBA; QWORD qwNSect = pNewEntry->EndingLBA; #ifdef _DEBUG if (iDebug) printf("GptAllocSectors(hBlockDev=%p, nSect=%s, forceSect=%s)\n", hGPT->hBlockDev, qwtox(qwNSect, szBuf1), qwtox(qwForceSect, szBuf2)); #endif // Compute the number of partition entries per sector. int iEntryPerSect = hGPT->iSectorSize / sizeof(EFI_PARTITION_ENTRY); // Allocate buffers to access drive data. pGptEntryBuf = (char *)malloc(hGPT->iSectorSize); if (!pGptEntryBuf) GptAllocSectorsFail(-4); pPartEntry = (EFI_PARTITION_ENTRY *)pGptEntryBuf; // Search the smallest contiguous block of free sectors large enough. // For that, build a list of the free disk areas. pqwFirst = (QWORD *)malloc(sizeof(QWORD) * (size_t)hGPT->pGptHdr->NumberOfPartitionEntries); pqwLast = (QWORD *)malloc(sizeof(QWORD) * (size_t)hGPT->pGptHdr->NumberOfPartitionEntries); if (!pqwFirst || !pqwLast) GptAllocSectorsFail(-4); // Initially, assume all the GPT-managed area is free. pqwFirst[0] = hGPT->pGptHdr->FirstUsableLBA; pqwLast[0] = hGPT->pGptHdr->LastUsableLBA; // Then progress negatively, removing chunks of allocated space. for (iPartition = 0, iIndex = 0, dwGptSect=(DWORD)(hGPT->pGptHdr->PartitionEntryLBA); iPartition < (int)(hGPT->pGptHdr->NumberOfPartitionEntries); iPartition++, iIndex = (int)(iPartition % iEntryPerSect), dwGptSect += iIndex ? 0 : 1 ) { if (iIndex == 0) // Read-in a new sector when passing a boundary. { QWORD qw; iErr = GptBlockRead(hGPT, qw = dwGptSect, 1, pGptEntryBuf); if (iErr) GptAllocSectorsFail(-3); } // Skip unused entries, but keep mark of the first one. if (IsNullUuid((uuid_t*)&(pPartEntry[iIndex].PartitionTypeGUID))) { // If we already have found an unused spot, just loop. if (iNewPartition != -1) continue; // OK. Let's use this one for the allocation below. iNewPartition = iPartition; dwNewSector = dwGptSect; iNewIndex = iIndex; continue; } // This entry is in use. Record what sector area it uses. // printfx("Removing block %s", pPartEntry[iIndex].StartingLBA); // printfx("-%s\n", pPartEntry[iIndex].EndingLBA); for (j=0; j<nBlocks; j++) { if (pPartEntry[iIndex].StartingLBA <= pqwLast[j]) // Then insert a hole in this segment { int k; if ( (pqwFirst[j] < pPartEntry[iIndex].StartingLBA) && (pPartEntry[iIndex].EndingLBA < pqwLast[j]) ) { // If both ends of the partition strictly inside the free area, split it. // printf("Splitting a free block.\n"); for (k=nBlocks; k>j; k--) // Move the rest of the list right by 1 slot { pqwFirst[k] = pqwFirst[k-1]; pqwLast[k] = pqwLast[k-1]; } nBlocks += 1; pqwLast[j] = pPartEntry[iIndex].StartingLBA - qwOne; pqwFirst[j+1] = pPartEntry[iIndex].EndingLBA + qwOne; } else if ( (pqwFirst[j] == pPartEntry[iIndex].StartingLBA) && (pPartEntry[iIndex].EndingLBA == pqwLast[j]) ) { // If both ends of the partition exactly match the free area, remove it. // printf("Removing one free block.\n"); nBlocks -= 1; for (k=j; k<nBlocks; k++) // Move the rest of the list left by 1 slot { pqwFirst[k] = pqwFirst[k+1]; pqwLast[k] = pqwLast[k+1]; } } else if (pqwFirst[j] < pPartEntry[iIndex].StartingLBA) { // If the ends match, mark the new end // printf("Shrinking a free block end.\n"); pqwLast[j] = pPartEntry[iIndex].StartingLBA - qwOne; } else { // The beginnings match. Mark the new beginning // printf("Shrinking a free block start.\n"); pqwFirst[j] = pPartEntry[iIndex].EndingLBA + qwOne; } /* printf("Free blocks: Sectors"); for (k=0; k<nBlocks; k++) { printfx(" %s", pqwFirst[k]); printfx("-%s;", pqwLast[k]); } printf("\n"); */ break; // Operation done } } } if (iNewPartition == -1) { GptAllocSectorsFail(-1); } // Allocate a block of sectors for our partition data. if (qwForceSect != qwZero) { qwFirst = qwForceSect; qwLast = qwFirst + qwNSect - qwOne; // Scan the free block list to make sure the whole requested range is free for (j=0; j<nBlocks; j++) { if ((pqwFirst[j] <= qwFirst) && (pqwLast[j] >= qwLast)) break; } if (j >= nBlocks) GptAllocSectorsFail(-5); } else // Scan the free block list to find the smallest area large enough for our data. { QWORD qwMaxWidth = _QWORD(0xFFFFFFFF, 0xFFFFFFFF); #ifdef _DEBUG if (iVerbose) printf("Free blocks: Sectors"); #endif for (j=0; j<nBlocks; j++) { #ifdef _DEBUG if (iVerbose) { printfx(" %s", pqwFirst[j]); printfx("-%s;", pqwLast[j]); } #endif QWORD qwWidth = qwOne + pqwLast[j] - pqwFirst[j]; if ( (qwWidth >= qwNSect) && (qwWidth < qwMaxWidth) ) { if ( (qwFirst == qwZero) || (pqwFirst[j] != hGPT->pGptHdr->LastUsableLBA) ) { // Allocate that block, except if it's the last one. qwMaxWidth = qwWidth; qwFirst = pqwFirst[j]; } } } #ifdef _DEBUG if (iVerbose) printf("\n"); #endif if (!qwFirst) GptAllocSectorsFail(-2); } qwLast = qwFirst + qwNSect - qwOne; #ifdef _DEBUG if (iVerbose) { printfx("Allocated sectors 0x%s", qwFirst); printfx(" to 0x%s.\n", qwLast); } #endif // Fill in the new partition characteristics memset(pNewEntry, 0, sizeof(EFI_PARTITION_ENTRY)); pNewEntry->PartitionTypeGUID = guidHardDiskImage; // Anything but 0 will do at this stage. uuid_create((uuid_t *)&(pNewEntry->UniquePartitionGUID)); // Generate a new GUID pNewEntry->StartingLBA = qwFirst; pNewEntry->EndingLBA = qwLast; alloc_return: free(pqwFirst); free(pqwLast); free(pGptEntryBuf); return iNewPartition; }