1 /* @(#)mac_label.c	1.22 20/05/11 joerg, Copyright 1997-2000 James Pearson, Copyright 2004-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)mac_label.c	1.22 20/05/11 joerg, Copyright 1997-2000 James Pearson, Copyright 2004-2020 J. Schilling";
6 #endif
7 /*
8  *      Copyright (c) 1997, 1998, 1999, 2000 James Pearson
9  *	Copyright (c) 2004-2020 J. Schilling
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2, or (at your option)
14  * any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; see the file COPYING.  If not, write to
23  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 
26 /*
27  *	mac_label.c: generate Mactintosh partition maps and label
28  *
29  *	Taken from "mkisofs 1.05 PLUS" by Andy Polyakov <appro@fy.chalmers.se>
30  *	(see http://fy.chalmers.se/~appro/mkisofs_plus.html for details)
31  *
32  *	The format of the HFS driver file:
33  *
34  *	HFS CD Label Block				512 bytes
35  *	Driver Partition Map (for 2048 byte blocks)	512 bytes
36  *	Driver Partition Map (for 512 byte blocks)	512 bytes
37  *	Empty						512 bytes
38  *	Driver Partition				N x 2048 bytes
39  *	HFS Partition Boot Block			1024 bytes
40  *
41  *	File of the above format can be extracted from a CD using
42  *	apple_driver.c
43  *
44  *	James Pearson 16/5/98
45  */
46 
47 /* PREP_BOOT Troy Benjegerdes 2/4/99 */
48 
49 #include "mkisofs.h"
50 #include "mac_label.h"
51 #include "apple.h"
52 #include <schily/schily.h>
53 
54 #ifdef PREP_BOOT
55 void	gen_prepboot_label	__PR((unsigned char *ml));
56 
57 #endif	/* PREP_BOOT */
58 #ifdef	APPLE_HYB
59 int	gen_mac_label		__PR((defer * mac_boot));
60 int	autostart		__PR((void));
61 #endif	/* APPLE_HYB */
62 
63 #ifdef PREP_BOOT
64 void
gen_prepboot_label(ml)65 gen_prepboot_label(ml)
66 	unsigned char	*ml;
67 {
68 	struct directory_entry *de;
69 	int		i = 0;
70 	unsigned	block;
71 	unsigned	size;
72 	MacLabel	*mac_label = (MacLabel *) ml;
73 
74 	if (verbose > 1) {
75 		fprintf(stderr, _("Creating %d PReP boot partition(s)\n"),
76 						use_prep_boot + use_chrp_boot);
77 	}
78 	mac_label->fdiskMagic[0] = fdiskMagic0;
79 	mac_label->fdiskMagic[1] = fdiskMagic1;
80 
81 	if (use_chrp_boot) {
82 		fprintf(stderr, _("CHRP boot partition 1\n"));
83 
84 		mac_label->image[i].boot = 0x80;
85 
86 		mac_label->image[i].CHSstart[0] = 0xff;
87 		mac_label->image[i].CHSstart[1] = 0xff;
88 		mac_label->image[i].CHSstart[2] = 0xff;
89 
90 		mac_label->image[i].type = chrpPartType;	/* 0x96 */
91 
92 		mac_label->image[i].CHSend[0] = 0xff;
93 		mac_label->image[i].CHSend[1] = 0xff;
94 		mac_label->image[i].CHSend[2] = 0xff;
95 
96 		mac_label->image[i].startSect[0] = 0;
97 		mac_label->image[i].startSect[1] = 0;
98 		mac_label->image[i].startSect[2] = 0;
99 		mac_label->image[i].startSect[3] = 0;
100 
101 		size = (unsigned)(last_extent - session_start) * (2048 / 512);
102 		mac_label->image[i].size[0] = size & 0xff;
103 		mac_label->image[i].size[1] = (size >> 8) & 0xff;
104 		mac_label->image[i].size[2] = (size >> 16) & 0xff;
105 		mac_label->image[i].size[3] = (size >> 24) & 0xff;
106 
107 		i++;
108 	}
109 
110 	for (; i < use_prep_boot + use_chrp_boot; i++) {
111 		de = search_tree_file(root, prep_boot_image[i - use_chrp_boot]);
112 		if (!de) {
113 			ex_boot_enoent(_("image"),
114 				prep_boot_image[i - use_chrp_boot]);
115 			/* NOTREACHED */
116 		}
117 		/* get size and block in 512-byte blocks */
118 		block = get_733(de->isorec.extent) * (2048 / 512);
119 		size = get_733(de->isorec.size) / 512 + 1;
120 		fprintf(stderr, _("PReP boot partition %d is \"%s\"\n"),
121 			i + 1, prep_boot_image[i - use_chrp_boot]);
122 
123 		mac_label->image[i].boot = 0x80;
124 
125 		mac_label->image[i].CHSstart[0] = 0xff;
126 		mac_label->image[i].CHSstart[1] = 0xff;
127 		mac_label->image[i].CHSstart[2] = 0xff;
128 
129 		mac_label->image[i].type = prepPartType;	/* 0x41 */
130 
131 		mac_label->image[i].CHSend[0] = 0xff;
132 		mac_label->image[i].CHSend[1] = 0xff;
133 		mac_label->image[i].CHSend[2] = 0xff;
134 
135 		/* deal with  endianess */
136 		mac_label->image[i].startSect[0] = block & 0xff;
137 		mac_label->image[i].startSect[1] = (block >> 8) & 0xff;
138 		mac_label->image[i].startSect[2] = (block >> 16) & 0xff;
139 		mac_label->image[i].startSect[3] = (block >> 24) & 0xff;
140 
141 		mac_label->image[i].size[0] = size & 0xff;
142 		mac_label->image[i].size[1] = (size >> 8) & 0xff;
143 		mac_label->image[i].size[2] = (size >> 16) & 0xff;
144 		mac_label->image[i].size[3] = (size >> 24) & 0xff;
145 	}
146 	for (; i < 4; i++) {
147 		mac_label->image[i].CHSstart[0] = 0xff;
148 		mac_label->image[i].CHSstart[1] = 0xff;
149 		mac_label->image[i].CHSstart[2] = 0xff;
150 
151 		mac_label->image[i].CHSend[0] = 0xff;
152 		mac_label->image[i].CHSend[1] = 0xff;
153 		mac_label->image[i].CHSend[2] = 0xff;
154 	}
155 }
156 
157 #endif	/* PREP_BOOT */
158 
159 #ifdef	APPLE_HYB
160 int
gen_mac_label(mac_boot)161 gen_mac_label(mac_boot)
162 	defer		*mac_boot;
163 {
164 	FILE		*fp;
165 	MacLabel	*mac_label;
166 	MacPart		*mac_part;
167 	char		*buffer = (char *)hce->hfs_map;
168 	int		block_size;
169 	int		have_hfs_boot = 0;
170 	char		tmp[SECTOR_SIZE];
171 	struct stat	stat_buf;
172 	mac_partition_table mpm[2];
173 	int		mpc = 0;
174 	int		i;
175 
176 	/* If we have a boot file, then open and check it */
177 	if (mac_boot->name) {
178 		if (stat(mac_boot->name, &stat_buf) < 0) {
179 			sprintf(hce->error, _("unable to stat HFS boot file %s"),
180 								mac_boot->name);
181 			return (-1);
182 		}
183 		if ((fp = fopen(mac_boot->name, "rb")) == NULL) {
184 			sprintf(hce->error, _("unable to open HFS boot file %s"),
185 								mac_boot->name);
186 			return (-1);
187 		}
188 		if (fread(tmp, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) {
189 			sprintf(hce->error, _("unable to read HFS boot file %s"),
190 								mac_boot->name);
191 			fclose(fp);
192 			return (-1);
193 		}
194 		/* check we have a bootable partition */
195 		mac_part = (MacPart *)(tmp + HFS_BLOCKSZ);
196 
197 		if (!(IS_MAC_PART(mac_part) &&
198 		    strncmp((char *)mac_part->pmPartType, pmPartType_2, 12) == 0)) {
199 			sprintf(hce->error, _("%s is not a HFS boot file"),
200 								mac_boot->name);
201 			fclose(fp);
202 			return (-1);
203 		}
204 		/* check we have a boot block as well - last 2 blocks of file */
205 
206 		if (fseek(fp, (off_t)-2 * HFS_BLOCKSZ, SEEK_END) != 0) {
207 			sprintf(hce->error, _("unable to seek HFS boot file %s"),
208 								mac_boot->name);
209 			fclose(fp);
210 			return (-1);
211 		}
212 		/* overwrite (empty) boot block for our HFS volume */
213 		if (fread(hce->hfs_hdr, 2, HFS_BLOCKSZ, fp) != HFS_BLOCKSZ) {
214 			sprintf(hce->error, _("unable to read HFS boot block %s"),
215 								mac_boot->name);
216 			fclose(fp);
217 			return (-1);
218 		}
219 		fclose(fp);
220 
221 		/* check boot block is valid */
222 		if (d_getw((unsigned char *)hce->hfs_hdr) != HFS_BB_SIGWORD) {
223 			sprintf(hce->error,
224 				_("%s does not contain a valid boot block"),
225 								mac_boot->name);
226 			return (-1);
227 		}
228 		/*
229 		 * collect info about boot file for later user
230 		 * - skip over the bootfile header
231 		 */
232 		mac_boot->size = stat_buf.st_size - SECTOR_SIZE - 2*HFS_BLOCKSZ;
233 		mac_boot->off = SECTOR_SIZE;
234 		mac_boot->pad = 0;
235 
236 		/*
237 		 * get size in SECTOR_SIZE blocks
238 		 * - shouldn't need to round up
239 		 */
240 		mpm[mpc].size = ISO_BLOCKS(mac_boot->size);
241 
242 		mpm[mpc].ntype = PM2;
243 		mpm[mpc].type = (char *)mac_part->pmPartType;
244 		mpm[mpc].start = mac_boot->extent = last_extent;
245 		mpm[mpc].name = 0;
246 
247 		/* flag that we have a boot file */
248 		have_hfs_boot++;
249 
250 		/* add boot file size to the total size */
251 		last_extent += mpm[mpc].size;
252 		hfs_extra += mpm[mpc].size;
253 
254 		mpc++;
255 	}
256 	/* set info about our hybrid volume */
257 	mpm[mpc].ntype = PM4;
258 	mpm[mpc].type = pmPartType_4;
259 	mpm[mpc].start = hce->hfs_map_size / HFS_BLK_CONV;
260 	mpm[mpc].size = last_extent - mpm[mpc].start -
261 			ISO_BLOCKS(mac_boot->size);
262 	mpm[mpc].name = volume_id;
263 
264 	mpc++;
265 
266 	if (verbose > 1)
267 		fprintf(stderr, _("Creating HFS Label %s %s\n"), mac_boot->name ?
268 			_("with boot file") : "",
269 			mac_boot->name ? mac_boot->name : "");
270 
271 	/* for a bootable CD, block size is SECTOR_SIZE */
272 	block_size = have_hfs_boot ? SECTOR_SIZE : HFS_BLOCKSZ;
273 
274 	/* create the CD label */
275 	mac_label = (MacLabel *)buffer;
276 	mac_label->sbSig[0] = 'E';
277 	mac_label->sbSig[1] = 'R';
278 	set_722((char *)mac_label->sbBlkSize, block_size);
279 	set_732((char *)mac_label->sbBlkCount,
280 				last_extent * (SECTOR_SIZE / block_size));
281 	set_722((char *)mac_label->sbDevType, 1);
282 	set_722((char *)mac_label->sbDevId, 1);
283 
284 	/* create the partition map entry */
285 	mac_part = (MacPart *)(buffer + block_size);
286 	mac_part->pmSig[0] = 'P';
287 	mac_part->pmSig[1] = 'M';
288 	set_732((char *)mac_part->pmMapBlkCnt, mpc + 1);
289 	set_732((char *)mac_part->pmPyPartStart, 1);
290 	set_732((char *)mac_part->pmPartBlkCnt, mpc + 1);
291 	strncpy((char *)mac_part->pmPartName, "Apple",
292 						sizeof (mac_part->pmPartName));
293 	strncpy((char *)mac_part->pmPartType, "Apple_partition_map",
294 						sizeof (mac_part->pmPartType));
295 	set_732((char *)mac_part->pmLgDataStart, 0);
296 	set_732((char *)mac_part->pmDataCnt, mpc + 1);
297 	set_732((char *)mac_part->pmPartStatus, PM_STAT_DEFAULT);
298 
299 	/* create partition map entries for our partitions */
300 	for (i = 0; i < mpc; i++) {
301 		mac_part = (MacPart *)(buffer + (i + 2) * block_size);
302 		if (mpm[i].ntype == PM2) {
303 			/* get driver label and patch it */
304 			memcpy((char *)mac_label, tmp, HFS_BLOCKSZ);
305 			set_732((char *)mac_label->sbBlkCount,
306 				last_extent * (SECTOR_SIZE / block_size));
307 			set_732((char *)mac_label->ddBlock,
308 				(mpm[i].start) * (SECTOR_SIZE / block_size));
309 			memcpy((char *)mac_part, tmp + HFS_BLOCKSZ,
310 								HFS_BLOCKSZ);
311 			set_732((char *)mac_part->pmMapBlkCnt, mpc + 1);
312 			set_732((char *)mac_part->pmPyPartStart,
313 				(mpm[i].start) * (SECTOR_SIZE / block_size));
314 		} else {
315 			mac_part->pmSig[0] = 'P';
316 			mac_part->pmSig[1] = 'M';
317 			set_732((char *)mac_part->pmMapBlkCnt, mpc + 1);
318 			set_732((char *)mac_part->pmPyPartStart,
319 				mpm[i].start * (SECTOR_SIZE / HFS_BLOCKSZ));
320 			set_732((char *)mac_part->pmPartBlkCnt,
321 				mpm[i].size * (SECTOR_SIZE / HFS_BLOCKSZ));
322 			strncpy((char *)mac_part->pmPartName, mpm[i].name,
323 				sizeof (mac_part->pmPartName));
324 			strncpy((char *)mac_part->pmPartType, mpm[i].type,
325 				sizeof (mac_part->pmPartType));
326 			set_732((char *)mac_part->pmLgDataStart, 0);
327 			set_732((char *)mac_part->pmDataCnt,
328 				mpm[i].size * (SECTOR_SIZE / HFS_BLOCKSZ));
329 			set_732((char *)mac_part->pmPartStatus,
330 				PM_STAT_DEFAULT);
331 		}
332 	}
333 
334 	if (have_hfs_boot) {	/* generate 512 partition table as well */
335 		mac_part = (MacPart *) (buffer + HFS_BLOCKSZ);
336 		if (mpc < 3) {	/* don't have to interleave with 2048 table */
337 			mac_part->pmSig[0] = 'P';
338 			mac_part->pmSig[1] = 'M';
339 			set_732((char *)mac_part->pmMapBlkCnt, mpc + 1);
340 			set_732((char *)mac_part->pmPyPartStart, 1);
341 			set_732((char *)mac_part->pmPartBlkCnt, mpc + 1);
342 			strncpy((char *)mac_part->pmPartName, "Apple",
343 					sizeof (mac_part->pmPartName));
344 			strncpy((char *)mac_part->pmPartType,
345 					"Apple_partition_map",
346 					sizeof (mac_part->pmPartType));
347 			set_732((char *)mac_part->pmLgDataStart, 0);
348 			set_732((char *)mac_part->pmDataCnt, mpc + 1);
349 			set_732((char *)mac_part->pmPartStatus,
350 							PM_STAT_DEFAULT);
351 			mac_part++;	/* +HFS_BLOCKSZ */
352 		}
353 		for (i = 0; i < mpc; i++, mac_part++) {
354 			if (mac_part == (MacPart *)(buffer + SECTOR_SIZE))
355 				mac_part++;	/* jump over 2048 partition */
356 						/* entry */
357 			if (mpm[i].ntype == PM2) {
358 				memcpy((char *)mac_part, tmp + HFS_BLOCKSZ * 2,
359 							HFS_BLOCKSZ);
360 				if (!IS_MAC_PART(mac_part)) {
361 					mac_part--;
362 					continue;
363 				}
364 				set_732((char *)mac_part->pmMapBlkCnt, mpc+1);
365 				set_732((char *)mac_part->pmPyPartStart,
366 				    mpm[i].start * (SECTOR_SIZE / HFS_BLOCKSZ));
367 			} else {
368 				mac_part->pmSig[0] = 'P';
369 				mac_part->pmSig[1] = 'M';
370 				set_732((char *)mac_part->pmMapBlkCnt, mpc+1);
371 				set_732((char *)mac_part->pmPyPartStart,
372 				    mpm[i].start * (SECTOR_SIZE / HFS_BLOCKSZ));
373 				set_732((char *)mac_part->pmPartBlkCnt,
374 				    mpm[i].size * (SECTOR_SIZE / HFS_BLOCKSZ));
375 				strncpy((char *)mac_part->pmPartName,
376 				    mpm[i].name, sizeof (mac_part->pmPartName));
377 				strncpy((char *)mac_part->pmPartType,
378 				    mpm[i].type, sizeof (mac_part->pmPartType));
379 				set_732((char *)mac_part->pmLgDataStart, 0);
380 				set_732((char *)mac_part->pmDataCnt,
381 				    mpm[i].size * (SECTOR_SIZE / HFS_BLOCKSZ));
382 				set_732((char *)mac_part->pmPartStatus,
383 							PM_STAT_DEFAULT);
384 			}
385 		}
386 	}
387 	return (0);
388 }
389 
390 /*
391  *	autostart: make the HFS CD use the QuickTime 2.0 Autostart feature.
392  *
393  *	based on information from Eric Eisenhart <eric@sonic.net> and
394  *	http://developer.apple.com/qa/qtpc/qtpc12.html and
395  *	http://developer.apple.com/dev/techsupport/develop/issue26/macqa.html
396  *
397  *	The name of the AutoStart file is stored in the area allocated for
398  *	the Clipboard name. This area begins 106 bytes into the sector of
399  *	block 0, with the first four bytes at that offset containing the
400  *	hex value 0x006A7068. This value indicates that an AutoStart
401  *	filename follows. After this 4-byte tag, 12 bytes remain, starting
402  *	at offset 110. In these 12 bytes, the name of the AutoStart file is
403  *	stored as a Pascal string, giving you up to 11 characters to identify
404  *	the file. The file must reside in the root directory of the HFS
405  *	volume or partition.
406  */
407 
408 int
autostart()409 autostart()
410 {
411 	int	len;
412 	int	i;
413 
414 	if ((len = strlen(autoname)) > 11)
415 		return (-1);
416 
417 	hce->hfs_hdr[106] = 0x00;
418 	hce->hfs_hdr[107] = 0x6A;
419 	hce->hfs_hdr[108] = 0x70;
420 	hce->hfs_hdr[109] = 0x68;
421 	hce->hfs_hdr[110] = len;
422 
423 	for (i = 0; i < len; i++)
424 		hce->hfs_hdr[111 + i] = autoname[i];
425 
426 	return (0);
427 }
428 #endif	/* APPLE_HYB */
429