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