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