xref: /openbsd-src/gnu/usr.sbin/mkhybrid/src/mac_label.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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