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