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