xref: /netbsd-src/external/gpl2/mkhybrid/dist/mac_label.c (revision 3acbd1aa78a9936f951b107569fea0ded0e9337b)
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 
28 int
gen_mac_label(defer * mac_boot)29 gen_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 
245 int
autostart()246 autostart()
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