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