1/* 2** mac_label.c: generate Mactintosh partition maps and label 3** 4** Taken from "mkisofs 1.05 PLUS" by Andy Polyakov <appro@fy.chalmers.se> 5** (see http://fy.chalmers.se/~appro/mkisofs_plus.html for details) 6** 7** The format of the HFS driver file: 8** 9** HFS CD Label Block 512 bytes 10** Driver Partition Map (for 2048 byte blocks) 512 bytes 11** Driver Partition Map (for 512 byte blocks) 512 bytes 12** Empty 512 bytes 13** Driver Partition N x 2048 bytes 14** HFS Partition Boot Block 1024 bytes 15** 16** File of the above format can be extracted from a CD using 17** apple_driver.c 18** 19** James Pearson 16/5/98 20*/ 21 22#include <config.h> 23#include <mkisofs.h> 24#include "mac_label_proto.h" 25#include <mac_label.h> 26#include "data.h" 27 28int 29gen_mac_label(defer *mac_boot) 30{ 31 FILE *fp; 32 MacLabel *mac_label; 33 MacPart *mac_part; 34 char *buffer = hce->hfs_map; 35 int block_size; 36 int have_hfs_boot = 0; 37 char tmp[SECTOR_SIZE]; 38 struct stat stat_buf; 39 mac_partition_table mpm[2]; 40 int mpc = 0; 41 int i; 42 43 /* If we have a boot file, then open and check it */ 44 if (mac_boot->name) { 45 if (stat(mac_boot->name, &stat_buf) < 0) { 46 snprintf(hce->error, ERROR_SIZE, 47 "unable to stat HFS boot file %s", mac_boot->name); 48 return (-1); 49 } 50 51 52 if ((fp = fopen(mac_boot->name, "rb")) == NULL) { 53 snprintf(hce->error, ERROR_SIZE, 54 "unable to open HFS boot file %s", mac_boot->name); 55 return (-1); 56 } 57 58 if (fread(tmp, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) { 59 snprintf(hce->error, ERROR_SIZE, 60 "unable to read HFS boot file %s", mac_boot->name); 61 return (-1); 62 } 63 64 65 /* check we have a bootable partition */ 66 mac_part = (MacPart*)(tmp+HFS_BLOCKSZ); 67 68 if (!(IS_MAC_PART(mac_part) && !strncmp(mac_part->pmPartType, pmPartType_2, 12))) { 69 snprintf(hce->error, ERROR_SIZE, "%s is not a HFS boot file", 70 mac_boot->name); 71 return (-1); 72 } 73 74 /* check we have a boot block as well - last 2 blocks of file */ 75 76 if (fseek(fp, -2 * HFS_BLOCKSZ, 2) != 0) { 77 snprintf(hce->error, ERROR_SIZE, 78 "unable to seek HFS boot file %s", mac_boot->name); 79 return (-1); 80 } 81 82 /* overwrite (empty) boot block for our HFS volume */ 83 if (fread(hce->hfs_hdr, 2, HFS_BLOCKSZ, fp) != HFS_BLOCKSZ) { 84 snprintf(hce->error, ERROR_SIZE, 85 "unable to read HFS boot block %s", mac_boot->name); 86 return (-1); 87 } 88 89 fclose (fp); 90 91 /* check boot block is valid */ 92 if (d_getw((unsigned char *)hce->hfs_hdr) != HFS_BB_SIGWORD) { 93 snprintf(hce->error, ERROR_SIZE, 94 "%s does not contain a valid boot block", mac_boot->name); 95 return (-1); 96 } 97 98 /* collect info about boot file for later user - skip over the boot 99 file header */ 100 mac_boot->size = stat_buf.st_size - SECTOR_SIZE - 2*HFS_BLOCKSZ; 101 mac_boot->off = SECTOR_SIZE; 102 mac_boot->pad = 0; 103 104 /* get size in SECTOR_SIZE blocks - shouldn't need to round up */ 105 mpm[mpc].size = ROUND_UP(mac_boot->size)/SECTOR_SIZE; 106 107 mpm[mpc].ntype = PM2; 108 mpm[mpc].type = mac_part->pmPartType; 109 mpm[mpc].start = mac_boot->extent = last_extent; 110 mpm[mpc].name = 0; 111 112 /* flag that we have a boot file */ 113 have_hfs_boot++; 114 115 /* add boot file size to the total size */ 116 last_extent += mpm[mpc].size; 117 hfs_extra += mpm[mpc].size; 118 119 mpc++; 120 } 121 122 /* set info about our hybrid volume */ 123 mpm[mpc].ntype = PM4; 124 mpm[mpc].type = pmPartType_4; 125 mpm[mpc].start = hce->hfs_map_size / BLK_CONV; 126 mpm[mpc].size = last_extent - mpm[mpc].start; 127 mpm[mpc].name = volume_id; 128 129 mpc++; 130 131 if (verbose > 1) 132 fprintf(stderr, "Creating HFS Label %s %s\n", mac_boot->name ? 133 "with boot file" : "", mac_boot->name ? mac_boot->name : "" ); 134 135 /* for a bootable CD, block size is SECTOR_SIZE */ 136 block_size = have_hfs_boot ? SECTOR_SIZE : HFS_BLOCKSZ; 137 138 /* create the CD label */ 139 mac_label = (MacLabel *)buffer; 140 mac_label->sbSig [0] = 'E'; 141 mac_label->sbSig [1] = 'R'; 142 set_722 (mac_label->sbBlkSize,block_size); 143 set_732 (mac_label->sbBlkCount,last_extent*(SECTOR_SIZE/block_size)); 144 set_722 (mac_label->sbDevType,1); 145 set_722 (mac_label->sbDevId,1); 146 147 /* create the partition map entry */ 148 mac_part = (MacPart*)(buffer+block_size); 149 mac_part->pmSig [0] = 'P'; 150 mac_part->pmSig [1] = 'M'; 151 set_732 (mac_part->pmMapBlkCnt,mpc+1); 152 set_732 (mac_part->pmPyPartStart,1); 153 set_732 (mac_part->pmPartBlkCnt,mpc+1); 154 strncpy (mac_part->pmPartName,"Apple",sizeof(mac_part->pmPartName)); 155 strncpy (mac_part->pmPartType,"Apple_partition_map",sizeof(mac_part->pmPartType)); 156 set_732 (mac_part->pmLgDataStart,0); 157 set_732 (mac_part->pmDataCnt,mpc+1); 158 set_732 (mac_part->pmPartStatus,PM_STAT_DEFAULT); 159 160 /* create partition map entries for our partitions */ 161 for (i=0;i<mpc;i++) { 162 mac_part = (MacPart*)(buffer + (i+2)*block_size); 163 if (mpm[i].ntype == PM2) { 164 /* get driver label and patch it */ 165 memcpy (mac_label, tmp, HFS_BLOCKSZ); 166 set_732 (mac_label->sbBlkCount,last_extent*(SECTOR_SIZE/block_size)); 167 set_732 (mac_label->ddBlock,(mpm[i].start)*(SECTOR_SIZE/block_size)); 168 memcpy (mac_part, tmp+HFS_BLOCKSZ, HFS_BLOCKSZ); 169 set_732 (mac_part->pmMapBlkCnt,mpc+1); 170 set_732 (mac_part->pmPyPartStart,(mpm[i].start)*(SECTOR_SIZE/block_size)); 171 } 172 else { 173 mac_part->pmSig [0] = 'P'; 174 mac_part->pmSig [1] = 'M'; 175 set_732 (mac_part->pmMapBlkCnt,mpc+1); 176 set_732 (mac_part->pmPyPartStart,mpm[i].start*(SECTOR_SIZE/HFS_BLOCKSZ)); 177 set_732 (mac_part->pmPartBlkCnt,mpm[i].size*(SECTOR_SIZE/HFS_BLOCKSZ)); 178 strncpy (mac_part->pmPartName,mpm[i].name,sizeof(mac_part->pmPartName)); 179 strncpy (mac_part->pmPartType,mpm[i].type,sizeof(mac_part->pmPartType)); 180 set_732 (mac_part->pmLgDataStart,0); 181 set_732 (mac_part->pmDataCnt,mpm[i].size*(SECTOR_SIZE/HFS_BLOCKSZ)); 182 set_732 (mac_part->pmPartStatus,PM_STAT_DEFAULT); 183 } 184 } 185 186 if (have_hfs_boot) { /* generate 512 partition table as well */ 187 mac_part = (MacPart*)(buffer+HFS_BLOCKSZ); 188 if (mpc<3) { /* don't have to interleave with 2048 table */ 189 mac_part->pmSig [0] = 'P'; 190 mac_part->pmSig [1] = 'M'; 191 set_732 (mac_part->pmMapBlkCnt,mpc+1); 192 set_732 (mac_part->pmPyPartStart,1); 193 set_732 (mac_part->pmPartBlkCnt,mpc+1); 194 strncpy (mac_part->pmPartName,"Apple",sizeof(mac_part->pmPartName)); 195 strncpy (mac_part->pmPartType,"Apple_partition_map",sizeof(mac_part->pmPartType)); 196 set_732 (mac_part->pmLgDataStart,0); 197 set_732 (mac_part->pmDataCnt,mpc+1); 198 set_732 (mac_part->pmPartStatus,PM_STAT_DEFAULT); 199 mac_part++; /* +HFS_BLOCKSZ */ 200 } 201 for (i=0;i<mpc;i++,mac_part++) { 202 if (mac_part == (MacPart*)(buffer+SECTOR_SIZE)) mac_part++; /* jump over 2048 partition entry */ 203 if (mpm[i].ntype == PM2) { 204 memcpy (mac_part, tmp+HFS_BLOCKSZ*2, HFS_BLOCKSZ); 205 if (!IS_MAC_PART(mac_part)) { mac_part--; continue; } 206 set_732 (mac_part->pmMapBlkCnt,mpc+1); 207 set_732 (mac_part->pmPyPartStart,(mpm[i].start)*(SECTOR_SIZE/HFS_BLOCKSZ)); 208 } 209 else { 210 mac_part->pmSig [0] = 'P'; 211 mac_part->pmSig [1] = 'M'; 212 set_732 (mac_part->pmMapBlkCnt,mpc+1); 213 set_732 (mac_part->pmPyPartStart,mpm[i].start*(SECTOR_SIZE/HFS_BLOCKSZ)); 214 set_732 (mac_part->pmPartBlkCnt,mpm[i].size*(SECTOR_SIZE/HFS_BLOCKSZ)); 215 strncpy (mac_part->pmPartName,mpm[i].name,sizeof(mac_part->pmPartName)); 216 strncpy (mac_part->pmPartType,mpm[i].type,sizeof(mac_part->pmPartType)); 217 set_732 (mac_part->pmLgDataStart,0); 218 set_732 (mac_part->pmDataCnt,mpm[i].size*(SECTOR_SIZE/HFS_BLOCKSZ)); 219 set_732 (mac_part->pmPartStatus,PM_STAT_DEFAULT); 220 } 221 } 222 } 223 224 return (0); 225} 226 227/* 228** autostart: make the HFS CD use the QuickTime 2.0 Autostart feature. 229** 230** based on information from Eric Eisenhart <eric@sonic.net> and 231** http://developer.apple.com/qa/qtpc/qtpc12.html and 232** http://developer.apple.com/dev/techsupport/develop/issue26/macqa.html 233** 234** The name of the AutoStart file is stored in the area allocated for 235** the Clipboard name. This area begins 106 bytes into the sector of 236** block 0, with the first four bytes at that offset containing the 237** hex value 0x006A7068. This value indicates that an AutoStart 238** filename follows. After this 4-byte tag, 12 bytes remain, starting 239** at offset 110. In these 12 bytes, the name of the AutoStart file is 240** stored as a Pascal string, giving you up to 11 characters to identify 241** the file. The file must reside in the root directory of the HFS 242** volume or partition. 243*/ 244 245int 246autostart() 247{ 248 int len, i; 249 250 if((len = strlen(autoname)) > 11) 251 return (-1); 252 253 hce->hfs_hdr[106] = 0x00; 254 hce->hfs_hdr[107] = 0x6A; 255 hce->hfs_hdr[108] = 0x70; 256 hce->hfs_hdr[109] = 0x68; 257 hce->hfs_hdr[110] = len; 258 259 for(i=0;i<len;i++) 260 hce->hfs_hdr[111+i] = autoname[i]; 261 262 return (0); 263} 264