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
28 int
gen_mac_label(defer * mac_boot)29 gen_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
245 int
autostart()246 autostart()
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