1 /*
2 * Copyright (c) 2008 Vreixo Formoso
3 * Copyright (c) 2010 - 2019 Thomas Schmitt
4 *
5 * This file is part of the libisofs project; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * or later as published by the Free Software Foundation.
8 * See COPYING file for details.
9 */
10
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14
15 #include "libisofs.h"
16 #include "system_area.h"
17 #include "eltorito.h"
18 #include "filesrc.h"
19 #include "ecma119_tree.h"
20 #include "image.h"
21 #include "messages.h"
22 #include "ecma119.h"
23 #include "writer.h"
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31
32 /* for gettimeofday() */
33 #include <sys/time.h>
34
35 /* >>> Need ./configure test for uuid_generate() which checks for:
36 uuid_t, uuid_generate, the need for -luuid
37 */
38 /*
39 #define Libisofs_with_uuid_generatE 1
40 */
41 #ifdef Libisofs_with_uuid_generatE
42 #include <uuid/uuid.h>
43 #endif
44
45 /* O_BINARY is needed for Cygwin but undefined elsewhere */
46 #ifndef O_BINARY
47 #define O_BINARY 0
48 #endif
49
50
51 /*
52 * Create a MBR for an isohybrid enabled ISOLINUX boot image.
53 * See libisofs/make_isohybrid_mbr.c
54 * Deprecated.
55 */
56 int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
57
58 /*
59 * The New ISOLINUX MBR Producer.
60 * Be cautious with changing parameters. Only few combinations are tested.
61 *
62 */
63 int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
64 int part_offset, int part_number, int fs_type,
65 uint8_t *buf, int flag);
66
67 /* Find out whether GPT and APM are desired by isohybrid
68 flag bit0 = register APM and GPT requests in Ecma119Image
69 */
70 int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
71 int *apm_count, int flag);
72
73
74 static int precompute_gpt(Ecma119Image *t);
75
76
77 /*
78 * @param flag bit0= img_blocks is start address rather than end address:
79 do not subtract 1
80 bit1= img_blocks is counted in 512-byte units rather than 2 KiB
81 */
82 static
iso_compute_cyl_head_sec(uint64_t img_blocks,int hpc,int sph,uint32_t * end_lba,uint32_t * end_sec,uint32_t * end_head,uint32_t * end_cyl,int flag)83 void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph,
84 uint32_t *end_lba, uint32_t *end_sec,
85 uint32_t *end_head, uint32_t *end_cyl, int flag)
86 {
87 uint64_t secs;
88
89 if(flag & 2)
90 secs = img_blocks;
91 else
92 secs = img_blocks * 4;
93 if (secs > (uint64_t) 0xfffffffc)
94 secs = 0xfffffffc; /* truncate rather than roll over */
95 if (flag & 1)
96 *end_lba = secs; /* first valid 512-lba */
97 else
98 secs = *end_lba = secs - 1; /* last valid 512-lba */
99 *end_cyl = secs / (sph * hpc);
100 secs -= *end_cyl * sph * hpc;
101 *end_head = secs / sph;
102 *end_sec = secs - *end_head * sph + 1; /* Sector count starts by 1 */
103 if (*end_cyl >= 1024) {
104 *end_cyl = 1023;
105 *end_head = hpc - 1;
106 *end_sec = sph;
107 }
108 }
109
110 /* @param flag bit0= The path contains instructions for the interval reader
111 @return ISO_SUCCESS = ok, partition will be written
112 ISO_SUCCESS + 1 = interval which shall be kept in place
113 else : error code
114 */
compute_partition_size(Ecma119Image * t,char * disk_path,uint32_t * size,int flag)115 static int compute_partition_size(Ecma119Image *t, char *disk_path,
116 uint32_t *size, int flag)
117 {
118 int ret, keep;
119 off_t num;
120 struct stat stbuf;
121 struct iso_interval_reader *ivr;
122 off_t byte_count;
123
124 if (flag & 1) {
125 ret = iso_interval_reader_new(t->image, disk_path,
126 &ivr, &byte_count, 0);
127 if (ret < 0)
128 return ret;
129 *size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
130 keep = iso_interval_reader_keep(t, ivr, 0);
131 iso_interval_reader_destroy(&ivr, 0);
132 if (keep < 0)
133 return keep;
134 return ISO_SUCCESS + (keep > 0);
135 }
136
137 *size = 0;
138 ret = stat(disk_path, &stbuf);
139 if (ret == -1)
140 return ISO_BAD_PARTITION_FILE;
141 if (! S_ISREG(stbuf.st_mode))
142 return ISO_BAD_PARTITION_FILE;
143 num = ((stbuf.st_size + 2047) / 2048);
144 if (num > 0x3fffffff || num == 0)
145 return ISO_BAD_PARTITION_FILE;
146 *size = num;
147 return ISO_SUCCESS;
148 }
149
150 /* Compute size and position of appended partitions.
151 @param flag bit0= Partitions inside ISO : update t->curblock
152 */
iso_compute_append_partitions(Ecma119Image * t,int flag)153 int iso_compute_append_partitions(Ecma119Image *t, int flag)
154 {
155 int ret, i, sa_type, cyl_align, cyl_size = 0;
156 int first_partition, last_partition;
157 uint32_t pos, size, add_pos = 0;
158 off_t start_byte, byte_count;
159 char msg[128];
160
161 sa_type = (t->system_area_options >> 2) & 0x3f;
162 cyl_align = (t->system_area_options >> 8) & 0x3;
163 if (sa_type == 0 && cyl_align == 3) {
164 cyl_size = t->partition_heads_per_cyl * t->partition_secs_per_head;
165 if (cyl_size % 4)
166 cyl_size = 0;
167 else
168 cyl_size /= 4;
169 }
170
171 #ifdef Libisofs_appended_partitions_inlinE
172
173 pos = t->curblock;
174
175 #else
176
177 pos = (t->vol_space_size + t->opts->ms_block);
178
179 #endif
180
181 iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
182 for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
183 if (t->opts->appended_partitions[i] == NULL)
184 continue;
185 if (t->opts->appended_partitions[i][0] == 0)
186 continue;
187 if (i + 1 > last_partition || i + 1 < first_partition) {
188 sprintf(msg,
189 "Partition number %d of appended partition is out of range [%d - %d]",
190 i + 1, first_partition, last_partition);
191 iso_msgs_submit(0, msg, 0, "FAILURE", 0);
192 return ISO_BAD_PARTITION_NO;
193 }
194
195 ret = compute_partition_size(t, t->opts->appended_partitions[i], &size,
196 t->opts->appended_part_flags[i]);
197 if (ret < 0)
198 return ret;
199 if (ret == ISO_SUCCESS + 1) {
200 /* Interval from imported_iso in add-on session */
201 t->appended_part_prepad[i] = 0;
202 ret = iso_interval_reader_start_size(t,
203 t->opts->appended_partitions[i],
204 &start_byte, &byte_count, 0);
205 if (ret < 0)
206 return ret;
207 t->appended_part_start[i] = start_byte / 2048;
208 t->appended_part_size[i] = size;
209 t->opts->iso_mbr_part_type = 0;
210 continue;
211 }
212
213 add_pos = 0;
214 if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) {
215 add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE);
216 } else if (cyl_size > 0 && (pos % cyl_size)) {
217 add_pos = cyl_size - (pos % cyl_size);
218 }
219 t->appended_part_prepad[i] = add_pos;
220 t->appended_part_start[i] = pos + add_pos;
221
222 if (cyl_size > 0 && (size % cyl_size)) {
223 /* Obey cylinder alignment (missing data will be written as
224 zeros by iso_write_partition_file()) */
225 size += cyl_size - (size % cyl_size);
226 }
227 t->appended_part_size[i] = size;
228 pos += add_pos + size;
229 t->total_size += (((off_t) add_pos) + size) * 2048;
230 if (flag & 1)
231 t->curblock = pos;
232 }
233 return ISO_SUCCESS;
234 }
235
236
mbr_part_slot_is_unused(uint8_t * slot)237 static int mbr_part_slot_is_unused(uint8_t *slot)
238 {
239 int i;
240
241 for (i = 0; i < 16; i++)
242 if (slot[i] != 0)
243 break;
244 if (i >= 16)
245 return 1;
246 return 0;
247 }
248
249
250 /* @param flag
251 bit1= partition_offset and partition_size are counted in
252 blocks of 512 rather than 2048
253 */
write_mbr_partition_entry(int partition_number,int partition_type,uint64_t partition_offset,uint64_t partition_size,int sph,int hpc,uint8_t * buf,int flag)254 static int write_mbr_partition_entry(int partition_number, int partition_type,
255 uint64_t partition_offset, uint64_t partition_size,
256 int sph, int hpc, uint8_t *buf, int flag)
257 {
258 uint8_t *wpt;
259 uint32_t end_lba, end_sec, end_head, end_cyl;
260 uint32_t start_lba, start_sec, start_head, start_cyl;
261 uint32_t after_end;
262 int i;
263
264 after_end = partition_offset + partition_size;
265 iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
266 &start_lba, &start_sec, &start_head, &start_cyl,
267 1 | (flag & 2));
268 iso_compute_cyl_head_sec((uint64_t) after_end, hpc, sph,
269 &end_lba, &end_sec, &end_head, &end_cyl,
270 (flag & 2));
271 wpt = buf + 446 + (partition_number - 1) * 16;
272
273 /* Not bootable */
274 *(wpt++) = 0x00;
275
276 /* C/H/S of the start */
277 *(wpt++) = start_head;
278 *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
279 *(wpt++) = start_cyl & 0xff;
280
281 /* (partition type) */
282 *(wpt++) = partition_type;
283
284 /* 3 bytes of C/H/S end */
285 *(wpt++) = end_head;
286 *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
287 *(wpt++) = end_cyl & 0xff;
288
289 /* LBA start in little endian */
290 for (i = 0; i < 4; i++)
291 *(wpt++) = (start_lba >> (8 * i)) & 0xff;
292
293 /* Number of sectors in partition, little endian */
294 end_lba = end_lba - start_lba + 1;
295 for (i = 0; i < 4; i++)
296 *(wpt++) = (end_lba >> (8 * i)) & 0xff;
297
298 /* Afaik, partition tables are recognize donly with MBR signature */
299 buf[510] = 0x55;
300 buf[511] = 0xAA;
301
302 return ISO_SUCCESS;
303 }
304
305
306 /* This is the gesture of grub-mkisofs --protective-msdos-label as explained by
307 Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org
308 "Currently we use first and not last entry. You need to:
309 1) Zero-fill 446-510
310 2) Put 0x55, 0xAA into 510-512
311 3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
312 (partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
313 start in little endian), [LBA end in little endian] at 446-462
314 "
315
316 "C/H/S end" means the CHS address of the last block in the partition.
317 It seems that not "[LBA end in little endian]" but "number of blocks"
318 should go into bytes 458-461. But with a start lba of 1, this is the
319 same number.
320 See also http://en.wikipedia.org/wiki/Master_boot_record
321
322 flag bit0= do not write 0x55, 0xAA to 510,511
323 bit1= do not mark partition as bootable
324 */
325 static
make_grub_msdos_label(uint32_t img_blocks,int sph,int hpc,uint8_t part_type,uint8_t * buf,int flag)326 int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
327 uint8_t part_type, uint8_t *buf, int flag)
328 {
329 uint8_t *wpt;
330 uint32_t end_lba, end_sec, end_head, end_cyl;
331 int i;
332
333 iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph,
334 &end_lba, &end_sec, &end_head, &end_cyl, 0);
335
336 /* 1) Zero-fill 446-510 */
337 wpt = buf + 446;
338 memset(wpt, 0, 64);
339
340 if (!(flag & 1)) {
341 /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
342 buf[510] = 0x55;
343 buf[511] = 0xAA;
344 }
345 if ((!(flag & 2)) && part_type != 0xee && part_type != 0xef) {
346 /* 3) Put 0x80 (for bootable partition), */
347 *(wpt++) = 0x80;
348 } else {
349 *(wpt++) = 0;
350 }
351
352 /* 0, 2, 0 (C/H/S of the start), */
353 *(wpt++) = 0;
354 *(wpt++) = 2;
355 *(wpt++) = 0;
356
357 /* 0xcd (partition type) */
358 *(wpt++) = part_type;
359
360 /* [3 bytes of C/H/S end], */
361 *(wpt++) = end_head;
362 *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
363 *(wpt++) = end_cyl & 0xff;
364
365
366 /* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */
367 *(wpt++) = 0x01;
368 *(wpt++) = 0x00;
369 *(wpt++) = 0x00;
370 *(wpt++) = 0x00;
371
372 /* [LBA end in little endian] */
373 for (i = 0; i < 4; i++)
374 *(wpt++) = (end_lba >> (8 * i)) & 0xff;
375
376 /* at 446-462 */
377 if (wpt - buf != 462) {
378 fprintf(stderr,
379 "libisofs: program error in make_grub_msdos_label: \"assert 462\"\n");
380 return ISO_ASSERT_FAILURE;
381 }
382 return ISO_SUCCESS;
383 }
384
385
386 /* @param flag bit0= zeroize partitions entries 2, 3, 4
387 bit1= UEFI protective MBR: start LBA = 1
388 */
389 static
iso_offset_partition_start(uint32_t img_blocks,int post_part_pad,uint32_t partition_offset,int sph,int hpc,uint8_t * buf,int flag)390 int iso_offset_partition_start(uint32_t img_blocks, int post_part_pad,
391 uint32_t partition_offset,
392 int sph, int hpc, uint8_t *buf, int flag)
393 {
394 uint8_t *wpt;
395 uint32_t end_lba, end_sec, end_head, end_cyl;
396 uint32_t start_lba, start_sec, start_head, start_cyl;
397 uint64_t img_hd_blocks;
398 int i;
399
400 iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
401 &start_lba, &start_sec, &start_head, &start_cyl, 1);
402 img_hd_blocks = ((uint64_t) img_blocks) * 4 - post_part_pad / 512;
403 iso_compute_cyl_head_sec(img_hd_blocks, hpc, sph,
404 &end_lba, &end_sec, &end_head, &end_cyl, 2);
405 if (flag & 2) {
406 start_lba = 1;
407 start_sec = 2;
408 start_head = start_cyl = 0;
409 }
410 wpt = buf + 446;
411
412 /* Let pass only legal bootability values */
413 if (*wpt != 0 && *wpt != 0x80)
414 (*wpt) = 0;
415 wpt++;
416
417 /* C/H/S of the start */
418 *(wpt++) = start_head;
419 *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
420 *(wpt++) = start_cyl & 0xff;
421
422 /* (partition type) */
423 wpt++;
424
425 /* 3 bytes of C/H/S end */
426 *(wpt++) = end_head;
427 *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
428 *(wpt++) = end_cyl & 0xff;
429
430 /* LBA start in little endian */
431 for (i = 0; i < 4; i++)
432 *(wpt++) = (start_lba >> (8 * i)) & 0xff;
433
434 /* Number of sectors in partition, little endian */
435 end_lba = end_lba - start_lba + 1;
436 for (i = 0; i < 4; i++)
437 *(wpt++) = (end_lba >> (8 * i)) & 0xff;
438
439 if (wpt - buf != 462) {
440 fprintf(stderr,
441 "libisofs: program error in iso_offset_partition_start: \"assert 462\"\n");
442 return ISO_ASSERT_FAILURE;
443 }
444
445 if (flag & 1) /* zeroize the other partition entries */
446 memset(wpt, 0, 3 * 16);
447
448 return ISO_SUCCESS;
449 }
450
451
boot_nodes_from_iso_path(Ecma119Image * t,char * path,IsoNode ** iso_node,Ecma119Node ** ecma_node,char * purpose,int flag)452 static int boot_nodes_from_iso_path(Ecma119Image *t, char *path,
453 IsoNode **iso_node, Ecma119Node **ecma_node,
454 char *purpose, int flag)
455 {
456 int ret;
457
458 ret = iso_tree_path_to_node(t->image, path, iso_node);
459 if (ret <= 0) {
460 iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
461 "Cannot find in ISO image: %s '%s'", purpose, path);
462 return ISO_BOOT_FILE_MISSING;
463 }
464 if ((*iso_node)->type != LIBISO_FILE) {
465 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
466 "Designated boot file is not a data file: '%s'", path);
467 return ISO_BOOT_IMAGE_NOT_VALID;
468 }
469
470 *ecma_node= ecma119_search_iso_node(t, *iso_node);
471 if (*ecma_node == NULL) {
472 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
473 "Program error: IsoFile has no Ecma119Node: '%s'", path);
474 return ISO_ASSERT_FAILURE;
475 } else {
476 if ((*ecma_node)->type != ECMA119_FILE) {
477 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
478 "Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'",
479 path);
480 return ISO_ASSERT_FAILURE;
481 }
482 }
483 return ISO_SUCCESS;
484 }
485
486
487 /* This function was implemented according to doc/boot_sectors.txt section
488 "MIPS Volume Header" which was derived by Thomas Schmitt from
489 cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based
490 on work of Florian Lohoff and Thiemo Seufer who possibly learned from
491 documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer
492 Systems, Inc.
493 This function itself is entirely under copyright (C) 2010 Thomas Schmitt.
494 */
make_mips_volume_header(Ecma119Image * t,uint8_t * buf,int flag)495 static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
496 {
497 char *namept, *name_field;
498 uint32_t num_cyl, idx, blocks, num, checksum;
499 off_t image_size;
500 static uint32_t bps = 512, spt = 32;
501 Ecma119Node *ecma_node;
502 IsoNode *node;
503 IsoStream *stream;
504 off_t file_size;
505 uint32_t file_lba;
506 int ret;
507
508 /* Bytes 512 to 32767 may come from image or external file */
509 memset(buf, 0, 512);
510
511 image_size = t->curblock * 2048;
512
513 /* 0 - 3 | 0x0be5a941 | Magic number */
514 iso_msb(buf, 0x0be5a941, 4);
515
516 /* 28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes */
517 num_cyl = (image_size + (bps * spt) - 1) / (bps * spt);
518 iso_msb(buf + 28, num_cyl & 0xffff, 2);
519
520 /* 32 - 33 | 1 | Number of tracks per cylinder */
521 iso_msb(buf + 32, 1, 2);
522
523 /* 35 - 35 | num_cyl_h | Number of usable cylinders, high byte */
524 buf[35] = (num_cyl >> 16) & 0xff;
525
526 /* 38 - 39 | 32 | Sectors per track */
527 iso_msb(buf + 38, spt, 2);
528
529 /* 40 - 41 | 512 | Bytes per sector */
530 iso_msb(buf + 40, bps, 2);
531
532 /* 44 - 47 | 0x00000034 | Controller characteristics */
533 iso_msb(buf + 44, 0x00000034, 4);
534
535 /* 72 - 87 | ========== | Volume Directory Entry 1 */
536 /* 72 - 79 | boot_name | Boot file basename */
537 /* 80 - 83 | boot_block | ISO 9660 LBA of boot file * 4 */
538 /* 84 - 87 | boot_bytes | File length in bytes */
539 /* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */
540
541 for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) {
542 ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx],
543 &node, &ecma_node, "MIPS boot file", 0);
544 if (ret < 0)
545 return ret;
546
547 namept = (char *) iso_node_get_name(node);
548 name_field = (char *) (buf + (72 + 16 * idx));
549 strncpy(name_field, namept, 8);
550
551 file_lba = ecma_node->info.file->sections[0].block;
552
553 iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
554
555 stream = iso_file_get_stream((IsoFile *) node);
556 file_size = iso_stream_get_size(stream);
557
558 /* genisoimage rounds up to full multiples of 2048.
559 libisofs did this too until 2020, but the arcload mips boot loader
560 throws error if the rounded size is stored here.
561 So now the exact bytecount gets stored.
562 */
563 iso_msb(buf + (72 + 16 * idx) + 12, file_size, 4);
564
565 }
566
567 /* 408 - 411 | part_blks | Number of 512 byte blocks in partition */
568 blocks = (image_size + bps - 1) / bps;
569 iso_msb(buf + 408, blocks, 4);
570 /* 416 - 419 | 0 | Partition is volume header */
571 iso_msb(buf + 416, 0, 4);
572
573 /* 432 - 435 | part_blks | Number of 512 byte blocks in partition */
574 iso_msb(buf + 432, blocks, 4);
575 iso_msb(buf + 444, 6, 4);
576
577 /* 504 - 507 | head_chk | Volume header checksum
578 The two's complement of bytes 0 to 503 read
579 as big endian unsigned 32 bit:
580 sum(32-bit-words) + head_chk == 0
581 */
582 checksum = 0;
583 for (idx = 0; idx < 504; idx += 4) {
584 num = iso_read_msb(buf + idx, 4);
585 /* Addition modulo a natural number is commutative and associative.
586 Thus the inverse of a sum is the sum of the inverses of the addends.
587 */
588 checksum -= num;
589 }
590 iso_msb(buf + 504, checksum, 4);
591
592 return ISO_SUCCESS;
593 }
594
595
596 /* The following two functions were implemented according to
597 doc/boot_sectors.txt section "MIPS Little Endian" which was derived
598 by Thomas Schmitt from
599 cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based
600 on work of Florian Lohoff and Thiemo Seufer,
601 and from <elf.h> by Free Software Foundation, Inc.
602
603 Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
604 */
605
606 /**
607 * Read the necessary ELF information from the first MIPS boot file.
608 * This is done before image writing starts.
609 */
iso_read_mipsel_elf(Ecma119Image * t,int flag)610 int iso_read_mipsel_elf(Ecma119Image *t, int flag)
611 {
612 uint32_t phdr_adr, todo, count;
613 int ret;
614 uint8_t *elf_buf = NULL;
615 IsoNode *iso_node;
616 Ecma119Node *ecma_node;
617 IsoStream *stream;
618
619 if (t->image->num_mips_boot_files <= 0)
620 {ret = ISO_SUCCESS; goto ex;}
621
622 LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048);
623 ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
624 &iso_node, &ecma_node, "MIPS boot file", 0);
625 if (ret < 0)
626 goto ex;
627 stream = iso_file_get_stream((IsoFile *) iso_node);
628
629 ret = iso_stream_open(stream);
630 if (ret < 0) {
631 iso_msg_submit(t->image->id, ret, 0,
632 "Cannot open designated MIPS boot file '%s'",
633 t->image->mips_boot_file_paths[0]);
634 goto ex;
635 }
636 ret = iso_stream_read(stream, elf_buf, 32);
637 if (ret != 32) {
638 cannot_read:;
639 iso_stream_close(stream);
640 iso_msg_submit(t->image->id, ret, 0,
641 "Cannot read from designated MIPS boot file '%s'",
642 t->image->mips_boot_file_paths[0]);
643 goto ex;
644 }
645
646
647 /* 24 - 27 | e_entry | Entry point virtual address */
648 t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4);
649
650 /* 28 - 31 | e_phoff | Program header table file offset */
651 phdr_adr = iso_read_lsb(elf_buf + 28, 4);
652
653 /* Skip stream up to byte address phdr_adr */
654 todo = phdr_adr - 32;
655 while (todo > 0) {
656 if (todo > 2048)
657 count = 2048;
658 else
659 count = todo;
660 todo -= count;
661 ret = iso_stream_read(stream, elf_buf, count);
662 if (ret != (int) count)
663 goto cannot_read;
664 }
665 ret = iso_stream_read(stream, elf_buf, 20);
666 if (ret != 20)
667 goto cannot_read;
668
669 /* 4 - 7 | p_offset | Segment file offset */
670 t->mipsel_p_offset = iso_read_lsb(elf_buf + 4, 4);
671
672 /* 8 - 11 | p_vaddr | Segment virtual address */
673 t->mipsel_p_vaddr = iso_read_lsb(elf_buf + 8, 4);
674
675 /* 16 - 19 | p_filesz | Segment size in file */
676 t->mipsel_p_filesz = iso_read_lsb(elf_buf + 16, 4);
677
678 iso_stream_close(stream);
679 ret = ISO_SUCCESS;
680 ex:;
681 LIBISO_FREE_MEM(elf_buf);
682 return ret;
683 }
684
685
686 /**
687 * Write DEC Bootblock from previously read ELF parameters.
688 * This is done when image writing has already begun.
689 */
make_mipsel_boot_block(Ecma119Image * t,uint8_t * buf,int flag)690 static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag)
691 {
692 int ret;
693 uint32_t seg_size, seg_start;
694 IsoNode *iso_node;
695 Ecma119Node *ecma_node;
696
697 /* Bytes 512 to 32767 may come from image or external file */
698 memset(buf, 0, 512);
699
700 if (t->image->num_mips_boot_files <= 0)
701 return ISO_SUCCESS;
702
703 ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
704 &iso_node, &ecma_node, "MIPS boot file", 0);
705 if (ret < 0)
706 return ret;
707
708 /* 8 - 11 | 0x0002757a | Magic number */
709 iso_lsb(buf + 8, 0x0002757a, 4);
710
711 /* 12 - 15 | 1 | Mode 1: Multi extent boot */
712 iso_lsb(buf + 12, 1, 4);
713
714 /* 16 - 19 | load_adr | Load address */
715 iso_lsb(buf + 16, t->mipsel_p_vaddr, 4);
716
717 /* 20 - 23 | exec_adr | Execution address */
718 iso_lsb(buf + 20, t->mipsel_e_entry, 4);
719
720 /* 24 - 27 | seg_size | Segment size in file. */
721 seg_size = (t->mipsel_p_filesz + 511) / 512;
722 iso_lsb(buf + 24, seg_size, 4);
723
724 /* 28 - 31 | seg_start | Segment file offset */
725 seg_start = ecma_node->info.file->sections[0].block * 4
726 + (t->mipsel_p_offset + 511) / 512;
727 iso_lsb(buf + 28, seg_start, 4);
728
729 return ISO_SUCCESS;
730 }
731
732
733 /* The following two functions were implemented according to
734 doc/boot_sectors.txt section "SUN Disk Label and boot images" which
735 was derived by Thomas Schmitt from
736 cdrtools-2.01.01a77/mkisofs/sunlabel.h
737 cdrtools-2.01.01a77/mkisofs/mkisofs.8
738 by Joerg Schilling
739
740 Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
741 */
742
743 /* @parm flag bit0= copy from next lower valid partition table entry
744 */
write_sun_partition_entry(int partition_number,char * appended_partitions[],uint32_t partition_offset[],uint32_t partition_size[],uint32_t cyl_size,uint8_t * buf,int flag)745 static int write_sun_partition_entry(int partition_number,
746 char *appended_partitions[],
747 uint32_t partition_offset[], uint32_t partition_size[],
748 uint32_t cyl_size, uint8_t *buf, int flag)
749 {
750 uint8_t *wpt;
751 int read_idx, i;
752
753 if (partition_number < 1 || partition_number > 8)
754 return ISO_ASSERT_FAILURE;
755
756 /* 142 - 173 | ========== | 8 partition entries of 4 bytes */
757 wpt = buf + 142 + (partition_number - 1) * 4;
758 if (partition_number == 1)
759 iso_msb(wpt, 4, 2); /* 4 = User partition */
760 else
761 iso_msb(wpt, 2, 2); /* 2 = Root partition with boot image */
762 iso_msb(wpt + 2, 0x10, 2); /* Permissions: 0x10 = read-only */
763
764 /* 444 - 507 | ========== | Partition table */
765 wpt = buf + 444 + (partition_number - 1) * 8;
766 read_idx = partition_number - 1;
767 if (flag & 1) {
768 /* Search next lower valid partition table entry. #1 is default */
769 for (read_idx = partition_number - 2; read_idx > 0; read_idx--)
770 if (appended_partitions[read_idx] != NULL)
771 if (appended_partitions[read_idx][0] != 0)
772 break;
773 }
774 iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4);
775 iso_msb(wpt + 4, partition_size[read_idx] * 4, 4);
776
777 /* 510 - 511 | checksum | The result of exoring 2-byte words 0 to 254 */
778 buf[510] = buf[511] = 0;
779 for (i = 0; i < 510; i += 2) {
780 buf[510] ^= buf[i];
781 buf[511] ^= buf[i + 1];
782 }
783
784 return ISO_SUCCESS;
785 }
786
787 /**
788 * Write SUN Disk Label with ISO in partition 1 and unused 2 to 8
789 */
make_sun_disk_label(Ecma119Image * t,uint8_t * buf,int flag)790 static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag)
791 {
792 int ret, i, l;
793 uint64_t blk;
794
795 /* Bytes 512 to 32767 may come from image or external file */
796 memset(buf, 0, 512);
797
798 /* 0 - 127 | label | ASCII Label */
799 if (t->opts->ascii_disc_label[0]) {
800 for (l = 0; l < 128 && t->opts->ascii_disc_label[l] != 0; l++);
801 if (l > 0)
802 memcpy((char *) buf, t->opts->ascii_disc_label, l);
803 } else {
804 strcpy((char *) buf,
805 "CD-ROM Disc with Sun sparc boot created by libisofs");
806 }
807
808 /* 128 - 131 | 1 | Layout version */
809 iso_msb(buf + 128, 1, 4);
810
811 /* 140 - 141 | 8 | Number of partitions */
812 iso_msb(buf + 140, 8, 2);
813
814 /* 188 - 191 | 0x600ddeee | vtoc sanity */
815 iso_msb(buf + 188, 0x600ddeee, 4);
816
817 /* 420 - 421 | 350 | Rotations per minute */
818 iso_msb(buf + 420, 350, 2);
819
820 /* 422 - 423 | 2048 | Number of physical cylinders (fixely 640 MB) */
821 iso_msb(buf + 422, 2048, 2);
822
823 /* 430 - 431 | 1 | interleave factor */
824 iso_msb(buf + 430, 1, 2);
825
826 /* 432 - 433 | 2048 | Number of data cylinders (fixely 640 MB) */
827 iso_msb(buf + 432, 2048, 2);
828
829 /* 436 - 437 | 1 | Number of heads per cylinder (1 cyl = 320 kB)*/
830 iso_msb(buf + 436, 1, 2);
831
832 /* 438 - 439 | 640 | Number of sectors per head (1 head = 320 kB) */
833 iso_msb(buf + 438, 640, 2);
834
835 /* 508 - 509 | 0xdabe | Magic Number */
836 iso_msb(buf + 508, 0xdabe, 2);
837
838 if (t->sparc_core_src != NULL) {
839 /* May be used for grub-sparc. */
840 blk= ((uint64_t) t->sparc_core_src->sections[0].block) *
841 (uint64_t) 2048;
842 for (i = 0; i < 8; i++)
843 buf[Libisofs_grub2_sparc_patch_adr_poS + i] = blk >> ((7 - i) * 8);
844 iso_msb(buf + Libisofs_grub2_sparc_patch_size_poS,
845 t->sparc_core_src->sections[0].size, 4);
846 }
847
848 /* Set partition 1 to describe ISO image and compute checksum */
849 t->appended_part_start[0] = 0;
850 t->appended_part_size[0] = t->curblock;
851 ret = write_sun_partition_entry(1, t->opts->appended_partitions,
852 t->appended_part_start, t->appended_part_size,
853 ISO_SUN_CYL_SIZE, buf, 0);
854 if (ret < 0)
855 return ret;
856 return ISO_SUCCESS;
857 }
858
859
hppa_palo_get_filepar(Ecma119Image * t,char * path,uint32_t * adr,uint32_t * len,int flag)860 static int hppa_palo_get_filepar(Ecma119Image *t, char *path,
861 uint32_t *adr, uint32_t *len, int flag)
862 {
863 int ret;
864 IsoNode *iso_node;
865 Ecma119Node *ecma_node;
866 off_t adr64;
867
868 ret = boot_nodes_from_iso_path(t, path,
869 &iso_node, &ecma_node, "HP-PA PALO boot file", 0);
870 if (ret < 0)
871 return ret;
872 if (iso_node_get_type(iso_node) != LIBISO_FILE) {
873 iso_msg_submit(t->image->id, ISO_HPPA_PALO_NOTREG, 0,
874 "HP-PA PALO file is not a data file");
875 return ISO_HPPA_PALO_NOTREG;
876 }
877 adr64 = ((off_t) 2048) * (off_t) ecma_node->info.file->sections[0].block;
878 if (adr64 > 0x7fffffff) {
879 iso_msg_submit(t->image->id, ISO_HPPA_PALO_OFLOW, 0,
880 "HP-PA PALO boot address exceeds 2 GB");
881 return ISO_HPPA_PALO_OFLOW;
882 }
883 *adr = adr64;
884 *len = ecma_node->info.file->sections[0].size;
885 return ISO_SUCCESS;
886 }
887
888
889 /**
890 * Write HP-PA PALO boot sector. See doc/boot_sectors.txt
891 *
892 * learned from cdrkit-1.1.10/genisoimage/boot-hppa.c
893 * by Steve McIntyre <steve@einval.com>
894 * who states "Heavily inspired by palo"
895 * Public mail conversations with Helge Deller, beginning with
896 * https://lists.debian.org/debian-hppa/2014/01/msg00016.html
897 * http://git.kernel.org/cgit/linux/kernel/git/deller/palo.git/tree/lib/
898 * (especially struct firstblock in common.h and struct partition in part.h)
899 *
900 */
make_hppa_palo_sector(Ecma119Image * t,uint8_t * buf,int hdrversion,int flag)901 static int make_hppa_palo_sector(Ecma119Image *t, uint8_t *buf, int hdrversion,
902 int flag)
903 {
904 int ret;
905 IsoImage *img;
906 uint32_t adr, len;
907
908 img = t->image;
909 if (img->hppa_cmdline == NULL && img->hppa_bootloader == NULL &&
910 img->hppa_kernel_32 == NULL && img->hppa_kernel_64 == NULL &&
911 img->hppa_ramdisk == NULL)
912 return ISO_SUCCESS;
913 if (img->hppa_cmdline == NULL || img->hppa_bootloader == NULL ||
914 img->hppa_kernel_32 == NULL || img->hppa_kernel_64 == NULL ||
915 img->hppa_ramdisk == NULL) {
916 iso_msg_submit(img->id, ISO_HPPA_PALO_INCOMPL, 0,
917 "Incomplete HP-PA PALO boot parameters");
918 return ISO_HPPA_PALO_INCOMPL;
919 }
920 if (hdrversion == 4) {
921 /* Bytes 256 to 32767 may come from loaded ISO image or external file */
922 memset(buf, 0, 256);
923 } else if(hdrversion == 5) {
924 memset(buf, 0, 512);
925 memset(buf + 1024, 0, 1024);
926 } else {
927 iso_msg_submit(img->id, ISO_WRONG_ARG_VALUE, 0,
928 "Unsupported HP-PA PALO header version %d (can do 4 or 5)",
929 hdrversion);
930 return ISO_WRONG_ARG_VALUE;
931 }
932
933 /* Magic */
934 iso_msb(buf + 0, 0x8000, 2);
935 /* Name of boot loader */
936 memcpy(buf + 2, "PALO", 5);
937 /* Version */
938 buf[7] = hdrversion;
939
940 /* Byte address and byte count of the "HPPA 32-bit kernel" file
941 */
942 ret = hppa_palo_get_filepar(t, img->hppa_kernel_32, &adr, &len, 0);
943 if (ret < 0)
944 return ret;
945 iso_msb(buf + 8, adr, 4);
946 iso_msb(buf + 12, len, 4);
947
948 /* Byte address and byte count of the "HPPA ramdisk" file
949 */
950 ret = hppa_palo_get_filepar(t, img->hppa_ramdisk, &adr, &len, 0);
951 if (ret < 0)
952 return ret;
953 iso_msb(buf + 16, adr, 4);
954 iso_msb(buf + 20, len, 4);
955
956 if (hdrversion == 4) {
957 /* "Command line" */
958 if (strlen(img->hppa_cmdline) > 127) {
959 iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
960 "HP-PA PALO command line too long");
961 return ISO_HPPA_PALO_CMDLEN;
962 }
963 memcpy(buf + 24, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
964 }
965
966 /* Byte address and byte count of the "HPPA 64-bit kernel" file
967 */
968 ret = hppa_palo_get_filepar(t, img->hppa_kernel_64, &adr, &len, 0);
969 if (ret < 0)
970 return ret;
971 iso_msb(buf + 232, adr, 4);
972 iso_msb(buf + 236, len, 4);
973
974 /* Byte address and byte count of the "HPPA bootloader" file
975 */
976 ret = hppa_palo_get_filepar(t, img->hppa_bootloader, &adr, &len, 0);
977 if (ret < 0)
978 return ret;
979 iso_msb(buf + 240, adr, 4);
980 iso_msb(buf + 244, len, 4);
981
982 if (hdrversion == 5) {
983 if (strlen(img->hppa_cmdline) > 1023) {
984 iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
985 "HP-PA PALO command line too long");
986 return ISO_HPPA_PALO_CMDLEN;
987 }
988 memcpy(buf + 1024, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
989 }
990 return ISO_SUCCESS;
991 }
992
993
994 /**
995 * Write DEC Alpha boot sector. See doc/boot_sectors.txt
996 *
997 * learned from cdrkit-1.1.10/genisoimage/boot-alpha.c
998 * by Steve McIntyre <steve@einval.com>
999 * who states "Heavily inspired by isomarkboot by David Mosberger in 1996"
1000 *
1001 */
make_dec_alpha_sector(Ecma119Image * t,uint8_t * buf,int flag)1002 static int make_dec_alpha_sector(Ecma119Image *t, uint8_t *buf, int flag)
1003 {
1004 int ret, i;
1005 IsoImage *img;
1006 IsoNode *iso_node;
1007 Ecma119Node *ecma_node;
1008 uint64_t size, lba, checksum = 0;
1009
1010 img = t->image;
1011 if (img->alpha_boot_image == NULL)
1012 return ISO_SUCCESS;
1013 ret = boot_nodes_from_iso_path(t, img->alpha_boot_image,
1014 &iso_node, &ecma_node, "DEC Alpha boot file", 0);
1015 if (ret < 0)
1016 return ret;
1017 memset(buf, 0, 512);
1018 strcpy((char *) buf, "Linux/Alpha aboot for ISO filesystem.");
1019 lba = ecma_node->info.file->sections[0].block * 4;
1020 size = ecma_node->info.file->sections[0].size / 512 +
1021 !!(ecma_node->info.file->sections[0].size % 512);
1022 iso_lsb(buf + 480, size & 0xffffffff, 4);
1023 iso_lsb(buf + 484, (size >> 32) & 0xffffffff, 4);
1024 iso_lsb(buf + 488, lba & 0xffffffff, 4);
1025 iso_lsb(buf + 492, (lba >> 32) & 0xffffffff, 4);
1026 for (i = 0; i < 63; i++)
1027 checksum += iso_read_lsb64(buf + 8 * i);
1028 iso_lsb(buf + 504, checksum & 0xffffffff, 4);
1029 iso_lsb(buf + 508, (checksum >> 32) & 0xffffffff, 4);
1030 return ISO_SUCCESS;
1031 }
1032
1033 /* Convenience frontend for iso_register_apm_entry().
1034 name and type are 0-terminated strings.
1035 */
iso_quick_apm_entry(struct iso_apm_partition_request ** req_array,int * apm_req_count,uint32_t start_block,uint32_t block_count,char * name,char * type)1036 int iso_quick_apm_entry(struct iso_apm_partition_request **req_array,
1037 int *apm_req_count,
1038 uint32_t start_block, uint32_t block_count,
1039 char *name, char *type)
1040 {
1041 int ret, l;
1042 struct iso_apm_partition_request *entry;
1043
1044 entry = calloc(1, sizeof(struct iso_apm_partition_request));
1045 if (entry == NULL)
1046 return ISO_OUT_OF_MEM;
1047 entry->start_block = start_block;
1048 entry->block_count = block_count;
1049 for (l = 0; l < 32 && name[l] != 0; l++);
1050 if (l > 0)
1051 memcpy((char *) entry->name, name, l);
1052 for (l = 0; l < 32 && type[l] != 0; l++);
1053 if (l > 0)
1054 memcpy((char *) entry->type, type, l);
1055 entry->req_status = 0;
1056 ret = iso_register_apm_entry(req_array, apm_req_count, entry, 0);
1057 free(entry);
1058 return ret;
1059 }
1060
1061
iso_find_gpt_entry(struct iso_gpt_partition_request ** req_array,int gpt_req_count,uint64_t start_block,uint64_t block_count,int * index,int flag)1062 static int iso_find_gpt_entry(struct iso_gpt_partition_request **req_array,
1063 int gpt_req_count,
1064 uint64_t start_block, uint64_t block_count,
1065 int *index, int flag)
1066 {
1067 struct iso_gpt_partition_request *entry;
1068
1069 for (*index = 0; *index < gpt_req_count; (*index)++) {
1070 entry = req_array[*index];
1071 if (entry->start_block == start_block &&
1072 entry->block_count == block_count)
1073 return 1;
1074 }
1075 *index = -1;
1076 return 0;
1077 }
1078
1079
1080 /* Convenience frontend for iso_register_gpt_entry().
1081 name has to be already encoded as UTF-16LE.
1082 */
iso_quick_gpt_entry(struct iso_gpt_partition_request ** req_array,int * gpt_req_count,uint64_t start_block,uint64_t block_count,uint8_t type_guid[16],uint8_t partition_guid[16],uint64_t flags,uint8_t name[72])1083 int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array,
1084 int *gpt_req_count,
1085 uint64_t start_block, uint64_t block_count,
1086 uint8_t type_guid[16], uint8_t partition_guid[16],
1087 uint64_t flags, uint8_t name[72])
1088 {
1089 int ret;
1090 struct iso_gpt_partition_request *entry;
1091
1092 entry = calloc(1, sizeof(struct iso_gpt_partition_request));
1093 if (entry == NULL)
1094 return ISO_OUT_OF_MEM;
1095 entry->start_block = start_block;
1096 entry->block_count = block_count;
1097 memcpy(entry->type_guid, type_guid, 16);
1098 memcpy(entry->partition_guid, partition_guid, 16);
1099 entry->flags = flags;
1100 memcpy(entry->name, name, 72);
1101 entry->req_status = 0;
1102 ret = iso_register_gpt_entry(req_array, gpt_req_count, entry, 0);
1103 free(entry);
1104 return ret;
1105 }
1106
1107
iso_quick_mbr_entry(struct iso_mbr_partition_request ** req_array,int * mbr_req_count,uint64_t start_block,uint64_t block_count,uint8_t type_byte,uint8_t status_byte,int desired_slot)1108 int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array,
1109 int *mbr_req_count,
1110 uint64_t start_block, uint64_t block_count,
1111 uint8_t type_byte, uint8_t status_byte,
1112 int desired_slot)
1113 {
1114 int ret;
1115 struct iso_mbr_partition_request *entry;
1116
1117 ret = iso_mbr_entry_slot_is_free(req_array, *mbr_req_count, desired_slot);
1118 if (ret < 0)
1119 desired_slot = 0;
1120 else if (ret == 0)
1121 return ISO_BOOT_MBR_COLLISION;
1122
1123 entry = calloc(1, sizeof(struct iso_mbr_partition_request));
1124 if (entry == NULL)
1125 return ISO_OUT_OF_MEM;
1126 entry->start_block = start_block;
1127 entry->block_count = block_count;
1128 entry->type_byte = type_byte;
1129 entry->status_byte = status_byte;
1130 entry->desired_slot = desired_slot;
1131 ret = iso_register_mbr_entry(req_array, mbr_req_count, entry, 0);
1132 free(entry);
1133 return ret;
1134 }
1135
1136
iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request ** req_array,int mbr_req_count,int slot)1137 int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array,
1138 int mbr_req_count, int slot)
1139 {
1140 int i;
1141
1142 if (slot < 0 || slot > ISO_MBR_ENTRIES_MAX)
1143 return -1;
1144 if (slot == 0)
1145 return 1;
1146 for (i = 0; i < mbr_req_count; i++)
1147 if (req_array[i]->desired_slot == slot)
1148 return 0;
1149 return 1;
1150 }
1151
1152
1153 /**
1154 * Compare the block interval positions of two iso_apm_partition_request
1155 */
1156 static
cmp_partition_request(const void * f1,const void * f2)1157 int cmp_partition_request(const void *f1, const void *f2)
1158 {
1159 struct iso_partition_request {
1160 uint64_t start_block;
1161 uint64_t block_count;
1162 } *r1, *r2;
1163
1164 r1 = *((struct iso_partition_request **) f1);
1165 r2 = *((struct iso_partition_request **) f2);
1166 if (r1->start_block < r2->start_block)
1167 return -1;
1168 if (r1->start_block > r2->start_block)
1169 return 1;
1170
1171 /* In case of overlapping the largest partition shall be first */
1172 if (r1->block_count > r2->block_count)
1173 return -1;
1174 if (r1->block_count < r2->block_count)
1175 return 1;
1176 return 0;
1177 }
1178
1179
1180 /* @param flag bit0= This is the entry in block 1. Its blocks are already in
1181 the desired apm_block_size unit. Set block_fac to 1.
1182 Set flags to 3 rather than 0x13.
1183 */
iso_write_apm_entry(Ecma119Image * t,int apm_block_size,struct iso_apm_partition_request * req,uint8_t * buf,int map_entries,int flag)1184 static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size,
1185 struct iso_apm_partition_request *req,
1186 uint8_t *buf, int map_entries, int flag)
1187 {
1188 uint8_t *wpt;
1189 uint32_t flags;
1190 int block_fac;
1191
1192 if ((flag & 1) || (t->apm_req_flags & 4))
1193 block_fac = 1;
1194 else
1195 block_fac = 2048 / apm_block_size;
1196
1197 memset(buf, 0, apm_block_size);
1198 wpt = buf;
1199
1200 /* Signature */
1201 wpt[0] = 'P'; wpt[1] = 'M';
1202 wpt+= 2;
1203 /* reserved */
1204 wpt += 2;
1205 /* Number of partition entries */
1206 iso_msb(wpt, (uint32_t) map_entries, 4);
1207 wpt += 4;
1208 /* Physical block start of partition */
1209 iso_msb(wpt, (uint32_t) (req->start_block * block_fac), 4);
1210 wpt += 4;
1211 /* Physical block count of partition */
1212 iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
1213 wpt += 4;
1214 /* Partition name */
1215 memcpy(wpt, req->name, 32);
1216 wpt += 32;
1217 /* Type string */
1218 memcpy(wpt, req->type, 32);
1219 wpt += 32;
1220 /* Logical block start */
1221 iso_msb(wpt, (uint32_t) 0, 4);
1222 wpt += 4;
1223 /* Logical block count */
1224 iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
1225 wpt += 4;
1226 /* Status flags : bit0= entry is valid , bit1= entry is allocated
1227 bit4= partition is readable , bit5= partition is writable
1228 bit30= automatic mount (legacy Mac)
1229 */
1230 if (flag & 1) {
1231 flags = 3;
1232 } else {
1233 flags = 0x13;
1234 if (strncmp((char *) req->type, "Apple_HFS", 9) == 0 &&
1235 req->type[9] == 0)
1236 flags |= 0x40000000;
1237 }
1238 iso_msb(wpt, flags, 4);
1239 wpt += 4;
1240
1241 /* boot_block , boot_bytes , processor , reserved : are all 0 */
1242
1243 return ISO_SUCCESS;
1244 }
1245
1246
1247 /* Sort and fill gaps in requested APM */
fill_apm_gaps(Ecma119Image * t,uint32_t img_blocks)1248 static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks)
1249 {
1250 int i, ret, gap_counter = 0, up_to;
1251 uint32_t part_end, goal, block_fac = 1;
1252 char gap_name[33];
1253
1254 if (t->apm_req_flags & 4) {
1255 if (t->opts->apm_block_size == 0)
1256 t->opts->apm_block_size = 2048;
1257 block_fac = 2048 / t->opts->apm_block_size;
1258 }
1259
1260 /* Find out whether an entry with start_block <= 1 is requested */
1261 for (i = 0; i < t->apm_req_count; i++) {
1262 if (t->apm_req[i]->start_block <= 1)
1263 break;
1264 }
1265 if (i >= t->apm_req_count) {
1266 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1267 1, 0, "Apple", "Apple_partition_map");
1268 if (ret < 0)
1269 return ret;
1270 }
1271
1272 qsort(t->apm_req, t->apm_req_count,
1273 sizeof(struct iso_apm_partition_request *), cmp_partition_request);
1274
1275 if (t->opts->part_like_isohybrid)
1276 return 1; /* No filling, only sorting */
1277
1278 /* t->apm_req_count will grow during the loop */
1279 up_to = t->apm_req_count + 1;
1280 for (i = 1; i < up_to; i++) {
1281 if (i < up_to - 1)
1282 goal = (uint32_t) t->apm_req[i]->start_block;
1283 else
1284 goal = img_blocks * block_fac;
1285 if (i == 1) {
1286 /* Description of APM itself */
1287 /* Actual APM size is not yet known. Protection begins at PVD */
1288 part_end = 16 * block_fac;
1289 if (goal < part_end && goal> 1)
1290 part_end = goal;
1291 } else {
1292 part_end = t->apm_req[i - 1]->start_block +
1293 t->apm_req[i - 1]->block_count;
1294 }
1295 if (part_end > goal) {
1296 iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0,
1297 "Program error: APM partitions %d and %d overlap by %lu blocks",
1298 i - 1, i, part_end - goal);
1299 return ISO_BOOT_APM_OVERLAP;
1300 }
1301
1302 if (t->apm_req_flags & 2) /* Do not fill gaps */
1303 continue;
1304
1305 if (part_end < goal || i == up_to - 1) { /* Always add a final entry */
1306 sprintf(gap_name, "Gap%d", gap_counter);
1307 gap_counter++;
1308 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1309 part_end, goal - part_end,
1310 gap_name, "ISO9660_data");
1311 if (ret < 0)
1312 return ret;
1313 /* Mark as automatically placed filler request */
1314 t->apm_req[t->apm_req_count - 1]->req_status |= 1;
1315 }
1316 }
1317
1318 /* Merge list of gap partitions with list of already sorted entries */
1319 if (!(t->apm_req_flags & 2)) /* No gaps were filled */
1320 qsort(t->apm_req, t->apm_req_count,
1321 sizeof(struct iso_apm_partition_request *), cmp_partition_request);
1322
1323 return 1;
1324 }
1325
1326
rectify_apm(Ecma119Image * t)1327 static int rectify_apm(Ecma119Image *t)
1328 {
1329 int ret;
1330
1331 #ifdef NIX
1332 /* Disabled */
1333
1334 /* <<< ts B20526 : Dummy mock-up */
1335 if (t->apm_req_count <= 0) {
1336 /*
1337 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1338 16, 20, "Test1_name_16_20", "Test1_type");
1339 / * >>> Caution: Size 90 causes intentional partition overlap error * /
1340 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1341 30, 90, "BAD_30_90_BAD", "Test1_type");
1342 */
1343 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1344 30, 20, "Test1_name_30_20", "Test1_type");
1345 if (ret < 0)
1346 return ret;
1347 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1348 100, 400, "Test2_name_100_400", "Test2_type");
1349 if (ret < 0)
1350 return ret;
1351 }
1352 #endif /* NIX */
1353
1354 if (t->apm_req_count == 0)
1355 return 1;
1356
1357 if (t->gpt_req_count > 0 &&
1358 t->opts->apm_block_size != 2048 && t->apm_req_count > 0) {
1359 iso_msgs_submit(0,
1360 "GPT and APM requested. APM block size would have to be 2048.",
1361 0, "FAILURE", 0);
1362 return ISO_BOOT_APM_GPT_BSIZE;
1363 }
1364 if (t->apm_req_count > 0) {
1365 ret = fill_apm_gaps(t, t->curblock);
1366 if (ret < 0)
1367 return ret;
1368 }
1369 return 1;
1370 }
1371
1372
1373 /* flag bit0= do not write Block0
1374 */
iso_write_apm(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf,int flag)1375 static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf,
1376 int flag)
1377 {
1378 int i, ret;
1379 uint32_t block_fac = 1;
1380 /* This is a micro mock-up of an APM Block0
1381 and also harmless x86 machine code.
1382 */
1383 static uint8_t block0_template[8] = {
1384 0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff
1385 };
1386
1387 if (t->apm_req_count <= 0)
1388 return 2;
1389
1390 if (t->opts->apm_block_size == 0) {
1391 /* One cannot be sure that all GPT partitions are registered
1392 already. So it is necessary to choose the block size which is
1393 combinable with GPT but not mountable on Linux.
1394 */
1395 t->opts->apm_block_size = 2048;
1396 }
1397
1398 if (t->apm_req_flags & 4)
1399 block_fac = 2048 / t->opts->apm_block_size;
1400
1401 if (!(t->apm_req_flags & 2)) {
1402 /* Gaps have been filled. Care for the final one */
1403 /* Adjust last partition to img_size. This size was not known when the
1404 number of APM partitions was determined.
1405 */
1406 if (img_blocks * block_fac <
1407 t->apm_req[t->apm_req_count - 1]->start_block)
1408 t->apm_req[t->apm_req_count - 1]->block_count = 0;
1409 else
1410 t->apm_req[t->apm_req_count - 1]->block_count =
1411 img_blocks * block_fac -
1412 t->apm_req[t->apm_req_count - 1]->start_block;
1413 /* If it is still empty, remove it */
1414 if(t->apm_req[t->apm_req_count - 1]->block_count == 0) {
1415 free(t->apm_req[t->apm_req_count - 1]);
1416 t->apm_req_count--;
1417 }
1418 }
1419
1420 /* If block size is larger than 512, then not all 63 entries will fit */
1421 if ((t->apm_req_count + 1) * t->opts->apm_block_size > 32768)
1422 return ISO_BOOT_TOO_MANY_APM;
1423
1424 /* Block 1 describes the APM itself */
1425 t->apm_req[0]->start_block = 1;
1426 t->apm_req[0]->block_count = t->apm_req_count;
1427
1428 if (!(flag & 1)) {
1429 /* Write APM block 0. Very sparse, not to overwrite much of
1430 possible MBR.
1431 */
1432 memcpy(buf, block0_template, 8);
1433 buf[2]= (t->opts->apm_block_size >> 8) & 0xff;
1434 buf[3]= 0;
1435 }
1436
1437 /* Write APM Block 1 to t->apm_req_count */
1438 for (i = 0; i < t->apm_req_count; i++) {
1439 ret = iso_write_apm_entry(t, t->opts->apm_block_size, t->apm_req[i],
1440 buf + (i + 1) * t->opts->apm_block_size, t->apm_req_count,
1441 i == 0);
1442 if (ret < 0)
1443 return ret;
1444 }
1445 return ISO_SUCCESS;
1446 }
1447
1448
iso_write_mbr(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf)1449 static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
1450 {
1451 int i, ret, req_of_slot[ISO_MBR_ENTRIES_MAX], q, j;
1452
1453 #ifdef NIX
1454 /* Disabled */
1455
1456 /* <<< Dummy mock-up */
1457 if (t->mbr_req_count <= 0) {
1458 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
1459 (uint64_t) 0, (uint64_t) 0, 0xee, 0, 0);
1460 if (ret < 0)
1461 return ret;
1462 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
1463 ((uint64_t) 100) * 4, (uint64_t) 0,
1464 0x0c, 0x80, 1);
1465 if (ret < 0)
1466 return ret;
1467 }
1468 #endif /* NIX */
1469
1470 if (t->mbr_req_count <= 0)
1471 return 2;
1472
1473 /* >>> Sort by start block ? */
1474
1475 /* Adjust partition ends */
1476 for (i = 0; i < t->mbr_req_count; i++) {
1477 if (i > 0) {
1478 if (t->mbr_req[i]->start_block <= t->mbr_req[i - 1]->start_block &&
1479 !(t->mbr_req[i]->block_count == 0 &&
1480 t->mbr_req[i]->start_block ==
1481 t->mbr_req[i - 1]->start_block))
1482 return ISO_BOOT_MBR_OVERLAP;
1483 if (t->mbr_req[i - 1]->start_block +
1484 t->mbr_req[i - 1]->block_count > t->mbr_req[i]->start_block)
1485 return ISO_BOOT_MBR_OVERLAP;
1486 }
1487 if (t->mbr_req[i]->block_count != 0)
1488 continue;
1489 if (i < t->mbr_req_count - 1)
1490 t->mbr_req[i]->block_count = t->mbr_req[i + 1]->start_block -
1491 t->mbr_req[i]->start_block;
1492 else
1493 t->mbr_req[i]->block_count = ((uint64_t) img_blocks) * 4 -
1494 t->mbr_req[i]->start_block;
1495 }
1496
1497 /* Assign requested entries to slot numbers */
1498 for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++)
1499 req_of_slot[i] = -1;
1500 for (i = 0; i < t->mbr_req_count; i++) {
1501 if (t->mbr_req[i]->desired_slot < 1 ||
1502 t->mbr_req[i]->desired_slot > ISO_MBR_ENTRIES_MAX)
1503 continue;
1504 if (req_of_slot[t->mbr_req[i]->desired_slot - 1] >= 0)
1505 return ISO_BOOT_MBR_COLLISION;
1506 req_of_slot[t->mbr_req[i]->desired_slot - 1] = i;
1507 }
1508 for (i = 0; i < t->mbr_req_count; i++) {
1509 if (t->mbr_req[i]->desired_slot > 0)
1510 continue;
1511 for (j = 0; j < ISO_MBR_ENTRIES_MAX; j++)
1512 if (req_of_slot[j] < 0)
1513 break;
1514 if (j >= ISO_MBR_ENTRIES_MAX)
1515 return ISO_BOOT_TOO_MANY_MBR;
1516 req_of_slot[j] = i;
1517 }
1518
1519 /* Write partition slots */
1520 for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) {
1521 memset(buf + 446 + i * 16, 0, 16);
1522 q = req_of_slot[i];
1523 if (q < 0)
1524 continue;
1525 if (t->mbr_req[q]->block_count == 0)
1526 continue;
1527 ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[q]->type_byte,
1528 t->mbr_req[q]->start_block, t->mbr_req[q]->block_count,
1529 t->partition_secs_per_head, t->partition_heads_per_cyl,
1530 buf, 2);
1531 if (ret < 0)
1532 return ret;
1533 buf[446 + i * 16] = t->mbr_req[q]->status_byte;
1534 }
1535 return ISO_SUCCESS;
1536 }
1537
1538
iso_write_gpt_entry(Ecma119Image * t,uint8_t * buf,uint8_t type_guid[16],uint8_t part_uuid[16],uint64_t start_lba,uint64_t end_lba,uint64_t flags,uint8_t name[72])1539 static void iso_write_gpt_entry(Ecma119Image *t, uint8_t *buf,
1540 uint8_t type_guid[16], uint8_t part_uuid[16],
1541 uint64_t start_lba, uint64_t end_lba,
1542 uint64_t flags, uint8_t name[72])
1543 {
1544 char *wpt;
1545 int i;
1546
1547 wpt = (char *) buf;
1548 memcpy(wpt, type_guid, 16);
1549 wpt += 16;
1550 for (i = 0; i < 16; i++)
1551 if (part_uuid[i])
1552 break;
1553 if (i == 16) {
1554 if (!t->gpt_disk_guid_set)
1555 iso_gpt_uuid(t, t->gpt_disk_guid);
1556 t->gpt_disk_guid_set = 1;
1557 iso_gpt_uuid(t, part_uuid);
1558 }
1559 memcpy(wpt, part_uuid, 16);
1560 wpt += 16;
1561 iso_lsb_to_buf(&wpt, start_lba & 0xffffffff, 4, 0);
1562 iso_lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 4, 0);
1563 iso_lsb_to_buf(&wpt, end_lba & 0xffffffff, 4, 0);
1564 iso_lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 4, 0);
1565 iso_lsb_to_buf(&wpt, flags & 0xffffffff, 4, 0);
1566 iso_lsb_to_buf(&wpt, (flags >> 32) & 0xffffffff, 4, 0);
1567 memcpy(wpt, name, 72);
1568 }
1569
1570
iso_write_gpt_header_block(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf,uint32_t max_entries,uint32_t part_start,uint32_t p_arr_crc)1571 int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks,
1572 uint8_t *buf, uint32_t max_entries,
1573 uint32_t part_start, uint32_t p_arr_crc)
1574 {
1575 static char *sig = "EFI PART";
1576 static char revision[4] = {0x00, 0x00, 0x01, 0x00};
1577 char *wpt;
1578 uint32_t crc;
1579 off_t back_lba;
1580
1581 memset(buf, 0, 512);
1582 wpt = (char *) buf;
1583
1584 /* >>> Make signature adjustable */
1585 memcpy(wpt, sig, 8); /* no trailing 0 */
1586 wpt += 8;
1587
1588 memcpy(wpt, revision, 4);
1589 wpt += 4;
1590 iso_lsb_to_buf(&wpt, 92, 4, 0);
1591
1592 /* CRC will be inserted later */
1593 wpt += 4;
1594
1595 /* reserved */
1596 iso_lsb_to_buf(&wpt, 0, 4, 0);
1597 /* Own LBA low 32 */
1598 iso_lsb_to_buf(&wpt, 1, 4, 0);
1599 /* Own LBA high 32 */
1600 iso_lsb_to_buf(&wpt, 0, 4, 0);
1601
1602 /* Backup header LBA is 1 hd block before backup GPT area end */
1603 back_lba = t->gpt_backup_end * 4 - 1;
1604 iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1);
1605 iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1);
1606
1607 /* First usable LBA for partitions (4 entries per hd block) */
1608 iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0);
1609 iso_lsb_to_buf(&wpt, 0, 4, 0);
1610
1611 /* Last usable LBA for partitions is 1 hd block before first backup entry*/
1612 iso_lsb_to_buf(&wpt,
1613 (uint32_t) ((back_lba - max_entries / 4 - 1) & 0xffffffff),
1614 4, 1);
1615 iso_lsb_to_buf(&wpt,
1616 (uint32_t) ((back_lba - max_entries / 4 - 1) >> 32), 4, 1);
1617
1618 /* Disk GUID */
1619 if (!t->gpt_disk_guid_set)
1620 iso_gpt_uuid(t, t->gpt_disk_guid);
1621 t->gpt_disk_guid_set = 1;
1622 memcpy(wpt, t->gpt_disk_guid, 16);
1623 wpt += 16;
1624
1625 /* Partition entries start */
1626 iso_lsb_to_buf(&wpt, part_start, 4, 0);
1627 iso_lsb_to_buf(&wpt, 0, 4, 0);
1628
1629 /* Number of partition entries */
1630 iso_lsb_to_buf(&wpt, max_entries, 4, 0);
1631
1632 /* Size of a partition entry */
1633 iso_lsb_to_buf(&wpt, 128, 4, 0);
1634
1635 /* CRC-32 of the partition array */
1636 iso_lsb_to_buf(&wpt, p_arr_crc, 4, 0);
1637
1638
1639 /* <<< Only for a first test */
1640 if (wpt - (char *) buf != 92) {
1641 iso_msgs_submit(0,
1642 "program error : write_gpt_header_block : wpt != 92",
1643 0, "FATAL", 0);
1644 return ISO_ISOLINUX_CANT_PATCH;
1645 }
1646
1647 /* CRC-32 of this header while head_crc is 0 */
1648 crc = iso_crc32_gpt((unsigned char *) buf, 92, 0);
1649 wpt = ((char *) buf) + 16;
1650 iso_lsb_to_buf(&wpt, crc, 4, 0);
1651
1652 return ISO_SUCCESS;
1653 }
1654
1655
1656 /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */
iso_ascii_utf_16le(uint8_t gap_name[72])1657 void iso_ascii_utf_16le(uint8_t gap_name[72])
1658 {
1659 int i;
1660
1661 for (i = strlen((char *) gap_name) - 1; i >= 0; i--) {
1662 gap_name[2 * i] = gap_name[i];
1663 gap_name[2 * i + 1] = 0;
1664 }
1665 }
1666
1667
intvl_overlap(uint64_t start1,uint64_t end1,uint64_t start2,uint64_t end2,int second)1668 static int intvl_overlap(uint64_t start1, uint64_t end1,
1669 uint64_t start2, uint64_t end2, int second)
1670 {
1671 if (start1 >= start2 && start1 <= end2)
1672 return 1;
1673 if (end1 >= start2 && end1 <= end2)
1674 return 1;
1675 if (!second)
1676 return intvl_overlap(start2, end2, start1, end1, 1);
1677 return 0;
1678 }
1679
1680
1681 /* Check APM HFS+ partitions whether they would fit in gaps.
1682 If so, add them as GPT partitions, too.
1683 */
iso_copy_apmhfs_to_gpt(Ecma119Image * t,int flag)1684 static int iso_copy_apmhfs_to_gpt(Ecma119Image *t, int flag)
1685 {
1686 int a, i, counter = 0, ret;
1687 uint64_t bfac = 4;
1688 static uint8_t hfs_plus_uuid[16] = {
1689 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
1690 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
1691 };
1692 static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1693 uint8_t gpt_name[72];
1694 static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
1695
1696 if ((t->apm_req_flags & 4) && t->opts->apm_block_size / 512 > 0)
1697 bfac = t->opts->apm_block_size / 512;
1698
1699 for (a = 0; a < t->apm_req_count; a++) {
1700 if (strcmp((char *) t->apm_req[a]->type, "Apple_HFS") != 0)
1701 continue;
1702 for (i = 0; i < t->gpt_req_count; i++)
1703 if (intvl_overlap(t->apm_req[a]->start_block * bfac,
1704 (t->apm_req[a]->start_block +
1705 t->apm_req[a]->block_count - 1) * bfac,
1706 t->gpt_req[i]->start_block,
1707 t->gpt_req[i]->start_block +
1708 t->gpt_req[i]->block_count - 1, 0))
1709 break;
1710 if (i >= t->gpt_req_count) {
1711 memset(gpt_name, 0, 72);
1712 counter++;
1713 if (counter > 1)
1714 sprintf((char *) gpt_name, "HFSPLUS_%d", counter);
1715 else
1716 sprintf((char *) gpt_name, "HFSPLUS");
1717 iso_ascii_utf_16le(gpt_name);
1718 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
1719 t->apm_req[a]->start_block * bfac,
1720 t->apm_req[a]->block_count * bfac,
1721 hfs_plus_uuid, zero_uuid,
1722 gpt_flags, gpt_name);
1723 if (ret < 0)
1724 return ret;
1725 }
1726 }
1727 return 1;
1728 }
1729
1730
iso_write_gpt(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf)1731 static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
1732 {
1733 static uint8_t basic_data_uuid[16] = {
1734 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
1735 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
1736 };
1737
1738 uint32_t p_arr_crc = 0;
1739 uint64_t start_lba, end_lba, goal, part_end, next_end, backup_end_lba;
1740 int ret, i, gap_counter = 0, up_to;
1741 struct iso_gpt_partition_request *req;
1742 uint8_t gpt_name[72];
1743 static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1744 static uint8_t *type_guid;
1745 static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
1746
1747 if (t->gpt_req_count == 0)
1748 return 2;
1749 backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * 4;
1750
1751 ret = iso_copy_apmhfs_to_gpt(t, 0);
1752 if (ret <= 0)
1753 return ret;
1754
1755 /* Sort and fill gaps */
1756 qsort(t->gpt_req, t->gpt_req_count,
1757 sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
1758 /* t->gpt_req_count will grow during the loop */
1759 up_to = t->gpt_req_count + 1;
1760 goal = 0;
1761 part_end = 0;
1762
1763 if (t->opts->part_like_isohybrid)
1764 up_to = 0; /* No gap filling */
1765
1766 for (i = 0; i < up_to; i++) {
1767 if (i < up_to - 1) {
1768 goal = t->gpt_req[i]->start_block;
1769 } else {
1770 goal = ((uint64_t) img_blocks) * 4;
1771 if (goal > backup_end_lba)
1772 goal = backup_end_lba;
1773 }
1774 if (i == 0) {
1775 if (goal <= 16 * 4)
1776 continue;
1777 next_end = 16 * 4;
1778 } else {
1779 next_end = t->gpt_req[i - 1]->start_block +
1780 t->gpt_req[i - 1]->block_count;
1781 }
1782 if (next_end > part_end)
1783 part_end = next_end;
1784 if (part_end > goal) {
1785 if (!(t->gpt_req_flags & 1)) {
1786 iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0,
1787 "Program error: GPT partitions %d and %d overlap by %.f blocks",
1788 i - 1, i, (double) (part_end - goal));
1789 return ISO_BOOT_GPT_OVERLAP;
1790 }
1791 } else if (part_end < goal) {
1792 memset(gpt_name, 0, 72);
1793 type_guid = basic_data_uuid;
1794 if (goal == t->vol_space_size * (uint64_t) 4 &&
1795 part_end == t->opts->partition_offset * (uint64_t) 4) {
1796 sprintf((char *) gpt_name, "ISO9660");
1797 if (t->opts->iso_gpt_flag & 1)
1798 type_guid = t->opts->iso_gpt_type_guid;
1799 } else {
1800 sprintf((char *) gpt_name, "Gap%d", gap_counter);
1801 }
1802 iso_ascii_utf_16le(gpt_name);
1803 gap_counter++;
1804 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
1805 part_end, goal - part_end,
1806 type_guid, zero_uuid,
1807 gpt_flags, gpt_name);
1808 if (ret < 0)
1809 return ret;
1810 /* Mark as automatically placed filler request */
1811 t->gpt_req[t->gpt_req_count - 1]->req_status |= 1;
1812 }
1813 }
1814 /* Merge list of gap partitions with list of already sorted entries */
1815 qsort(t->gpt_req, t->gpt_req_count,
1816 sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
1817
1818 if ((int) t->gpt_max_entries < t->gpt_req_count)
1819 return ISO_BOOT_TOO_MANY_GPT;
1820
1821 /* Write the GPT entries to buf */
1822 for (i = 0; i < t->gpt_req_count; i++) {
1823 req = t->gpt_req[i];
1824 start_lba = req->start_block;
1825 end_lba = req->start_block + req->block_count;
1826 if (req->start_block == t->opts->partition_offset * ((uint64_t) 4) &&
1827 req->block_count == ((uint64_t) 4) * 0xffffffff)
1828 end_lba = t->vol_space_size * 4;
1829 if (end_lba > backup_end_lba)
1830 end_lba = backup_end_lba;
1831 end_lba = end_lba - 1;
1832 iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i,
1833 req->type_guid, req->partition_guid,
1834 start_lba, end_lba, req->flags, req->name);
1835 }
1836 for (; i < (int) t->gpt_max_entries; i++)
1837 memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128);
1838
1839 p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start,
1840 128 * t->gpt_max_entries, 0);
1841 ret = iso_write_gpt_header_block(t, img_blocks, buf + 512,
1842 t->gpt_max_entries,
1843 t->gpt_part_start, p_arr_crc);
1844 if (ret < 0)
1845 return ret;
1846 return ISO_SUCCESS;
1847 }
1848
1849
1850 /* Add a dummy MBR partition of type 0 with boot flag */
iso_dummy_mbr_partition(uint8_t * buf,int mode)1851 static void iso_dummy_mbr_partition(uint8_t *buf, int mode)
1852 {
1853 int i;
1854 /* bootable , start 0/0/1, type 0x00, end 0/0/1,
1855 start LBA 0, block count 1 */
1856 static uint8_t dummy_entry[16] = {
1857 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
1858 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
1859
1860 for (i = 0; i < 4; i++) {
1861 if (mbr_part_slot_is_unused(buf + 446 + 16 * i)) {
1862 memcpy(buf + 446 + 16 * i, dummy_entry, 16);
1863 return;
1864 }
1865 }
1866 /* Abundance of 0xee and 0xef partitions. No other one free. */
1867 for (i = 0; i < 4; i++) {
1868 if (buf[446 + 16 * i + 4] != 0xef) {
1869 buf[446 + 16 * i] |= 0x80;
1870 return;
1871 }
1872 }
1873 i = 3;
1874 buf[446 + 16 * i] |= 0x80;
1875 }
1876
1877
1878 /* @param flag
1879 bit0= t->opts->ms_block is not counted in t->total_size
1880 */
iso_write_system_area(Ecma119Image * t,uint8_t * buf,int flag)1881 int iso_write_system_area(Ecma119Image *t, uint8_t *buf, int flag)
1882 {
1883 int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0;
1884 int first_partition = 1, last_partition = 4, apm_flag, part_type = 0;
1885 int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0;
1886 int offset_flag = 0, risk_of_ee = 0;
1887 uint32_t img_blocks, gpt_blocks, mbrp1_blocks, pml_blocks;
1888 uint64_t blk;
1889 uint8_t *wpt;
1890
1891 if ((t == NULL) || (buf == NULL)) {
1892 return ISO_NULL_POINTER;
1893 }
1894
1895 /* set buf to 0s */
1896 memset(buf, 0, 16 * BLOCK_SIZE);
1897
1898 sa_type = (t->system_area_options >> 2) & 0x3f;
1899
1900 iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
1901 for (i = first_partition - 1; i <= last_partition - 1; i++)
1902 if (t->opts->appended_partitions[i] != NULL) {
1903 will_append = 1;
1904 break;
1905 }
1906
1907 #ifdef Libisofs_appended_partitions_inlinE
1908 img_blocks = t->vol_space_size;
1909 #else
1910 img_blocks = t->curblock;
1911 #endif
1912
1913 if (t->system_area_data != NULL) {
1914 /* Write more or less opaque boot image */
1915 memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE);
1916
1917 } else if (sa_type == 0 && t->catalog != NULL &&
1918 (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
1919 /* Check for isolinux image with magic number of 3.72 and produce
1920 an MBR from our built-in template. (Deprecated since 31 Mar 2010)
1921 */
1922 if (t->bootsrc[0] == NULL)
1923 return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
1924 "Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
1925 if (img_blocks < 0x80000000) {
1926 int_img_blocks= img_blocks;
1927 } else {
1928 int_img_blocks= 0x7ffffff0;
1929 }
1930 ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block,
1931 &int_img_blocks, (char*)buf, 0);
1932 if (ret != 1) {
1933 /* error, it should never happen */
1934 return ISO_ASSERT_FAILURE;
1935 }
1936 return ISO_SUCCESS;
1937 }
1938
1939 /* If APM entries were submitted to iso_register_apm_entry(), then they
1940 get sprinkled over the system area after the system area template was
1941 loaded and before any other data get inserted.
1942 Note that if APM and MBR get combined, then the first 8 bytes of the MBR
1943 template must be replaceable by:
1944 {0x45, 0x52, 0x08 0x00, 0xeb, 0x02, 0xff, 0xff}
1945
1946 >>> ts B20526
1947 >>> This does not care for eventual image enlargements in last minute.
1948 >>> A sa_type, that does this, will have to adjust the last APM entry
1949 >>> if exactness matters.
1950 */
1951
1952 apm_flag = 0;
1953 if (sa_type == 0 && (t->system_area_options & 3) == 2) {
1954 do_isohybrid = 1;
1955
1956 /* >>> Coordinate with partprepend writer */
1957 /* <<< provisory trap */
1958 if (t->mbr_req_count > 0)
1959 return ISO_BOOT_MBR_OVERLAP;
1960
1961 /* If own APM is desired, set flag bit0 to prevent writing of Block0
1962 which would interfere with the own Block0 of isohybrid.
1963 */
1964 ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
1965 if (ret < 0)
1966 return ret;
1967 if (apm_count > 0)
1968 apm_flag |= 1;
1969 }
1970
1971 ret = iso_write_apm(t, img_blocks, buf, apm_flag);
1972 if (ret < 0) {
1973 iso_msg_submit(t->image->id, ret, 0,
1974 "Cannot set up Apple Partition Map");
1975 return ret;
1976 }
1977 ret = iso_write_mbr(t, img_blocks, buf);
1978 if (ret < 0) {
1979 iso_msg_submit(t->image->id, ret, 0,
1980 "Cannot set up MBR partition table");
1981 return ret;
1982 }
1983 if (t->mbr_req_count > 0) {
1984 if (sa_type != 0)
1985 return ISO_NON_MBR_SYS_AREA;
1986 risk_of_ee = 1;
1987 }
1988
1989 if (t->gpt_backup_outside)
1990 gpt_blocks = t->total_size / BLOCK_SIZE +
1991 (flag & 1) * t->opts->ms_block;
1992 else
1993 gpt_blocks = img_blocks;
1994 ret = iso_write_gpt(t, gpt_blocks, buf);
1995 if (ret < 0) {
1996 iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT");
1997 return ret;
1998 }
1999
2000 if (sa_type == 0 && (t->system_area_options & 1)) {
2001 if (t->mbr_req_count == 0){
2002 /* Write GRUB protective msdos label, i.e. a simple partition
2003 table */
2004 if (t->gpt_req_count > 0 && ! t->opts->part_like_isohybrid) {
2005 part_type = 0xee;
2006 pml_blocks = gpt_blocks;
2007 } else {
2008 part_type = 0xcd;
2009 if (t->opts->iso_mbr_part_type >= 0 &&
2010 t->opts->iso_mbr_part_type <= 255)
2011 part_type= t->opts->iso_mbr_part_type;
2012 pml_blocks = img_blocks;
2013 }
2014 ret = make_grub_msdos_label(pml_blocks, t->partition_secs_per_head,
2015 t->partition_heads_per_cyl,
2016 (uint8_t) part_type, buf, 0);
2017 if (ret != ISO_SUCCESS) /* error should never happen */
2018 return ISO_ASSERT_FAILURE;
2019 risk_of_ee = 1;
2020 } else if (t->gpt_req_count > 0) {
2021
2022 /* >>> ??? change first partition type to 0xee */;
2023
2024 }
2025 } else if (do_isohybrid) {
2026 /* Patch externally provided system area as isohybrid MBR */
2027 if (t->catalog == NULL || t->system_area_data == NULL) {
2028 /* isohybrid makes only sense together with ISOLINUX boot image
2029 and externally provided System Area.
2030 */
2031 return ISO_ISOLINUX_CANT_PATCH;
2032 }
2033
2034 if (gpt_count > 0 || apm_count > 0)
2035 part_type = 0x00;
2036 else {
2037 part_type = 0x17;
2038 if (t->opts->iso_mbr_part_type >= 0 &&
2039 t->opts->iso_mbr_part_type <= 255)
2040 part_type= t->opts->iso_mbr_part_type;
2041 }
2042
2043 if (t->opts->appended_as_gpt && t->have_appended_partitions) {
2044 part_type = 0xee;
2045 risk_of_ee = 1;
2046 img_blocks = gpt_blocks;
2047 no_boot_mbr = 2;
2048 }
2049
2050 /* >>> ??? Why is partition_offset 0 here ?
2051 It gets adjusted later by iso_offset_partition_start()
2052 Would it harm to give the real offset here ?
2053 */;
2054
2055 ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf,
2056 1 | no_boot_mbr);
2057 if (ret != 1)
2058 return ret;
2059 } else if (sa_type == 1) {
2060 ret = make_mips_volume_header(t, buf, 0);
2061 if (ret != ISO_SUCCESS)
2062 return ret;
2063 } else if (sa_type == 2) {
2064 ret = make_mipsel_boot_block(t, buf, 0);
2065 if (ret != ISO_SUCCESS)
2066 return ret;
2067 } else if (sa_type == 3) {
2068 ret = make_sun_disk_label(t, buf, 0);
2069 if (ret != ISO_SUCCESS)
2070 return ret;
2071 } else if (sa_type == 4 || sa_type == 5) {
2072 /* (By coincidence, sa_type and PALO header versions match) */
2073 ret = make_hppa_palo_sector(t, buf, sa_type, 0);
2074 if (ret != ISO_SUCCESS)
2075 return ret;
2076 } else if (sa_type == 6) {
2077 ret = make_dec_alpha_sector(t, buf, 0);
2078 if (ret != ISO_SUCCESS)
2079 return ret;
2080 } else if ((t->opts->partition_offset > 0 || will_append) &&
2081 sa_type == 0 && t->mbr_req_count == 0) {
2082 /* Write a simple partition table. */
2083 part_type = 0xcd;
2084 if (t->opts->iso_mbr_part_type >= 0 &&
2085 t->opts->iso_mbr_part_type <= 255)
2086 part_type= t->opts->iso_mbr_part_type;
2087 ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
2088 t->partition_heads_per_cyl,
2089 (uint8_t) part_type, buf, 2);
2090 if (ret != ISO_SUCCESS) /* error should never happen */
2091 return ISO_ASSERT_FAILURE;
2092 risk_of_ee = 1;
2093 if (t->opts->appended_as_gpt && t->have_appended_partitions) {
2094
2095 /* >>> ??? Do this in any case of t->gpt_req_count > ? */;
2096
2097 /* Re-write partition entry 1 : protective MBR for GPT */
2098 part_type = 0xee;
2099 risk_of_ee = 1;
2100 ret = write_mbr_partition_entry(1, part_type,
2101 (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1,
2102 t->partition_secs_per_head, t->partition_heads_per_cyl,
2103 buf, 2);
2104 if (ret < 0)
2105 return ret;
2106 } else if (t->opts->partition_offset == 0) {
2107 /* Re-write partition entry 1 : start at 0, type Linux */
2108 blk = ((uint64_t) img_blocks) * 4 - t->post_iso_part_pad / 512;
2109 part_type = 0x83;
2110 if (t->opts->iso_mbr_part_type >= 0 &&
2111 t->opts->iso_mbr_part_type <= 255)
2112 part_type= t->opts->iso_mbr_part_type;
2113 ret = write_mbr_partition_entry(1, part_type, (uint64_t) 0, blk,
2114 t->partition_secs_per_head, t->partition_heads_per_cyl,
2115 buf, 2);
2116 if (ret < 0)
2117 return ret;
2118 }
2119 }
2120
2121 /* Check for protective MBR in mbr_req and adjust to GPT size */
2122 if (t->gpt_req_count > 0 && sa_type == 0 && t->mbr_req_count == 1) {
2123 if (t->mbr_req[0]->type_byte == 0xee && buf[450] == 0xee &&
2124 t->mbr_req[0]->desired_slot <= 1) {
2125 part_type = 0xee;
2126 risk_of_ee = 1;
2127 ret = write_mbr_partition_entry(1, part_type,
2128 (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1,
2129 t->partition_secs_per_head, t->partition_heads_per_cyl,
2130 buf, 2);
2131 if (ret < 0)
2132 return ret;
2133 }
2134 }
2135
2136 if (t->opts->partition_offset > 0 && sa_type == 0 &&
2137 t->mbr_req_count == 0) {
2138 /* Adjust partition table to partition offset.
2139 With t->mbr_req_count > 0 this has already been done,
2140 */
2141
2142 #ifndef Libisofs_appended_partitions_inlinE
2143
2144 img_blocks = t->curblock; /* value might have been altered */
2145
2146 #else
2147
2148 /* A change of t->curblock does not matter in this case */
2149
2150 #endif
2151
2152 if (part_type == 0xee && t->gpt_req_count > 0) {
2153 mbrp1_blocks = t->total_size / BLOCK_SIZE +
2154 (flag & 1) * t->opts->ms_block;
2155 offset_flag |= 2 | 1; /* protective MBR, no other partitions */
2156 } else {
2157 mbrp1_blocks = img_blocks;
2158 }
2159 ret = iso_offset_partition_start(mbrp1_blocks, t->post_iso_part_pad,
2160 t->opts->partition_offset,
2161 t->partition_secs_per_head,
2162 t->partition_heads_per_cyl, buf,
2163 offset_flag);
2164 if (ret != ISO_SUCCESS) /* error should never happen */
2165 return ISO_ASSERT_FAILURE;
2166 }
2167
2168 /* This possibly overwrites the non-mbr_req partition table entries
2169 made so far. Overwriting those from t->mbr_req is not allowed.
2170 */
2171 if (sa_type == 3 ||
2172 !(t->opts->appended_as_gpt || t->opts->appended_as_apm)) {
2173 for (i = first_partition - 1; i <= last_partition - 1; i++) {
2174 if (t->opts->appended_partitions[i] == NULL)
2175 continue;
2176 if (i < t->mbr_req_count)
2177 return ISO_BOOT_MBR_COLLISION;
2178 if (sa_type == 3) {
2179 ret = write_sun_partition_entry(i + 1,
2180 t->opts->appended_partitions,
2181 t->appended_part_start, t->appended_part_size,
2182 ISO_SUN_CYL_SIZE,
2183 buf, t->opts->appended_partitions[i][0] == 0);
2184 } else {
2185 ret = write_mbr_partition_entry(i + 1,
2186 t->opts->appended_part_types[i],
2187 (uint64_t) t->appended_part_start[i],
2188 (uint64_t) t->appended_part_size[i],
2189 t->partition_secs_per_head, t->partition_heads_per_cyl,
2190 buf, 0);
2191 }
2192 if (ret < 0)
2193 return ret;
2194 }
2195 }
2196
2197 if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) {
2198 /* Patch MBR for GRUB2 */
2199 if (t->num_bootsrc <= 0)
2200 return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
2201 "No boot image found as jump target for GRUB2 MBR.");
2202 if (t->bootsrc[0] == NULL)
2203 return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
2204 "Cannot refer by GRUB2 MBR to data outside of ISO 9660 filesystem.");
2205 blk = t->bootsrc[0]->sections[0].block * 4 +
2206 Libisofs_grub2_mbr_patch_offsT;
2207 wpt = buf + Libisofs_grub2_mbr_patch_poS;
2208 for (i = 0; i < 8; i++)
2209 wpt[i] = blk >> (i * 8);
2210 }
2211
2212 /* Prevent partition type 0xee if no GPT emerged */
2213
2214 /* >>> ??? check for GPT magic number at byte 512 ff. ? */;
2215
2216 if (sa_type == 0 && ((t->system_area_options & 3) || risk_of_ee) &&
2217 (t->opts->part_like_isohybrid || t->gpt_req_count == 0) &&
2218 t->opts->iso_mbr_part_type != 0xee) {
2219 for (i = 0; i < 4; i++) {
2220 if (buf[446 + 16 * i + 4] == 0xee) {
2221 iso_msgs_submit(0,
2222 "Prevented partition type 0xEE in MBR without GPT",
2223 0, "WARNING", 0);
2224 part_type = 0xcd;
2225 if (t->opts->iso_mbr_part_type >= 0 &&
2226 t->opts->iso_mbr_part_type <= 255)
2227 part_type= t->opts->iso_mbr_part_type;
2228 buf[446 + 16 * i + 4] = (uint8_t) part_type;
2229 }
2230 }
2231 }
2232
2233 if (sa_type == 0 && (
2234 (t->system_area_options & 3) ||
2235 (t->system_area_options & (1 << 14)) ||
2236 (((t->system_area_options >> 10) & 15) != 1 &&
2237 (t->system_area_options & (1 << 15)))
2238 )) {
2239 /* This is an MBR which shall have a bootable/active flag
2240 protective-msdos-label, isohybrid, grub2-mbr, mbr-force-bootable
2241 */
2242 for (i = 0; i < 4; i++)
2243 if (buf[446 + 16 * i] & 0x80)
2244 break;
2245 if (i >= 4) { /* no bootable/active flag set yet */
2246 for (i = 0; i < 4; i++) {
2247 if ((!mbr_part_slot_is_unused(buf + 446 + 16 * i)) &&
2248 buf[446 + 16 * i + 4] != 0xee &&
2249 buf[446 + 16 * i + 4] != 0xef) {
2250 buf[446 + 16 * i] |= 0x80;
2251 break;
2252 }
2253 }
2254 if (i >= 4) { /* still no bootable/active flag set */
2255 if (t->system_area_options & (1 << 15)) /* Force it */
2256 iso_dummy_mbr_partition(buf, 0);
2257 }
2258 }
2259 }
2260
2261 if ((((t->system_area_options >> 2) & 0x3f) == 0 &&
2262 (t->system_area_options & 3) == 1) ||
2263 t->opts->partition_offset > 0) {
2264 /* Protective MBR || partition offset
2265 ISO will not be a partition or add-on session.
2266 It can span the whole image.
2267 */
2268 t->pvd_size_is_total_size = 1;
2269 }
2270
2271 return ISO_SUCCESS;
2272 }
2273
2274 /* Choose *heads_per_cyl so that
2275 - *heads_per_cyl * secs_per_head * 1024 >= imgsize / 512
2276 - *heads_per_cyl * secs_per_head is divisible by 4
2277 - it is as small as possible (to reduce alignment overhead)
2278 - it is <= 255
2279 @return 1= success , 0= cannot achieve goals
2280 */
2281 static
try_sph(off_t imgsize,int secs_per_head,int * heads_per_cyl,int flag)2282 int try_sph(off_t imgsize, int secs_per_head, int *heads_per_cyl, int flag)
2283 {
2284 off_t hd_blocks, hpc;
2285
2286 hd_blocks= imgsize / 512;
2287 hpc = hd_blocks / secs_per_head / 1024;
2288 if (hpc * secs_per_head * 1024 < hd_blocks)
2289 hpc++;
2290 if ((secs_per_head % 4) == 0) {
2291 ;
2292 } else if ((secs_per_head % 2) == 0) {
2293 hpc += (hpc % 2);
2294 } else if(hpc % 4) {
2295 hpc += 4 - (hpc % 4);
2296 }
2297 if (hpc > 255)
2298 return 0;
2299 *heads_per_cyl = hpc;
2300 return 1;
2301 }
2302
iso_align_isohybrid(Ecma119Image * t,int flag)2303 int iso_align_isohybrid(Ecma119Image *t, int flag)
2304 {
2305 int sa_type, ret, always_align;
2306 uint32_t img_blocks;
2307 off_t imgsize, cylsize = 0, frac;
2308 char *msg = NULL;
2309
2310 #ifdef Libisofs_part_align_writeR
2311 int fap, lap, app_part_count;
2312 #endif
2313
2314 LIBISO_ALLOC_MEM(msg, char, 160);
2315 sa_type = (t->system_area_options >> 2) & 0x3f;
2316 if (sa_type != 0)
2317 {ret = ISO_SUCCESS; goto ex;}
2318 always_align = (t->system_area_options >> 8) & 3;
2319
2320 if (!t->gpt_backup_outside) {
2321 /* Take into account the backup GPT */;
2322 ret = precompute_gpt(t);
2323 if (ret < 0)
2324 goto ex;
2325 }
2326
2327 #ifdef Libisofs_part_align_writeR
2328
2329 /* If partitions get appended then t->opts->tail_blocks and
2330 t->gpt_backup_size come after the alignment padding.
2331 */
2332 app_part_count = iso_count_appended_partitions(t, &fap, &lap);
2333 img_blocks = t->curblock;
2334 if (app_part_count == 0)
2335 img_blocks += t->opts->tail_blocks + t->gpt_backup_size;
2336
2337 #else
2338
2339 img_blocks = t->curblock + t->opts->tail_blocks + t->gpt_backup_size;
2340
2341 #endif
2342
2343 imgsize = ((off_t) img_blocks) * (off_t) 2048;
2344 if ((!(t->opts->appended_as_gpt && t->have_appended_partitions))
2345 && ((t->system_area_options & 3) || always_align)
2346 && (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head
2347 * 1024) * (off_t) 512 < imgsize) {
2348 /* Choose small values which can represent the image size */
2349 /* First try 32 sectors per head */
2350 ret = try_sph(imgsize, 32, &(t->partition_heads_per_cyl), 0);
2351 if (ret == 1) {
2352 t->partition_secs_per_head = 32;
2353 } else {
2354 /* Did not work with 32. Try 63 */
2355 t->partition_secs_per_head = 63;
2356 ret = try_sph(imgsize, 63, &(t->partition_heads_per_cyl), 0);
2357 if (ret != 1)
2358 t->partition_heads_per_cyl = 255;
2359 }
2360 cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head *512;
2361 frac = imgsize % cylsize;
2362 sprintf(msg, "Automatically adjusted MBR geometry to %d/%d/%d",
2363 (int) (imgsize / cylsize + !!frac),
2364 t->partition_heads_per_cyl, t->partition_secs_per_head);
2365 iso_msgs_submit(0, msg, 0, "NOTE", 0);
2366 }
2367
2368 if (always_align == 2)
2369 {ret = ISO_SUCCESS; goto ex;}
2370
2371 cylsize = 0;
2372 if (t->catalog != NULL &&
2373 (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
2374 /* Check for isolinux image with magic number of 3.72 and produce
2375 an MBR from our built-in template. (Deprecated since 31 Mar 2010)
2376 */
2377 if (img_blocks >= 0x40000000)
2378 {ret = ISO_SUCCESS; goto ex;}
2379 cylsize = 64 * 32 * 512;
2380
2381 } else if (t->system_area_options & 2) {
2382 /* Patch externally provided system area as isohybrid MBR */
2383 if (t->catalog == NULL || t->system_area_data == NULL) {
2384 /* isohybrid makes only sense together with ISOLINUX boot image
2385 and externally provided System Area.
2386 */
2387 {ret = ISO_ISOLINUX_CANT_PATCH; goto ex;}
2388 }
2389 cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
2390 * 512;
2391 } else if (always_align) {
2392 cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
2393 * 512;
2394 }
2395 if (cylsize == 0)
2396 {ret = ISO_SUCCESS; goto ex;}
2397 if (((double) imgsize) / (double) cylsize > 1024.0) {
2398 iso_msgs_submit(0,
2399 "Image size exceeds 1024 cylinders. Cannot align partition.",
2400 0, "WARNING", 0);
2401 iso_msgs_submit(0,
2402 "There are said to be BIOSes which will not boot this via MBR.",
2403 0, "WARNING", 0);
2404 {ret = ISO_SUCCESS; goto ex;}
2405 }
2406
2407 frac = imgsize % cylsize;
2408 imgsize += (frac > 0 ? cylsize - frac : 0);
2409
2410 frac = imgsize - ((off_t) img_blocks) * (off_t) 2048;
2411 if (frac == 0)
2412 {ret = ISO_SUCCESS; goto ex;}
2413 t->post_iso_part_pad = 0;
2414 if (frac % 2048) {
2415 t->post_iso_part_pad = 2048 - frac % 2048;
2416 sprintf(msg,
2417 "Cylinder aligned image size is not divisible by 2048. Have to add %d bytes.",
2418 t->post_iso_part_pad);
2419 iso_msgs_submit(0, msg, 0, "WARNING", 0);
2420 }
2421
2422 #ifdef Libisofs_part_align_writeR
2423
2424 t->part_align_blocks = (frac + 2047) / 2048;
2425
2426 #else
2427
2428 t->opts->tail_blocks += (frac + 2047) / 2048;
2429
2430 #endif /* ! Libisofs_part_align_writeR */
2431
2432 ret = ISO_SUCCESS;
2433 ex:;
2434 LIBISO_FREE_MEM(msg);
2435 return ret;
2436 }
2437
2438
iso_register_apm_entry(struct iso_apm_partition_request ** req_array,int * apm_req_count,struct iso_apm_partition_request * req,int flag)2439 int iso_register_apm_entry(struct iso_apm_partition_request **req_array,
2440 int *apm_req_count,
2441 struct iso_apm_partition_request *req, int flag)
2442 {
2443 struct iso_apm_partition_request *entry;
2444
2445 if (*apm_req_count >= ISO_APM_ENTRIES_MAX)
2446 return ISO_BOOT_TOO_MANY_APM;
2447 entry = calloc(1, sizeof(struct iso_apm_partition_request));
2448 if (entry == NULL)
2449 return ISO_OUT_OF_MEM;
2450
2451 memcpy(entry, req, sizeof(struct iso_apm_partition_request));
2452 req_array[*apm_req_count] = entry;
2453 (*apm_req_count)++;
2454 return ISO_SUCCESS;
2455 }
2456
2457
iso_register_mbr_entry(struct iso_mbr_partition_request ** req_array,int * mbr_req_count,struct iso_mbr_partition_request * req,int flag)2458 int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array,
2459 int *mbr_req_count,
2460 struct iso_mbr_partition_request *req, int flag)
2461 {
2462 struct iso_mbr_partition_request *entry;
2463
2464 if (*mbr_req_count >= ISO_MBR_ENTRIES_MAX)
2465 return ISO_BOOT_TOO_MANY_MBR;
2466 entry = calloc(1, sizeof(struct iso_mbr_partition_request));
2467 if (entry == NULL)
2468 return ISO_OUT_OF_MEM;
2469
2470 memcpy(entry, req, sizeof(struct iso_mbr_partition_request));
2471 req_array[*mbr_req_count] = entry;
2472 (*mbr_req_count)++;
2473 return ISO_SUCCESS;
2474 }
2475
iso_register_gpt_entry(struct iso_gpt_partition_request ** req_array,int * gpt_req_count,struct iso_gpt_partition_request * req,int flag)2476 int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array,
2477 int *gpt_req_count,
2478 struct iso_gpt_partition_request *req, int flag)
2479 {
2480 struct iso_gpt_partition_request *entry;
2481
2482 if (*gpt_req_count >= ISO_GPT_ENTRIES_MAX)
2483 return ISO_BOOT_TOO_MANY_GPT;
2484 entry = calloc(1, sizeof(struct iso_gpt_partition_request));
2485 if (entry == NULL)
2486 return ISO_OUT_OF_MEM;
2487
2488 memcpy(entry, req, sizeof(struct iso_gpt_partition_request));
2489 req_array[*gpt_req_count] = entry;
2490 (*gpt_req_count)++;
2491 return ISO_SUCCESS;
2492 }
2493
2494 #ifdef Libisofs_with_uuid_generatE
2495
swap_uuid(void * u_pt)2496 static void swap_uuid(void *u_pt)
2497 {
2498 uint8_t tr, *u;
2499
2500 u = (uint8_t *) u_pt;
2501 tr = u[0]; u[0] = u[3]; u[3] = tr;
2502 tr = u[1]; u[1] = u[2]; u[2] = tr;
2503 tr = u[4]; u[4] = u[5]; u[5] = tr;
2504 tr = u[6]; u[6] = u[7]; u[7] = tr;
2505 }
2506
2507 #endif /* Libisofs_with_uuid_generatE */
2508
2509
2510 /* CRC-32 as of GPT and Ethernet.
2511 Parameters are deduced from a table driven implementation in isohybrid.c
2512 */
iso_crc32_gpt(unsigned char * data,int count,int flag)2513 uint32_t iso_crc32_gpt(unsigned char *data, int count, int flag)
2514 {
2515 unsigned int acc, top, result = 0;
2516 long int i;
2517
2518 /* Chosen so that the CRC of 0 bytes of input is 0x00000000 */
2519 acc = 0x46af6449;
2520
2521 /* Process data bits and flush numerator by 32 zero bits */
2522 for (i = 0; i < count * 8 + 32; i++) {
2523 top = acc & 0x80000000;
2524 acc = (acc << 1);
2525 if (i < count * 8)
2526 /* The least significant bits of input bytes get processed first */
2527 acc |= ((data[i / 8] >> (i % 8)) & 1);
2528 if (top)
2529 /* Division by the generating polynomial */
2530 acc ^= 0x04c11db7;
2531 }
2532 /* Mirror residue bits */
2533 for (i = 0; i < 32; i++)
2534 if (acc & (1 << i))
2535 result |= 1 << (31 - i);
2536 /* Return bit complement */
2537 return result ^ 0xffffffff;
2538 }
2539
iso_mark_guid_version_4(uint8_t * u)2540 void iso_mark_guid_version_4(uint8_t *u)
2541 {
2542 /* Mark as UUID version 4. RFC 4122 says u[6], but UEFI prescribes
2543 bytes 6 and 7 to be swapped.
2544 */
2545 u[7] = (u[7] & 0x0f) | 0x40;
2546
2547 /* Variant is "1 0 x" as described in RFC 4122.
2548 */
2549 u[8] = (u[8] & 0x3f) | 0x80;
2550
2551 return;
2552 }
2553
iso_generate_gpt_guid(uint8_t guid[16])2554 void iso_generate_gpt_guid(uint8_t guid[16])
2555 {
2556
2557 #ifdef Libisofs_with_uuid_generatE
2558
2559 uuid_t u;
2560
2561 uuid_generate(u);
2562 swap_uuid((void *) u);
2563 memcpy(guid, u, 16);
2564
2565 #else
2566
2567 uint8_t *u;
2568 /* produced by uuid_generate() and byte-swapped to UEFI specs */
2569 static uint8_t uuid_template[16] = {
2570 0xee, 0x29, 0x9d, 0xfc, 0x65, 0xcc, 0x7c, 0x40,
2571 0x92, 0x61, 0x5b, 0xcd, 0x6f, 0xed, 0x08, 0x34
2572 };
2573 uint32_t rnd, salt;
2574 struct timeval tv;
2575 pid_t pid;
2576 int i, ret, fd;
2577
2578 u = guid;
2579
2580 /* First try /dev/urandom
2581 */
2582 fd = open("/dev/urandom", O_RDONLY | O_BINARY);
2583 if (fd == -1)
2584 goto fallback;
2585 ret = read(fd, u, 16);
2586 if (ret != 16) {
2587 close(fd);
2588 goto fallback;
2589 }
2590 close(fd);
2591 iso_mark_guid_version_4(u);
2592 return;
2593
2594
2595 fallback:;
2596 pid = getpid();
2597 salt = iso_crc32_gpt((unsigned char *) &guid, sizeof(uint8_t *), 0) ^ pid;
2598
2599 /* This relies on the uniqueness of the template and the rareness of
2600 bootable ISO image production via libisofs. Estimated 48 bits of
2601 entropy should influence the production of a single day.
2602 So first collisions are to be expected with about 16 million images
2603 per day.
2604 */
2605 memcpy(u, uuid_template, 16);
2606 gettimeofday(&tv, NULL);
2607 for (i = 0; i < 4; i++)
2608 u[i] = (salt >> (8 * i)) & 0xff;
2609 for (i = 0; i < 2; i++)
2610 u[4 + i] = (pid >> (8 * i)) & 0xff;
2611 u[6] = ((salt >> 8) ^ (pid >> 16)) & 0xff;
2612 rnd = ((0xffffff & tv.tv_sec) << 8) |
2613 (((tv.tv_usec >> 16) ^ (salt & 0xf0)) & 0xff);
2614 for (i = 0; i < 4; i++)
2615 u[10 + i] ^= (rnd >> (8 * i)) & 0xff;
2616 u[14] ^= (tv.tv_usec >> 8) & 0xff;
2617 u[15] ^= tv.tv_usec & 0xff;
2618
2619 iso_mark_guid_version_4(u);
2620 return;
2621
2622 #endif /* ! Libisofs_with_uuid_generatE */
2623
2624 }
2625
iso_gpt_uuid(Ecma119Image * t,uint8_t uuid[16])2626 void iso_gpt_uuid(Ecma119Image *t, uint8_t uuid[16])
2627 {
2628 if (t->gpt_uuid_counter == 0)
2629 iso_generate_gpt_guid(t->gpt_uuid_base);
2630
2631 memcpy(uuid, t->gpt_uuid_base, 16);
2632
2633 /* Previous implementation changed only byte 9. So i expand it by applying
2634 the counter in little-endian style.
2635 */
2636 uuid[9] ^= t->gpt_uuid_counter & 0xff;
2637 uuid[10] ^= (t->gpt_uuid_counter >> 8) & 0xff;
2638 uuid[11] ^= (t->gpt_uuid_counter >> 16) & 0xff;
2639 uuid[12] ^= (t->gpt_uuid_counter >> 24) & 0xff;
2640 t->gpt_uuid_counter++;
2641 return;
2642 }
2643
assess_appended_gpt(Ecma119Image * t,int flag)2644 int assess_appended_gpt(Ecma119Image *t, int flag)
2645 {
2646 static uint8_t basic_data_uuid[16] = {
2647 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
2648 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
2649 };
2650 static uint8_t efi_sys_uuid[16] = {
2651 0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
2652 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
2653 };
2654 static uint8_t hfs_plus_uuid[16] = {
2655 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
2656 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
2657 };
2658 static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2659 int i, ret, do_apm = 0, do_gpt = 0, index, already_in_gpt = 0;
2660 uint8_t gpt_name[72], *type_uuid;
2661 char apm_type[33];
2662
2663 #ifndef Libisofs_appended_partitions_inlinE
2664 if (!t->gpt_backup_outside)
2665 return 2;
2666 #endif
2667
2668 if ((t->apm_req_count > 0 && t->opts->part_like_isohybrid) ||
2669 (t->have_appended_partitions && t->opts->appended_as_apm))
2670 do_apm = 1;
2671 if (t->gpt_req_count > 0 ||
2672 (t->have_appended_partitions && t->opts->appended_as_gpt))
2673 do_gpt = 1;
2674
2675 if (do_apm == 0 && do_gpt == 0)
2676 return 2;
2677
2678 /* Represent appended partitions */
2679 for (i = 0; i <= 3; i++) {
2680 if (t->opts->appended_partitions[i] == NULL)
2681 continue;
2682 if (do_apm) {
2683 memset(gpt_name, 0, 32);
2684 sprintf((char *) gpt_name, "Appended%d", i + 1);
2685 strcpy(apm_type, "Data");
2686 if (t->opts->appended_part_gpt_flags[i] & 1) {
2687 if (memcmp(t->opts->appended_part_type_guids[i], hfs_plus_uuid,
2688 16) == 0)
2689 strcpy(apm_type, "Apple_HFS");
2690 }
2691 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
2692 t->appended_part_start[i] * t->hfsp_iso_block_fac,
2693 t->appended_part_size[i] * t->hfsp_iso_block_fac,
2694 (char *) gpt_name, apm_type);
2695 if (ret < 0)
2696 return ret;
2697 }
2698 if (do_gpt)
2699 already_in_gpt = iso_find_gpt_entry(t->gpt_req, t->gpt_req_count,
2700 ((uint64_t) t->appended_part_start[i]) * 4,
2701 ((uint64_t) t->appended_part_size[i]) * 4,
2702 &index, 0);
2703 if (do_gpt && !already_in_gpt) {
2704 memset(gpt_name, 0, 72);
2705 sprintf((char *) gpt_name, "Appended%d", i + 1);
2706 iso_ascii_utf_16le(gpt_name);
2707 if (t->opts->appended_part_gpt_flags[i] & 1)
2708 type_uuid = t->opts->appended_part_type_guids[i];
2709 else if (t->opts->appended_part_types[i] == 0xef)
2710 type_uuid = efi_sys_uuid;
2711 else
2712 type_uuid = basic_data_uuid;
2713 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2714 ((uint64_t) t->appended_part_start[i]) * 4,
2715 ((uint64_t) t->appended_part_size[i]) * 4,
2716 type_uuid, zero_uuid,
2717 (uint64_t) 0, gpt_name);
2718 if (ret < 0)
2719 return ret;
2720 }
2721 }
2722 return ISO_SUCCESS;
2723 }
2724
2725 /* Probably already called by tail_writer_compute_data_blocks via
2726 iso_align_isohybrid
2727 */
precompute_gpt(Ecma119Image * t)2728 static int precompute_gpt(Ecma119Image *t)
2729 {
2730 uint32_t gpt_part_start;
2731 int ret, sa_type;
2732 int gpt_count, gpt_idx[128], apm_count;
2733
2734 /* Avoid repetition by gpt_tail_writer_compute_data_blocks */
2735 t->gpt_is_computed = 1;
2736
2737
2738 /* Assess APM and GPT requests of isohybrid */
2739 sa_type = (t->system_area_options >> 2) & 0x3f;
2740 if (sa_type == 0 && (t->system_area_options & 3) == 2) {
2741
2742 /* >>> ISOHYBRID :
2743 Shall isohybrid be combinable with other APM and GPT requesters ?
2744 */;
2745 /* <<< provisorily: Not compatible */
2746 ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
2747 if (ret < 0)
2748 return ret;
2749 if (t->gpt_req_count > 0 && gpt_count > 0)
2750 return ISO_BOOT_GPT_OVERLAP;
2751 if (t->apm_req_count > 0 && apm_count > 0)
2752 return ISO_BOOT_APM_OVERLAP;
2753 /* Register the GPT and APM partition entries */
2754 ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 1);
2755 if (ret < 0)
2756 return ret;
2757 }
2758
2759 /* With part_like_isohybrid:
2760 If no GPT is registered yet, and MBR, but neither CHRP nor ISOLINUX
2761 isohybrid is desired, then try to apply the isohybrid GPT and APM flags
2762 nevertheless. Avoid an overall ISO image GPT partition.
2763 */
2764 if (t->opts->part_like_isohybrid && t->gpt_req_count <= 0 &&
2765 ((t->system_area_options >> 2) & 0x3f) == 0 &&
2766 ((t->system_area_options >> 10) & 0xf) != 1 &&
2767 (!(t->system_area_options & 2))) {
2768
2769 ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count,
2770 1 | ((t->apm_req_count > 0) << 1) | 4);
2771 if (ret <= 0)
2772 return ret;
2773 t->apm_req_flags |= 2; /* Do not fill APM gaps,
2774 do not adjust final APM partition size */
2775 }
2776
2777 /* Assess impact of appended partitions on GPT */
2778 ret = assess_appended_gpt(t, 0);
2779 if (ret < 0)
2780 return ret;
2781
2782 /* Rectify APM requests early in order to learn the size of GPT.
2783 iso_write_apm() relies on this being already done here.
2784 So perform even if no GPT is required.
2785 */
2786 ret = rectify_apm(t);
2787 if (ret < 0)
2788 return ret;
2789
2790 #ifdef NIX
2791 /* Disabled */
2792
2793 /* <<< ts B20526 : Dummy mock-up */
2794 if (t->gpt_req_count <= 0) {
2795
2796 /* <<< ??? Move to system_area.h and publish as macro ?
2797 Or to make_isohybrid_mbr.c ?
2798 */
2799 static uint8_t hfs_uuid[16] = {
2800 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
2801 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
2802 };
2803 static uint8_t basic_data_uuid[16] = {
2804 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
2805 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
2806 };
2807
2808 uint8_t gpt_name[72];
2809 static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2810 static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
2811
2812 memset(gpt_name, 0, 72);
2813 gpt_name[0] = 'T'; gpt_name[2] = '1';
2814 strcpy((char *) gpt_name, "GPT Test 1");
2815 iso_ascii_utf_16le(gpt_name);
2816 /*
2817 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2818 (uint64_t) (16 * 4), (uint64_t) (20 * 4),
2819 hfs_uuid, zero_uuid, gpt_flags, gpt_name);
2820 / * Caution: Size 90 causes intentional partition overlap error * /
2821 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2822 (uint64_t) (30 * 4), (uint64_t) (90 * 4),
2823 hfs_uuid, zero_uuid,
2824 gpt_flags, gpt_name);
2825 */
2826 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2827 (uint64_t) (30 * 4), (uint64_t) (40 * 4),
2828 hfs_uuid, zero_uuid,
2829 gpt_flags, gpt_name);
2830 if (ret < 0)
2831 return ret;
2832 strcpy((char *) gpt_name, "GPT Test 2");
2833 iso_ascii_utf_16le(gpt_name);
2834 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2835 (uint64_t) (110 * 4), (uint64_t) (60 * 4),
2836 basic_data_uuid, zero_uuid,
2837 gpt_flags, gpt_name);
2838 if (ret < 0)
2839 return ret;
2840 }
2841 #endif /* NIX */
2842
2843 /* Is a GPT requested ? */
2844 t->gpt_backup_end = 0;
2845 t->gpt_max_entries = 0;
2846 if (t->gpt_req_count == 0)
2847 return ISO_SUCCESS;
2848
2849 /* Determine GPT partition start in System Area, */
2850 gpt_part_start = 0;
2851 if (t->apm_req_count > 0) {
2852 if (t->opts->apm_block_size == 0)
2853 t->opts->apm_block_size = 2048;
2854 gpt_part_start = (t->apm_req_count + 1) *
2855 (t->opts->apm_block_size / 512);
2856 }
2857 if (gpt_part_start < 2)
2858 gpt_part_start = 2;
2859 else if (gpt_part_start >= 64)
2860 return ISO_BOOT_TOO_MANY_GPT;
2861 t->gpt_part_start = gpt_part_start;
2862
2863 /* Necessary number of 2K blocks */
2864 t->gpt_max_entries = (64 - t->gpt_part_start) * 4;
2865 t->gpt_backup_size = ((t->gpt_max_entries / 4 + 1) * 512 + 2047) / 2048;
2866
2867 return ISO_SUCCESS;
2868 }
2869
2870
gpt_tail_writer_compute_data_blocks(IsoImageWriter * writer)2871 int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer)
2872 {
2873 Ecma119Image *t;
2874 int ret;
2875
2876 if (writer == NULL)
2877 return ISO_ASSERT_FAILURE;
2878 t = writer->target;
2879
2880 if (! t->gpt_is_computed) {
2881 ret = precompute_gpt(t);
2882 if (ret < 0)
2883 return ret;
2884 }
2885
2886 if (t->gpt_backup_outside) {
2887 t->total_size += t->gpt_backup_size * 2048;
2888 /* The ISO block number after the backup GPT header */
2889 t->gpt_backup_end = t->total_size / BLOCK_SIZE + t->opts->ms_block;
2890 } else {
2891 t->curblock += t->gpt_backup_size;
2892 /* The ISO block number after the backup GPT header */
2893 t->gpt_backup_end = t->curblock;
2894 }
2895
2896 return ISO_SUCCESS;
2897 }
2898
2899
gpt_tail_writer_write_vol_desc(IsoImageWriter * writer)2900 int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer)
2901 {
2902 return ISO_SUCCESS;
2903 }
2904
2905
gpt_tail_writer_write_data(IsoImageWriter * writer)2906 static int gpt_tail_writer_write_data(IsoImageWriter *writer)
2907 {
2908 Ecma119Image *t;
2909 uint8_t *head, *new_head, *entries;
2910 uint8_t *backup_buf = NULL;
2911 uint32_t crc, i;
2912 uint64_t part_start;
2913 int ret;
2914
2915 t = writer->target;
2916 if (t->gpt_backup_end == 0 || t->gpt_max_entries == 0)
2917 return ISO_SUCCESS; /* No backup GPT area reserved by compute_data() */
2918
2919 backup_buf = calloc(1, t->gpt_backup_size * 2048);
2920 if (backup_buf == NULL)
2921 return ISO_OUT_OF_MEM;
2922 memset(backup_buf, 0, t->gpt_backup_size * 2048);
2923
2924 /* Check whether GPT header block came through */
2925 head = t->sys_area_as_written + 512;
2926 if (strncmp((char *) head, "EFI PART", 8) != 0) {
2927 tampered_head:;
2928 /* Send error message but do not prevent further image production */
2929 iso_msgs_submit(0,
2930 "GPT header block was altered before writing to System Area.",
2931 0, "FAILURE", 0);
2932 goto write_zeros;
2933 }
2934 for (i = 92; i < 512; i++)
2935 if (head[i])
2936 goto tampered_head;
2937
2938 /* Patch memorized header block */
2939 new_head = backup_buf + t->gpt_backup_size * 2048 - 512;
2940 memcpy(new_head, head, 512);
2941 /* Exchange "Location of this header" and "Location of header backup" */
2942 memcpy(new_head + 24, head + 32, 8);
2943 memcpy(new_head + 32, head + 24, 8);
2944 /* Point to the backup partition entries */
2945 part_start = ((uint64_t) t->gpt_backup_end) * 4
2946 - 1 - t->gpt_max_entries / 4;
2947 iso_lsb(new_head + 72, part_start & 0xffffffff, 4);
2948 iso_lsb(new_head + 76, (part_start >> 32) & 0xffffffff, 4);
2949
2950 /* Compute new header CRC */
2951 memset(new_head + 16, 0, 4);
2952 crc = iso_crc32_gpt((unsigned char *) new_head, 92, 0);
2953 iso_lsb(new_head + 16, crc, 4);
2954
2955 /* Copy GPT entries */
2956 entries = t->sys_area_as_written + t->gpt_part_start * 512;
2957 memcpy(new_head - t->gpt_max_entries * 128,
2958 entries, t->gpt_max_entries * 128);
2959
2960 ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
2961 free(backup_buf);
2962 if (ret < 0)
2963 return ret;
2964
2965 if (!t->gpt_backup_outside) {
2966
2967 /* >>> Why isn't t->curblock updated ? */;
2968
2969 }
2970 return ISO_SUCCESS;
2971
2972 write_zeros:;
2973 ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
2974 free(backup_buf);
2975 if (ret < 0)
2976 return ret;
2977 return ISO_SUCCESS;
2978 }
2979
2980
gpt_tail_writer_free_data(IsoImageWriter * writer)2981 static int gpt_tail_writer_free_data(IsoImageWriter *writer)
2982 {
2983 return ISO_SUCCESS;
2984 }
2985
2986
gpt_tail_writer_create(Ecma119Image * target)2987 int gpt_tail_writer_create(Ecma119Image *target)
2988 {
2989 IsoImageWriter *writer;
2990
2991 writer = calloc(1, sizeof(IsoImageWriter));
2992 if (writer == NULL) {
2993 return ISO_OUT_OF_MEM;
2994 }
2995 writer->compute_data_blocks = gpt_tail_writer_compute_data_blocks;
2996 writer->write_vol_desc = gpt_tail_writer_write_vol_desc;
2997 writer->write_data = gpt_tail_writer_write_data;
2998 writer->free_data = gpt_tail_writer_free_data;
2999 writer->data = NULL;
3000 writer->target = target;
3001
3002 /* add this writer to image */
3003 target->writers[target->nwriters++] = writer;
3004
3005 return ISO_SUCCESS;
3006 }
3007
3008
3009 /* ---------------------- Partition Prepend Writer --------------------- */
3010
3011
partprepend_writer_compute_data_blocks(IsoImageWriter * writer)3012 static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
3013 {
3014 Ecma119Image *t;
3015 IsoFileSrc *src;
3016 int ret, will_have_gpt = 0, with_chrp = 0, i, part_type, keep;
3017 static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3018 static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
3019 uint8_t gpt_name[72];
3020 uint64_t part_start;
3021 off_t start_byte, byte_count;
3022
3023 /* <<< ??? Move to system_area.h and publish as macro ? */
3024 static uint8_t efi_sys_uuid[16] = {
3025 0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
3026 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
3027 };
3028
3029 if (writer == NULL)
3030 return ISO_ASSERT_FAILURE;
3031 t = writer->target;
3032
3033 with_chrp = ((t->system_area_options & 0x3cff) == 0x0400);
3034 if (t->opts->efi_boot_partition != NULL ||
3035 t->gpt_req_count > 0) /* Might not catch all cases with GPT */
3036 will_have_gpt = 1;
3037
3038 if (t->opts->efi_boot_partition != NULL) {
3039 keep = 0;
3040 if (t->efi_boot_part_filesrc != NULL) {
3041 /* A file in the emerging ISO image shall store its content
3042 as prepended partition.
3043 Install absolute block addresses and determine partition size.
3044 */
3045 src = t->efi_boot_part_filesrc;
3046 t->efi_boot_part_size = 0;
3047 for (i = 0; i < src->nsections; i++) {
3048 src->sections[i].block = t->curblock + t->efi_boot_part_size;
3049 t->efi_boot_part_size += (src->sections[i].size + 2047) / 2048;
3050 }
3051 part_start = t->curblock * 4;
3052 } else {
3053 ret = compute_partition_size(t, t->opts->efi_boot_partition,
3054 &(t->efi_boot_part_size),
3055 t->opts->efi_boot_part_flag & 1);
3056 if (ret < 0)
3057 return ret;
3058 part_start = t->curblock * 4;
3059 if (ret == ISO_SUCCESS + 1) {
3060 /* Interval from imported_iso in add-on session will be kept */
3061 ret = iso_interval_reader_start_size(t,
3062 t->opts->efi_boot_partition,
3063 &start_byte, &byte_count, 0);
3064 if (ret < 0)
3065 return ret;
3066 part_start = start_byte / 512;
3067 keep = 1;
3068 }
3069 }
3070 memset(gpt_name, 0, 72);
3071 strcpy((char *) gpt_name, "EFI boot partition");
3072 iso_ascii_utf_16le(gpt_name);
3073 ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), part_start,
3074 ((uint64_t) t->efi_boot_part_size) * 4,
3075 efi_sys_uuid, zero_uuid, gpt_flags, gpt_name);
3076 if (ret < 0)
3077 return ret;
3078 if (!keep)
3079 t->curblock += t->efi_boot_part_size;
3080 }
3081
3082 if (with_chrp) {
3083 /* CHRP is not compatible with any other partition in MBR */
3084 if (t->opts->prep_partition != NULL || t->opts->fat || will_have_gpt ||
3085 t->mbr_req_count > 0)
3086 return ISO_BOOT_MBR_OVERLAP;
3087 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3088 (uint64_t) 0, (uint64_t) 0, 0x96, 0x80, 0);
3089 if (ret < 0)
3090 return ret;
3091 return ISO_SUCCESS;
3092 }
3093
3094 part_start = t->curblock * 4;
3095 keep = 0;
3096 if (t->opts->prep_partition != NULL) {
3097 ret = compute_partition_size(t, t->opts->prep_partition,
3098 &(t->prep_part_size),
3099 t->opts->prep_part_flag & 1);
3100 if (ret < 0)
3101 return ret;
3102 if (ret == ISO_SUCCESS + 1) {
3103 /* Interval from imported_iso in add-on session will be kept */
3104 ret = iso_interval_reader_start_size(t,
3105 t->opts->prep_partition,
3106 &start_byte, &byte_count, 0);
3107 if (ret < 0)
3108 return ret;
3109 part_start = start_byte / 512;
3110 keep = 1;
3111 }
3112 }
3113 if (t->prep_part_size > 0 || t->opts->fat || will_have_gpt) {
3114 /* Protecting MBR entry for ISO start or whole ISO */
3115 part_type = 0xcd;
3116 if (t->opts->iso_mbr_part_type >= 0 &&
3117 t->opts->iso_mbr_part_type <= 255)
3118 part_type= t->opts->iso_mbr_part_type;
3119 if (will_have_gpt)
3120 part_type = 0xee;
3121 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3122 will_have_gpt ? (uint64_t) 1 :
3123 ((uint64_t) t->opts->partition_offset) * 4,
3124 (uint64_t) 0, part_type, 0, 0);
3125 if (ret < 0)
3126 return ret;
3127 }
3128 if (t->prep_part_size > 0) {
3129 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), part_start,
3130 ((uint64_t) t->prep_part_size) * 4,
3131 0x41, 0, 0);
3132 if (ret < 0)
3133 return ret;
3134 if (!keep) {
3135 t->curblock += t->prep_part_size;
3136 part_start = t->curblock * 4;
3137 } else {
3138 part_start += t->prep_part_size * 4;
3139 }
3140 } else {
3141 part_start = t->curblock * 4;
3142 }
3143 if (t->prep_part_size > 0 || t->opts->fat) {
3144 /* FAT partition or protecting MBR entry for ISO end */
3145 ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3146 part_start, (uint64_t) 0,
3147 t->opts->fat ? 0x0c : 0xcd, 0, 0);
3148 if (ret < 0)
3149 return ret;
3150 }
3151
3152 return ISO_SUCCESS;
3153 }
3154
3155
partprepend_writer_write_vol_desc(IsoImageWriter * writer)3156 static int partprepend_writer_write_vol_desc(IsoImageWriter *writer)
3157 {
3158 return ISO_SUCCESS;
3159 }
3160
3161
partprepend_writer_write_data(IsoImageWriter * writer)3162 static int partprepend_writer_write_data(IsoImageWriter *writer)
3163 {
3164 Ecma119Image *t;
3165 int ret;
3166
3167 t = writer->target;
3168
3169 if (t->opts->efi_boot_partition != NULL && t->efi_boot_part_size) {
3170
3171 if (t->efi_boot_part_filesrc != NULL) {
3172 ret = iso_filesrc_write_data(t, t->efi_boot_part_filesrc,
3173 NULL, NULL, 0);
3174 } else {
3175 ret = iso_write_partition_file(t, t->opts->efi_boot_partition,
3176 (uint32_t) 0, t->efi_boot_part_size,
3177 t->opts->efi_boot_part_flag & 1);
3178 }
3179 if (ret < 0)
3180 return ret;
3181 }
3182 if (t->opts->prep_partition != NULL && t->prep_part_size) {
3183 ret = iso_write_partition_file(t, t->opts->prep_partition,
3184 (uint32_t) 0, t->prep_part_size,
3185 t->opts->prep_part_flag & 1);
3186 if (ret < 0)
3187 return ret;
3188 }
3189
3190 return ISO_SUCCESS;
3191 }
3192
3193
partprepend_writer_free_data(IsoImageWriter * writer)3194 static int partprepend_writer_free_data(IsoImageWriter *writer)
3195 {
3196 return ISO_SUCCESS;
3197 }
3198
3199
partprepend_writer_create(Ecma119Image * target)3200 int partprepend_writer_create(Ecma119Image *target)
3201 {
3202 IsoImageWriter *writer;
3203
3204 writer = calloc(1, sizeof(IsoImageWriter));
3205 if (writer == NULL) {
3206 return ISO_OUT_OF_MEM;
3207 }
3208
3209 writer->compute_data_blocks = partprepend_writer_compute_data_blocks;
3210 writer->write_vol_desc = partprepend_writer_write_vol_desc;
3211 writer->write_data = partprepend_writer_write_data;
3212 writer->free_data = partprepend_writer_free_data;
3213 writer->data = NULL;
3214 writer->target = target;
3215
3216 /* add this writer to image */
3217 target->writers[target->nwriters++] = writer;
3218
3219 return ISO_SUCCESS;
3220 }
3221
3222
3223 #ifdef Libisofs_appended_partitions_inlinE
3224
3225 /* ----------------- Inline Partition Append Writer ------------------ */
3226
3227
partappend_writer_compute_data_blocks(IsoImageWriter * writer)3228 static int partappend_writer_compute_data_blocks(IsoImageWriter *writer)
3229 {
3230 int ret;
3231
3232 ret = iso_compute_append_partitions(writer->target, 1);
3233 return ret;
3234 }
3235
3236
partappend_writer_write_vol_desc(IsoImageWriter * writer)3237 static int partappend_writer_write_vol_desc(IsoImageWriter *writer)
3238 {
3239 return ISO_SUCCESS;
3240 }
3241
3242
partappend_writer_write_data(IsoImageWriter * writer)3243 static int partappend_writer_write_data(IsoImageWriter *writer)
3244 {
3245 Ecma119Image *target;
3246 int res, first_partition = 1, last_partition = 0;
3247 int i;
3248
3249 target = writer->target;
3250
3251 /* Append partition data */
3252 iso_tell_max_part_range(target->opts,
3253 &first_partition, &last_partition, 0);
3254
3255 for (i = first_partition - 1; i <= last_partition - 1; i++) {
3256 if (target->opts->appended_partitions[i] == NULL)
3257 continue;
3258 if (target->opts->appended_partitions[i][0] == 0)
3259 continue;
3260 res = iso_write_partition_file(target,
3261 target->opts->appended_partitions[i],
3262 target->appended_part_prepad[i],
3263 target->appended_part_size[i],
3264 target->opts->appended_part_flags[i] & 1);
3265 if (res < 0)
3266 return res;
3267 target->curblock += target->appended_part_size[i];
3268 }
3269 return ISO_SUCCESS;
3270 }
3271
3272
partappend_writer_free_data(IsoImageWriter * writer)3273 static int partappend_writer_free_data(IsoImageWriter *writer)
3274 {
3275 return ISO_SUCCESS;
3276 }
3277
3278
partappend_writer_create(Ecma119Image * target)3279 int partappend_writer_create(Ecma119Image *target)
3280 {
3281 IsoImageWriter *writer;
3282
3283 writer = calloc(1, sizeof(IsoImageWriter));
3284 if (writer == NULL) {
3285 return ISO_OUT_OF_MEM;
3286 }
3287
3288 writer->compute_data_blocks = partappend_writer_compute_data_blocks;
3289 writer->write_vol_desc = partappend_writer_write_vol_desc;
3290 writer->write_data = partappend_writer_write_data;
3291 writer->free_data = partappend_writer_free_data;
3292 writer->data = NULL;
3293 writer->target = target;
3294
3295 /* add this writer to image */
3296 target->writers[target->nwriters++] = writer;
3297
3298 return ISO_SUCCESS;
3299 }
3300
3301 #endif /* Libisofs_appended_partitions_inlinE */
3302
3303
iso_delete_gpt_apm_fillers(Ecma119Image * target,int flag)3304 void iso_delete_gpt_apm_fillers(Ecma119Image *target, int flag)
3305 {
3306 int i, widx;
3307
3308 /* Dispose the requests with req_status bit0 */
3309 for (i = 0; i < target->gpt_req_count; i++) {
3310 if (target->gpt_req[i]->req_status & 1) {
3311 free(target->gpt_req[i]);
3312 target->gpt_req[i] = NULL;
3313 }
3314 }
3315 /* Densify the request arrays */
3316 widx = 0;
3317 for (i = 0; i < target->gpt_req_count; i++) {
3318 if (target->gpt_req[i] != NULL) {
3319 target->gpt_req[widx] = target->gpt_req[i];
3320 widx++;
3321 }
3322 }
3323 target->gpt_req_count = widx;
3324
3325 /* And again for APM */
3326 for (i = 0; i < target->apm_req_count; i++) {
3327 if (target->apm_req[i]->req_status & 1) {
3328 free(target->apm_req[i]);
3329 target->apm_req[i] = NULL;
3330 }
3331 }
3332 widx = 0;
3333 for (i = 0; i < target->apm_req_count; i++) {
3334 if (target->apm_req[i] != NULL) {
3335 target->apm_req[widx] = target->apm_req[i];
3336 widx++;
3337 }
3338 }
3339 target->apm_req_count = widx;
3340 }
3341
3342