/*! @file cdboothack.c @copyright David Elliott @created 2009-03-21 @abstract Writes some isolinux-style boot info table fields @discussion Now that the CD boot sector is capable of loading more than 31 CD sectors we need to know how large the boot file is to determine how many sectors must be loaded. Generally you would use mkisofs or genisoimage with the -boot-info-table option to have it write all the fields. But it's kinda nice to be able to use hdiutil makehybrid which has no such facility. Realizing that we only need to know the sector count and realizing that this project's makefiles are responsible for combining the CD bootsector (cdboot.s) and the booter it seemed reasonable to make a utility which would record the file length as mkisofs/genisoimage would do. */ #include #include // boot info table starts 8 bytes into loader int const boot_info_offset = 8; struct boot_info_table { uint32_t bi_pvd; uint32_t bi_file; uint32_t bi_length; uint32_t bi_csum; uint32_t bi_reserved[10]; }; int const failme = 1 / (sizeof(struct boot_info_table) == 56); struct boot_file_start { char reserved[8]; struct boot_info_table bi; }; int const failme2 = 1 / (sizeof(struct boot_file_start) == 64); int main(int argc, char **argv) { if(argc != 2) { fprintf(stderr,"Usage: %s cdboot\n", argv[0]); return 1; } char const *cdbootfn = argv[1]; FILE *cdbootf = fopen(cdbootfn, "r+b"); if(cdbootf == NULL) { fprintf(stderr, "Could not open %s for writing.\n", cdbootfn); return 0; } // Place to stash the boot info table along with the preceding 8 bytes struct boot_file_start startOfFile; // Working area for the DWORD reads. char buf[sizeof(uint32_t)]; size_t bytesread; bytesread = fread(&startOfFile, 1, sizeof(startOfFile), cdbootf); if(bytesread < sizeof(startOfFile)) { fprintf(stderr, "File must be at least 64 bytes\n"); return 1; } // Yes, the checksum starts at byte 64 according to the genisoimage manpage. uint32_t csum = 0; size_t totalread = sizeof(startOfFile); size_t padbytes = 0; do { bytesread = fread(buf, 1, sizeof(uint32_t), cdbootf); if(bytesread > 0) { if(padbytes > 0) { fprintf(stderr, "Did not expect to read more of the file after having padded it"); return 1; } for(;bytesread < 4; ++bytesread) { ++padbytes; buf[bytesread] = '\0'; } totalread += bytesread; csum += *(uint32_t *)buf; } } while(bytesread > 0); int i; for(i=0; i 0) { fprintf(stderr, "Wrote %lu bytes of padding", padbytes); } off_t fileSize = ftell(cdbootf); if(fileSize != totalread) { fprintf(stderr, "Reported size from ftell %lld isn't what we expected %lu\n", fileSize, totalread); return 1; } // Update the boot info table with the length and checksum startOfFile.bi.bi_pvd = 0; startOfFile.bi.bi_file = 0; startOfFile.bi.bi_length = totalread; startOfFile.bi.bi_csum = csum; // Write it out to the file. fseek(cdbootf, 0L, SEEK_SET); size_t byteswritten; byteswritten = fwrite(&startOfFile,1,sizeof(startOfFile),cdbootf); if(byteswritten < sizeof(startOfFile)) { fprintf(stderr, "Failed to write new header\n"); return 1; } fclose(cdbootf); fprintf(stderr, "CD booter is %lld bytes\n", fileSize); return 0; }