1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2010 - 2016 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 "eltorito.h"
17 #include "fsource.h"
18 #include "filesrc.h"
19 #include "image.h"
20 #include "messages.h"
21 #include "writer.h"
22 #include "ecma119.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 /**
29 * This table should be written with the actual values at offset
30 * 8 of boot image, when used ISOLINUX boot loader
31 */
32 struct boot_info_table {
33 uint8_t bi_pvd BP(1, 4); /* LBA of primary volume descriptor */
34 uint8_t bi_file BP(5, 8); /* LBA of boot file */
35 uint8_t bi_length BP(9, 12); /* Length of boot file */
36 uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
37 uint8_t bi_reserved BP(17, 56); /* Reserved */
38 };
39
40 /**
41 * Structure for each one of the four entries in a partition table on a
42 * hard disk image.
43 */
44 struct partition_desc {
45 uint8_t boot_ind;
46 uint8_t begin_chs[3];
47 uint8_t type;
48 uint8_t end_chs[3];
49 uint8_t start[4];
50 uint8_t size[4];
51 };
52
53 /**
54 * Structures for a Master Boot Record of a hard disk image.
55 */
56 struct hard_disc_mbr {
57 uint8_t code_area[440];
58 uint8_t opt_disk_sg[4];
59 uint8_t pad[2];
60 struct partition_desc partition[4];
61 uint8_t sign1;
62 uint8_t sign2;
63 };
64
65 /* API */
el_torito_set_boot_platform_id(ElToritoBootImage * bootimg,uint8_t id)66 int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id)
67 {
68 bootimg->platform_id = id;
69 return 1;
70 }
71
72 /* API */
el_torito_get_boot_platform_id(ElToritoBootImage * bootimg)73 int el_torito_get_boot_platform_id(ElToritoBootImage *bootimg)
74 {
75 return bootimg->platform_id;
76 }
77
78 /**
79 * Sets the load segment for the initial boot image. This is only for
80 * no emulation boot images, and is a NOP for other image types.
81 */
el_torito_set_load_seg(ElToritoBootImage * bootimg,short segment)82 void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
83 {
84 if (bootimg->type != 0)
85 return;
86 if (segment < 0)
87 bootimg->load_seg = 0x1000 + segment;
88 else
89 bootimg->load_seg = segment;
90 }
91
92 /* API */
el_torito_get_load_seg(ElToritoBootImage * bootimg)93 int el_torito_get_load_seg(ElToritoBootImage *bootimg)
94 {
95 return (int) bootimg->load_seg;
96 }
97
98 /**
99 * Sets the number of sectors (512b) to be load at load segment during
100 * the initial boot procedure. This is only for no emulation boot images,
101 * and is a NOP for other image types.
102 */
el_torito_set_load_size(ElToritoBootImage * bootimg,short sectors)103 void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
104 {
105 if (bootimg->type != 0)
106 return;
107 if (sectors < 0)
108 bootimg->load_size = 0x10000 + sectors;
109 else
110 bootimg->load_size = sectors;
111 }
112
113 /* API */
el_torito_get_load_size(ElToritoBootImage * bootimg)114 int el_torito_get_load_size(ElToritoBootImage *bootimg)
115 {
116 return (int) bootimg->load_size;
117 }
118
119 /* API */
el_torito_set_full_load(ElToritoBootImage * bootimg,int mode)120 void el_torito_set_full_load(ElToritoBootImage *bootimg, int mode)
121 {
122 if (bootimg->type != 0)
123 return;
124 bootimg->load_size_full= !!mode;
125 }
126
127 /* API */
el_torito_get_full_load(ElToritoBootImage * bootimg)128 int el_torito_get_full_load(ElToritoBootImage *bootimg)
129 {
130 return bootimg->load_size_full;
131 }
132
133
134 /**
135 * Marks the specified boot image as not bootable
136 */
el_torito_set_no_bootable(ElToritoBootImage * bootimg)137 void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
138 {
139 bootimg->bootable = 0;
140 }
141
142 /* API */
el_torito_get_bootable(ElToritoBootImage * bootimg)143 int el_torito_get_bootable(ElToritoBootImage *bootimg)
144 {
145 return !!bootimg->bootable;
146 }
147
148 /* API */
el_torito_set_id_string(ElToritoBootImage * bootimg,uint8_t id_string[28])149 int el_torito_set_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
150 {
151 memcpy(bootimg->id_string, id_string, 28);
152 return 1;
153 }
154
155 /* API */
el_torito_get_id_string(ElToritoBootImage * bootimg,uint8_t id_string[28])156 int el_torito_get_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
157 {
158
159 memcpy(id_string, bootimg->id_string, 28);
160 return 1;
161 }
162
163 /* API */
el_torito_set_selection_crit(ElToritoBootImage * bootimg,uint8_t crit[20])164 int el_torito_set_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
165 {
166 memcpy(bootimg->selection_crit, crit, 20);
167 return 1;
168 }
169
170 /* API */
el_torito_get_selection_crit(ElToritoBootImage * bootimg,uint8_t crit[20])171 int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
172 {
173
174 memcpy(crit, bootimg->selection_crit, 20);
175 return 1;
176 }
177
178 /* API */
el_torito_seems_boot_info_table(ElToritoBootImage * bootimg,int flag)179 int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag)
180 {
181 switch (flag & 15) {
182 case 0:
183 return bootimg->seems_boot_info_table;
184 case 1:
185 return bootimg->seems_grub2_boot_info;
186 }
187 return 0;
188 }
189
190 /**
191 * Specifies that this image needs to be patched. This involves the writing
192 * of a 56 bytes boot information table at offset 8 of the boot image file.
193 * The original boot image file won't be modified.
194 * This is needed for isolinux boot images.
195 */
el_torito_patch_isolinux_image(ElToritoBootImage * bootimg)196 void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
197 {
198 bootimg->isolinux_options |= 0x01;
199 }
200
201
202 /**
203 * Specifies options for IsoLinux boot images. This should only be used with
204 * isolinux boot images.
205 *
206 * @param options
207 * bitmask style flag. The following values are defined:
208 *
209 * bit 0 -> 1 to path the image, 0 to not
210 * Patching the image involves the writing of a 56 bytes
211 * boot information table at offset 8 of the boot image file.
212 * The original boot image file won't be modified. This is needed
213 * to allow isolinux images to be bootable.
214 * bit 1 -> 1 to generate an hybrid image, 0 to not
215 * An hybrid image is a boot image that boots from either CD/DVD
216 * media or from USB sticks. For that, you should use an isolinux
217 * image that supports hybrid mode. Recent images support this.
218 * @return
219 * 1 if success, < 0 on error
220 * @since 0.6.12
221 */
el_torito_set_isolinux_options(ElToritoBootImage * bootimg,int options,int flag)222 int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag)
223 {
224 bootimg->isolinux_options = (options & 0x03ff);
225 bootimg->seems_boot_info_table = !!(options & 1);
226 bootimg->seems_grub2_boot_info = !!(options & (1 << 9));
227 return ISO_SUCCESS;
228 }
229
230 /* API */
el_torito_get_isolinux_options(ElToritoBootImage * bootimg,int flag)231 int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag)
232 {
233 return bootimg->isolinux_options & 0x03ff;
234 }
235
236 /* API */
el_torito_get_boot_media_type(ElToritoBootImage * bootimg,enum eltorito_boot_media_type * media_type)237 int el_torito_get_boot_media_type(ElToritoBootImage *bootimg,
238 enum eltorito_boot_media_type *media_type)
239 {
240 if (bootimg) {
241 switch (bootimg->type) {
242 case 1:
243 case 2:
244 case 3:
245 *media_type = ELTORITO_FLOPPY_EMUL;
246 return 1;
247 case 4:
248 *media_type = ELTORITO_HARD_DISC_EMUL;
249 return 1;
250 case 0:
251 *media_type = ELTORITO_NO_EMUL;
252 return 1;
253 default:
254 /* should never happen */
255 return ISO_ASSERT_FAILURE;
256 break;
257 }
258 }
259 return ISO_WRONG_ARG_VALUE;
260 }
261
262 static
iso_tree_add_boot_node(IsoDir * parent,const char * name,IsoBoot ** boot)263 int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
264 {
265 IsoBoot *node;
266 IsoNode **pos;
267 time_t now;
268 int ret;
269
270 if (parent == NULL || name == NULL || boot == NULL) {
271 return ISO_NULL_POINTER;
272 }
273 if (boot) {
274 *boot = NULL;
275 }
276
277 /* check if the name is valid */
278 ret = iso_node_is_valid_name(name);
279 if (ret < 0)
280 return ret;
281
282 /* find place where to insert */
283 pos = &(parent->children);
284 while (*pos != NULL && strcmp((*pos)->name, name) < 0) {
285 pos = &((*pos)->next);
286 }
287 if (*pos != NULL && !strcmp((*pos)->name, name)) {
288 /* a node with same name already exists */
289 return ISO_NODE_NAME_NOT_UNIQUE;
290 }
291
292 node = calloc(1, sizeof(IsoBoot));
293 if (node == NULL) {
294 return ISO_OUT_OF_MEM;
295 }
296
297 node->node.refcount = 1;
298 node->node.type = LIBISO_BOOT;
299 node->node.name = strdup(name);
300 if (node->node.name == NULL) {
301 free(node);
302 return ISO_OUT_OF_MEM;
303 }
304 node->lba = 0;
305 node->size = 0;
306 node->content = NULL;
307
308 /* attributes from parent */
309 node->node.mode = S_IFREG | (parent->node.mode & 0444);
310 node->node.uid = parent->node.uid;
311 node->node.gid = parent->node.gid;
312 node->node.hidden = parent->node.hidden;
313
314 /* current time */
315 iso_nowtime(&now, 0);
316 node->node.atime = now;
317 node->node.ctime = now;
318 node->node.mtime = now;
319
320 /* add to dir */
321 node->node.parent = parent;
322 node->node.next = *pos;
323 *pos = (IsoNode*)node;
324
325 if (boot) {
326 *boot = node;
327 }
328 return ++parent->nchildren;
329 }
330
331 /* Get start and size from "%d_start_%lus_size_%lud" */
332 static
iso_parse_start_size(char * text,unsigned long * part_start,unsigned long * part_size)333 void iso_parse_start_size(char *text, unsigned long *part_start,
334 unsigned long *part_size)
335 {
336 char *cpt;
337 unsigned long start, size;
338
339 cpt = strchr(text, '_');
340 if (cpt == NULL)
341 return;
342 if (strncmp(cpt, "_start_", 7) != 0)
343 return;
344 sscanf(cpt + 7, "%lu", &start);
345 cpt = strchr(cpt + 7, '_');
346 if (cpt == NULL)
347 return;
348 if (*(cpt - 1) != 's')
349 return;
350 if (strncmp(cpt, "_size_", 6) != 0)
351 return;
352 sscanf(cpt + 6, "%lu", &size);
353 for (cpt = cpt + 6; *cpt >= '0' && *cpt <= '9'; cpt++);
354 if (*cpt != 'd')
355 return;
356
357 *part_start = start;
358 *part_size = size;
359 }
360
361 static
create_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,struct el_torito_boot_image ** bootimg,IsoFile ** bootnode)362 int create_image(IsoImage *image, const char *image_path,
363 enum eltorito_boot_media_type type,
364 struct el_torito_boot_image **bootimg,
365 IsoFile **bootnode)
366 {
367 int ret;
368 struct el_torito_boot_image *boot;
369 int boot_media_type = 0;
370 int load_sectors = 0; /* number of sector to load */
371 int part_idx = -1;
372 unsigned long part_start = 0, part_size = 0;
373 unsigned char partition_type = 0;
374 off_t size;
375 IsoNode *imgfile = NULL;
376 IsoStream *stream = NULL;
377
378 *bootnode = NULL;
379
380 if (strncmp(image_path, "--interval:appended_partition_", 30) == 0) {
381 /* --interval:appended_partition_N... */
382 if (type != ELTORITO_NO_EMUL) {
383
384 /* >>> ??? lift this ban by making a temporary IsoStream from
385 partition source, determine size,
386 and read ELTORITO_HARD_DISC_EMUL MBR ?
387 */
388
389 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
390 "Appended partition cannot serve as El Torito boot image with FD/HD emulation");
391 return ISO_BOOT_IMAGE_NOT_VALID;
392 }
393 sscanf(image_path + 30, "%d", &part_idx);
394 if (part_idx < 1 || part_idx > ISO_MAX_PARTITIONS) {
395 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
396 "Appended partition index for El Torito boot image is out of range");
397 return ISO_BOOT_IMAGE_NOT_VALID;
398 }
399 iso_parse_start_size((char *) (image_path + 30),
400 &part_start, &part_size);
401 part_idx--;
402 size = 1;
403 } else {
404 ret = iso_tree_path_to_node(image, image_path, &imgfile);
405 if (ret < 0) {
406 return ret;
407 }
408 if (ret == 0) {
409 iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
410 "El Torito boot image file missing in ISO image: '%s'",
411 image_path);
412 return ISO_NODE_DOESNT_EXIST;
413 }
414
415 if (imgfile->type != LIBISO_FILE) {
416 return ISO_BOOT_IMAGE_NOT_VALID;
417 }
418 *bootnode = (IsoFile *) imgfile;
419
420 stream = ((IsoFile*)imgfile)->stream;
421
422 /* we need to read the image at least two times */
423 if (!iso_stream_is_repeatable(stream)) {
424 return ISO_BOOT_IMAGE_NOT_VALID;
425 }
426
427 size = iso_stream_get_size(stream);
428 }
429 if (size <= 0) {
430 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
431 "Boot image file is empty");
432 return ISO_BOOT_IMAGE_NOT_VALID;
433 }
434
435 switch (type) {
436 case ELTORITO_FLOPPY_EMUL:
437 switch (size) {
438 case 1200 * 1024:
439 boot_media_type = 1; /* 1.2 meg diskette */
440 break;
441 case 1440 * 1024:
442 boot_media_type = 2; /* 1.44 meg diskette */
443 break;
444 case 2880 * 1024:
445 boot_media_type = 3; /* 2.88 meg diskette */
446 break;
447 default:
448 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
449 "Invalid image size %d Kb. Must be one of 1.2, 1.44"
450 "or 2.88 Mb", iso_stream_get_size(stream) / 1024);
451 return ISO_BOOT_IMAGE_NOT_VALID;
452 break;
453 }
454 /* it seems that for floppy emulation we need to load
455 * a single sector (512b) */
456 load_sectors = 1;
457 break;
458 case ELTORITO_HARD_DISC_EMUL:
459 {
460 size_t i;
461 struct hard_disc_mbr mbr;
462 int used_partition;
463
464 /* read the MBR on disc and get the type of the partition */
465 ret = iso_stream_open(stream);
466 if (ret < 0) {
467 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, ret,
468 "Can't open image file.");
469 return ret;
470 }
471 ret = iso_stream_read(stream, &mbr, sizeof(mbr));
472 iso_stream_close(stream);
473 if (ret != sizeof(mbr)) {
474 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
475 "Can't read MBR from image file.");
476 return ret < 0 ? ret : (int) ISO_FILE_READ_ERROR;
477 }
478
479 /* check valid MBR signature */
480 if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
481 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
482 "Invalid MBR. Wrong signature.");
483 return (int) ISO_BOOT_IMAGE_NOT_VALID;
484 }
485
486 /* ensure single partition */
487 used_partition = -1;
488 for (i = 0; i < 4; ++i) {
489 if (mbr.partition[i].type != 0) {
490 /* it's an used partition */
491 if (used_partition != -1) {
492 iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
493 "Invalid MBR. At least 2 partitions: %d and "
494 "%d, are being used\n", used_partition, i);
495 return ISO_BOOT_IMAGE_NOT_VALID;
496 } else
497 used_partition = i;
498 }
499 }
500 partition_type = mbr.partition[used_partition].type;
501 }
502 boot_media_type = 4;
503
504 /* only load the MBR */
505 load_sectors = 1;
506 break;
507 case ELTORITO_NO_EMUL:
508 boot_media_type = 0;
509 break;
510 }
511
512 boot = calloc(1, sizeof(struct el_torito_boot_image));
513 if (boot == NULL) {
514 return ISO_OUT_OF_MEM;
515 }
516 boot->image = (IsoFile*)imgfile;
517 boot->appended_idx = part_idx;
518 boot->appended_start = part_start;
519 boot->appended_size = part_size;
520 if (imgfile != NULL)
521 iso_node_ref(imgfile); /* get our ref */
522 boot->bootable = 1;
523 boot->seems_boot_info_table = 0;
524 boot->seems_grub2_boot_info = 0;
525 boot->seems_isohybrid_capable = 0;
526 boot->isolinux_options = 0;
527 boot->type = boot_media_type;
528 boot->partition_type = partition_type;
529 boot->load_seg = 0;
530 boot->load_size = load_sectors;
531 boot->load_size_full = 0;
532 boot->platform_id = 0; /* 80x86 */
533 memset(boot->id_string, 0, sizeof(boot->id_string));
534 memset(boot->selection_crit, 0, sizeof(boot->selection_crit));
535 *bootimg = boot;
536
537 return ISO_SUCCESS;
538 }
539
iso_image_set_boot_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,const char * catalog_path,ElToritoBootImage ** boot)540 int iso_image_set_boot_image(IsoImage *image, const char *image_path,
541 enum eltorito_boot_media_type type,
542 const char *catalog_path,
543 ElToritoBootImage **boot)
544 {
545 int ret, i;
546 struct el_torito_boot_catalog *catalog;
547 ElToritoBootImage *boot_image= NULL;
548 IsoBoot *cat_node= NULL;
549 IsoFile *boot_node;
550
551 if (image == NULL || image_path == NULL || catalog_path == NULL) {
552 return ISO_NULL_POINTER;
553 }
554 if (image->bootcat != NULL) {
555 return ISO_IMAGE_ALREADY_BOOTABLE;
556 }
557
558 /* create the node for the catalog */
559 {
560 IsoDir *parent;
561 char *catdir = NULL, *catname = NULL;
562 catdir = strdup(catalog_path);
563 if (catdir == NULL) {
564 return ISO_OUT_OF_MEM;
565 }
566
567 /* get both the dir and the name */
568 catname = strrchr(catdir, '/');
569 if (catname == NULL)
570 catname = catdir;
571 if (catname == catdir) {
572 /* we are appending catalog to root node */
573 parent = image->root;
574 } else {
575 IsoNode *p;
576 catname[0] = '\0';
577 ret = iso_tree_path_to_node(image, catdir, &p);
578 if (ret <= 0) {
579 iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
580 "Cannot find directory for El Torito boot catalog in ISO image: '%s'",
581 catdir);
582 free(catdir);
583 return ret < 0 ? ret : (int) ISO_NODE_DOESNT_EXIST;
584 }
585 if (p->type != LIBISO_DIR) {
586 free(catdir);
587 return ISO_WRONG_ARG_VALUE;
588 }
589 parent = (IsoDir*)p;
590 }
591 if (catname[0] == '/' || catname[0] == 0)
592 catname++;
593 ret = iso_tree_add_boot_node(parent, catname, &cat_node);
594 free(catdir);
595 if (ret < 0) {
596 return ret;
597 }
598 }
599
600 /* create the boot image */
601 ret = create_image(image, image_path, type, &boot_image, &boot_node);
602 if (ret < 0) {
603 goto boot_image_cleanup;
604 }
605
606 /* creates the catalog with the given image */
607 catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
608 if (catalog == NULL) {
609 ret = ISO_OUT_OF_MEM;
610 goto boot_image_cleanup;
611 }
612 catalog->num_bootimages = 1;
613 catalog->bootimages[0] = boot_image;
614 for (i = 1; i < Libisofs_max_boot_imageS; i++)
615 catalog->bootimages[i] = NULL;
616 catalog->node = cat_node;
617 catalog->sort_weight = 1000000000; /* very high */
618 if (boot_node != NULL)
619 if (!(boot_node->explicit_weight || boot_node->from_old_session))
620 boot_node->sort_weight = 2;
621 iso_node_ref((IsoNode*)cat_node);
622 image->bootcat = catalog;
623
624 if (boot) {
625 *boot = boot_image;
626 }
627
628 return ISO_SUCCESS;
629
630 boot_image_cleanup:;
631 if (cat_node) {
632 iso_node_take((IsoNode*)cat_node);
633 iso_node_unref((IsoNode*)cat_node);
634 }
635 if (boot_image) {
636 if (boot_image->image != NULL)
637 iso_node_unref((IsoNode*)boot_image->image);
638 free(boot_image);
639 }
640 return ret;
641 }
642
643 /**
644 * Get the boot catalog and the El-Torito default boot image of an ISO image.
645 *
646 * This can be useful, for example, to check if a volume read from a previous
647 * session or an existing image is bootable. It can also be useful to get
648 * the image and catalog tree nodes. An application would want those, for
649 * example, to prevent the user removing it.
650 *
651 * Both nodes are owned by libisofs and should not be freed. You can get your
652 * own ref with iso_node_ref(). You can can also check if the node is already
653 * on the tree by getting its parent (note that when reading El-Torito info
654 * from a previous image, the nodes might not be on the tree even if you haven't
655 * removed them). Remember that you'll need to get a new ref
656 * (with iso_node_ref()) before inserting them again to the tree, and probably
657 * you will also need to set the name or permissions.
658 *
659 * @param image
660 * The image from which to get the boot image.
661 * @param boot
662 * If not NULL, it will be filled with a pointer to the boot image, if
663 * any. That object is owned by the IsoImage and should not be freed by
664 * the user, nor dereferenced once the last reference to the IsoImage was
665 * disposed via iso_image_unref().
666 * @param imgnode
667 * When not NULL, it will be filled with the image tree node. No extra ref
668 * is added, you can use iso_node_ref() to get one if you need it.
669 * @param catnode
670 * When not NULL, it will be filled with the catnode tree node. No extra
671 * ref is added, you can use iso_node_ref() to get one if you need it.
672 * @return
673 * 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
674 * image), < 0 error.
675 */
iso_image_get_boot_image(IsoImage * image,ElToritoBootImage ** boot,IsoFile ** imgnode,IsoBoot ** catnode)676 int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
677 IsoFile **imgnode, IsoBoot **catnode)
678 {
679 if (image == NULL) {
680 return ISO_NULL_POINTER;
681 }
682 if (image->bootcat == NULL) {
683 return 0;
684 }
685
686 /* ok, image is bootable */
687 if (boot) {
688 *boot = image->bootcat->bootimages[0];
689 }
690 if (imgnode) {
691 *imgnode = image->bootcat->bootimages[0]->image;
692 }
693 if (catnode) {
694 *catnode = image->bootcat->node;
695 }
696 return ISO_SUCCESS;
697 }
698
iso_image_get_bootcat(IsoImage * image,IsoBoot ** catnode,uint32_t * lba,char ** content,off_t * size)699 int iso_image_get_bootcat(IsoImage *image, IsoBoot **catnode, uint32_t *lba,
700 char **content, off_t *size)
701 {
702 IsoBoot *bootcat;
703
704 *catnode = NULL;
705 *lba = 0;
706 *content = NULL;
707 *size = 0;
708 bootcat = image->bootcat->node;
709 if (bootcat == NULL)
710 return 0;
711 *catnode = bootcat;
712 *lba = bootcat->lba;
713 if (bootcat->size > 0 && bootcat->content != NULL) {
714 *content = calloc(1, bootcat->size);
715 if (*content == NULL)
716 return ISO_OUT_OF_MEM;
717 memcpy(*content, bootcat->content, bootcat->size);
718 }
719 if (*content != NULL)
720 *size = bootcat->size;
721 return 1;
722 }
723
iso_image_get_all_boot_imgs(IsoImage * image,int * num_boots,ElToritoBootImage *** boots,IsoFile *** bootnodes,int flag)724 int iso_image_get_all_boot_imgs(IsoImage *image, int *num_boots,
725 ElToritoBootImage ***boots, IsoFile ***bootnodes, int flag)
726 {
727 int i;
728 struct el_torito_boot_catalog *cat;
729
730 if (image == NULL)
731 return ISO_NULL_POINTER;
732 if (image->bootcat == NULL)
733 return 0;
734 cat = image->bootcat;
735 *num_boots = cat->num_bootimages;
736 *boots = NULL;
737 *bootnodes = NULL;
738 if (*num_boots <= 0)
739 return 0;
740 *boots = calloc(*num_boots, sizeof(ElToritoBootImage *));
741 *bootnodes = calloc(*num_boots, sizeof(IsoFile *));
742 if(*boots == NULL || *bootnodes == NULL) {
743 if (*boots != NULL)
744 free(*boots);
745 if (*bootnodes != NULL)
746 free(*bootnodes);
747 *boots = NULL;
748 *bootnodes = NULL;
749 return ISO_OUT_OF_MEM;
750 }
751 for (i = 0; i < *num_boots; i++) {
752 (*boots)[i] = cat->bootimages[i];
753 (*bootnodes)[i] = image->bootcat->bootimages[i]->image;
754 }
755 return 1;
756 }
757
758 /**
759 * Removes the El-Torito bootable image.
760 *
761 * The IsoBoot node that acts as placeholder for the catalog is also removed
762 * for the image tree, if there.
763 * If the image is not bootable (don't have el-torito boot image) this function
764 * just returns.
765 */
iso_image_remove_boot_image(IsoImage * image)766 void iso_image_remove_boot_image(IsoImage *image)
767 {
768 if (image == NULL || image->bootcat == NULL)
769 return;
770
771 /*
772 * remove catalog node from its parent and dispose it
773 * (another reference is with the catalog)
774 */
775 if (iso_node_get_parent((IsoNode*) image->bootcat->node) != NULL) {
776 iso_node_take((IsoNode*) image->bootcat->node);
777 iso_node_unref((IsoNode*) image->bootcat->node);
778 }
779
780 /* free boot catalog and image, including references to nodes */
781 el_torito_boot_catalog_free(image->bootcat);
782 image->bootcat = NULL;
783 }
784
785 /* API */
iso_image_add_boot_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,int flag,ElToritoBootImage ** boot)786 int iso_image_add_boot_image(IsoImage *image, const char *image_path,
787 enum eltorito_boot_media_type type, int flag,
788 ElToritoBootImage **boot)
789 {
790 int ret;
791 struct el_torito_boot_catalog *catalog = image->bootcat;
792 ElToritoBootImage *boot_img;
793 IsoFile *boot_node;
794
795 if(catalog == NULL)
796 return ISO_BOOT_NO_CATALOG;
797 if (catalog->num_bootimages >= Libisofs_max_boot_imageS)
798 return ISO_BOOT_IMAGE_OVERFLOW;
799 ret = create_image(image, image_path, type, &boot_img, &boot_node);
800 if (ret < 0)
801 return ret;
802 if (boot_node != NULL)
803 if (!(boot_node->explicit_weight || boot_node->from_old_session))
804 boot_node->sort_weight = 2;
805 catalog->bootimages[catalog->num_bootimages] = boot_img;
806 catalog->num_bootimages++;
807 if (boot != NULL)
808 *boot = boot_img;
809 return 1;
810 }
811
812 /* API */
iso_image_set_boot_catalog_weight(IsoImage * image,int sort_weight)813 int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight)
814 {
815 if (image->bootcat == NULL)
816 return 0;
817 image->bootcat->sort_weight = sort_weight;
818 return 1;
819 }
820
821 /* API */
iso_image_set_boot_catalog_hidden(IsoImage * image,int hide_attrs)822 int iso_image_set_boot_catalog_hidden(IsoImage *image, int hide_attrs)
823 {
824 if (image->bootcat == NULL)
825 return 0;
826 if (image->bootcat->node == NULL)
827 return 0;
828 iso_node_set_hidden((IsoNode *) image->bootcat->node, hide_attrs);
829 return 1;
830 }
831
832
el_torito_boot_catalog_free(struct el_torito_boot_catalog * cat)833 void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
834 {
835 struct el_torito_boot_image *image;
836 int i;
837
838 if (cat == NULL) {
839 return;
840 }
841
842 for (i = 0; i < Libisofs_max_boot_imageS; i++) {
843 image = cat->bootimages[i];
844 if (image == NULL)
845 continue;
846 if ((IsoNode*)image->image != NULL)
847 iso_node_unref((IsoNode*)image->image);
848 free(image);
849 }
850 if ((IsoNode*)cat->node != NULL)
851 iso_node_unref((IsoNode*)cat->node);
852 free(cat);
853 }
854
855 /**
856 * Stream that generates the contents of a El-Torito catalog.
857 */
858 struct catalog_stream
859 {
860 Ecma119Image *target;
861 uint8_t buffer[BLOCK_SIZE];
862 int offset; /* -1 if stream is not opened */
863 };
864
865 static void
write_validation_entry(uint8_t * buf,uint8_t platform_id,uint8_t id_string[24])866 write_validation_entry(uint8_t *buf, uint8_t platform_id,
867 uint8_t id_string[24])
868 {
869 size_t i;
870 int checksum;
871
872 struct el_torito_validation_entry *ve =
873 (struct el_torito_validation_entry*)buf;
874 ve->header_id[0] = 1;
875 ve->platform_id[0] = platform_id;
876 memcpy(ve->id_string, id_string, sizeof(ve->id_string));
877 ve->key_byte1[0] = 0x55;
878 ve->key_byte2[0] = 0xAA;
879 /* calculate the checksum, to ensure sum of all words is 0 */
880 checksum = 0;
881 for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
882 checksum -= (int16_t) ((buf[i+1] << 8) | buf[i]);
883 }
884 iso_lsb(ve->checksum, checksum, 2);
885 }
886
887 static void
write_section_header(uint8_t * buf,Ecma119Image * t,int idx,int num_entries)888 write_section_header(uint8_t *buf, Ecma119Image *t, int idx, int num_entries)
889 {
890 char *id_string;
891
892 struct el_torito_section_header *e =
893 (struct el_torito_section_header *) buf;
894
895 /* 0x90 = more section headers follow , 0x91 = final section */
896 e->header_indicator[0] =
897 0x90 + (idx == t->catalog->num_bootimages - num_entries);
898 e->platform_id[0] = t->catalog->bootimages[idx]->platform_id;
899 e->num_entries[0] = num_entries & 0xff;
900 e->num_entries[1] = (num_entries >> 8) & 0xff;;
901 id_string = (char *) e->id_string;
902 memcpy(id_string, t->catalog->bootimages[idx]->id_string,
903 sizeof(e->id_string));
904 }
905
906 static int
write_section_load_size(struct el_torito_boot_image * img,struct el_torito_section_entry * se,uint16_t load_size,off_t full_byte_size,int flag)907 write_section_load_size(struct el_torito_boot_image *img,
908 struct el_torito_section_entry *se,
909 uint16_t load_size, off_t full_byte_size, int flag)
910 {
911 uint16_t size;
912 off_t blocks;
913
914 size= load_size;
915 if(img->type == 0 && img->load_size_full) {
916 blocks= ((full_byte_size + 2047) / 2048) * 4;
917 if (blocks > 65535) {
918 if (img->platform_id == 0xef)
919 size= 0;
920 else
921 size= 65535;
922 } else if(blocks <= 0) {
923 size= 1;
924 } else {
925 size= blocks;
926 }
927 }
928 iso_lsb(se->sec_count, size, 2);
929 return(1);
930 }
931
932 /**
933 * Write one section entry.
934 * Usable for the Default Entry
935 * and for Section Entries with Selection criteria type == 0
936 */
937 static
write_section_entry(uint8_t * buf,Ecma119Image * t,int idx)938 int write_section_entry(uint8_t *buf, Ecma119Image *t, int idx)
939 {
940 struct el_torito_boot_image *img;
941 struct el_torito_section_entry *se =
942 (struct el_torito_section_entry*)buf;
943 int app_idx, mode = 0;
944
945 img = t->catalog->bootimages[idx];
946
947 se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
948 se->boot_media_type[0] = img->type;
949 iso_lsb(se->load_seg, img->load_seg, 2);
950 se->system_type[0] = img->partition_type;
951
952 if (t->boot_appended_idx[idx] >= 0)
953 if (t->appended_part_size[t->boot_appended_idx[idx]] > 0)
954 mode = 2; /* appended partition */
955 if (mode == 0 && t->opts->appendable &&
956 (t->boot_intvl_start[idx] > 0 || t->boot_intvl_size[idx] > 0) &&
957 t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 <=
958 t->opts->ms_block)
959 mode = 1; /* image interval */
960 if (mode == 0 && t->boot_appended_idx[idx] >= 0) {
961 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
962 "Appended partition which shall serve as boot image does not exist");
963 return ISO_BOOT_IMAGE_NOT_VALID;
964 }
965
966 if (mode == 1) {
967 if (t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 >
968 t->total_size / 2048 + t->opts->ms_block - t->eff_partition_offset
969 ) {
970 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
971 "Block interval which shall serve as boot image is outside result range");
972 return ISO_BOOT_IMAGE_NOT_VALID;
973 }
974
975 /* >>> check for non-automatic load size */;
976
977 if (t->boot_intvl_size[idx] > 65535) {
978 if (img->platform_id == 0xef)
979 iso_lsb(se->sec_count, 0, 2);
980 else
981 iso_lsb(se->sec_count, 65535, 2);
982 } else {
983 if (t->boot_intvl_size[idx] == 0) {
984 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
985 "Block interval which shall serve as boot image has zero size");
986 return ISO_BOOT_IMAGE_NOT_VALID;
987 }
988 iso_lsb(se->sec_count, t->boot_intvl_size[idx], 2);
989 }
990 iso_lsb(se->block, t->boot_intvl_start[idx], 4);
991 } else if (mode == 2) {
992 app_idx = t->boot_appended_idx[idx];
993
994 /* >>> check for non-automatic load size */;
995
996 if (t->appended_part_size[app_idx] * 4 > 65535) {
997 if (img->platform_id == 0xef)
998 iso_lsb(se->sec_count, 0, 2);
999 else
1000 iso_lsb(se->sec_count, 65535, 2);
1001 } else {
1002 iso_lsb(se->sec_count, t->appended_part_size[app_idx] * 4, 2);
1003 }
1004 iso_lsb(se->block, t->appended_part_start[app_idx], 4);
1005 } else {
1006 write_section_load_size(img, se, (uint16_t) img->load_size,
1007 (off_t) t->bootsrc[idx]->sections[0].size, 0);
1008 iso_lsb(se->block, t->bootsrc[idx]->sections[0].block, 4);
1009 }
1010
1011 se->selec_criteria[0] = img->selection_crit[0];
1012 memcpy(se->vendor_sc, img->selection_crit + 1, 19);
1013 return ISO_SUCCESS;
1014 }
1015
1016 static
catalog_open(IsoStream * stream)1017 int catalog_open(IsoStream *stream)
1018 {
1019 int i, j, k, num_entries, ret;
1020 struct catalog_stream *data;
1021 uint8_t *wpt;
1022 struct el_torito_boot_catalog *cat;
1023 struct el_torito_boot_image **boots;
1024
1025 if (stream == NULL) {
1026 return ISO_NULL_POINTER;
1027 }
1028 data = stream->data;
1029 cat = data->target->catalog;
1030 boots = cat->bootimages;
1031
1032 if (data->offset != -1) {
1033 return ISO_FILE_ALREADY_OPENED;
1034 }
1035
1036 memset(data->buffer, 0, BLOCK_SIZE);
1037
1038 /* fill the buffer with the catalog contents */
1039 write_validation_entry(data->buffer,
1040 boots[0]->platform_id, boots[0]->id_string);
1041
1042 /* write default entry = first boot image */
1043 ret = write_section_entry(data->buffer + 32, data->target, 0);
1044 if (ret < 0)
1045 return ret;
1046
1047 /* IMPORTANT: The maximum number of boot images must fit into BLOCK_SIZE */
1048 wpt = data->buffer + 64;
1049 for (i = 1; i < cat->num_bootimages; ) {
1050 /* Look ahead and put images of same platform_id and id_string
1051 into the same section */
1052 for (j = i + 1; j < cat->num_bootimages; j++) {
1053 if (boots[i]->platform_id != boots[j]->platform_id)
1054 break;
1055 for (k = 0; k < (int) sizeof(boots[i]->id_string); k++)
1056 if (boots[i]->id_string[k] != boots[j]->id_string[k])
1057 break;
1058 if (k < (int) sizeof(boots[i]->id_string))
1059 break;
1060 }
1061 num_entries = j - i;
1062
1063 write_section_header(wpt, data->target, i, num_entries);
1064 wpt += 32;
1065 for (j = 0; j < num_entries; j++) {
1066 ret = write_section_entry(wpt, data->target, i);
1067 if (ret < 0)
1068 return ret;
1069 wpt += 32;
1070 i++;
1071 }
1072 }
1073 data->offset = 0;
1074 return ISO_SUCCESS;
1075 }
1076
1077 static
catalog_close(IsoStream * stream)1078 int catalog_close(IsoStream *stream)
1079 {
1080 struct catalog_stream *data;
1081 if (stream == NULL) {
1082 return ISO_NULL_POINTER;
1083 }
1084 data = stream->data;
1085
1086 if (data->offset == -1) {
1087 return ISO_FILE_NOT_OPENED;
1088 }
1089 data->offset = -1;
1090 return ISO_SUCCESS;
1091 }
1092
1093 static
catalog_get_size(IsoStream * stream)1094 off_t catalog_get_size(IsoStream *stream)
1095 {
1096 return BLOCK_SIZE;
1097 }
1098
1099 static
catalog_read(IsoStream * stream,void * buf,size_t count)1100 int catalog_read(IsoStream *stream, void *buf, size_t count)
1101 {
1102 size_t len;
1103 struct catalog_stream *data;
1104 if (stream == NULL || buf == NULL) {
1105 return ISO_NULL_POINTER;
1106 }
1107 if (count == 0) {
1108 return ISO_WRONG_ARG_VALUE;
1109 }
1110 data = stream->data;
1111
1112 if (data->offset == -1) {
1113 return ISO_FILE_NOT_OPENED;
1114 }
1115
1116 len = MIN(count, (size_t) (BLOCK_SIZE - data->offset));
1117 memcpy(buf, data->buffer + data->offset, len);
1118 return len;
1119 }
1120
1121 static
catalog_is_repeatable(IsoStream * stream)1122 int catalog_is_repeatable(IsoStream *stream)
1123 {
1124 return 1;
1125 }
1126
1127 /**
1128 * fs_id will be the id reserved for El-Torito
1129 * dev_id will be 0 for catalog, 1 for boot image (if needed)
1130 * ino_id 0 is supposed to be unique. At write time it will get assigned
1131 * an automatic file serial number in the ISO, if needed.
1132 */
1133 static
catalog_get_id(IsoStream * stream,unsigned int * fs_id,dev_t * dev_id,ino_t * ino_id)1134 void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
1135 ino_t *ino_id)
1136 {
1137 *fs_id = ISO_ELTORITO_FS_ID;
1138 *dev_id = 0;
1139 *ino_id = 0;
1140 }
1141
1142 static
catalog_free(IsoStream * stream)1143 void catalog_free(IsoStream *stream)
1144 {
1145 free(stream->data);
1146 }
1147
1148 IsoStreamIface catalog_stream_class = {
1149 0,
1150 "boot",
1151 catalog_open,
1152 catalog_close,
1153 catalog_get_size,
1154 catalog_read,
1155 catalog_is_repeatable,
1156 catalog_get_id,
1157 catalog_free,
1158 NULL,
1159 NULL,
1160 NULL,
1161 NULL
1162 };
1163
1164 /**
1165 * Create an IsoStream for writing El-Torito catalog for a given target.
1166 */
1167 static
catalog_stream_new(Ecma119Image * target,IsoStream ** stream)1168 int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
1169 {
1170 IsoStream *str;
1171 struct catalog_stream *data;
1172
1173 if (target == NULL || stream == NULL || target->catalog == NULL) {
1174 return ISO_NULL_POINTER;
1175 }
1176
1177 str = calloc(1, sizeof(IsoStream));
1178 if (str == NULL) {
1179 return ISO_OUT_OF_MEM;
1180 }
1181 data = calloc(1, sizeof(struct catalog_stream));
1182 if (data == NULL) {
1183 free(str);
1184 return ISO_OUT_OF_MEM;
1185 }
1186
1187 /* fill data */
1188 data->target = target;
1189 data->offset = -1;
1190
1191 str->refcount = 1;
1192 str->data = data;
1193 str->class = &catalog_stream_class;
1194
1195 *stream = str;
1196 return ISO_SUCCESS;
1197 }
1198
el_torito_catalog_file_src_create(Ecma119Image * target,IsoFileSrc ** src)1199 int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
1200 {
1201 int ret;
1202 IsoFileSrc *file;
1203 IsoStream *stream;
1204
1205 if (target == NULL || src == NULL || target->catalog == NULL) {
1206 return ISO_OUT_OF_MEM;
1207 }
1208
1209 if (target->cat != NULL) {
1210 /* catalog file src already created */
1211 *src = target->cat;
1212 return ISO_SUCCESS;
1213 }
1214
1215 file = calloc(1, sizeof(IsoFileSrc));
1216 if (file == NULL) {
1217 return ISO_OUT_OF_MEM;
1218 }
1219
1220 ret = catalog_stream_new(target, &stream);
1221 if (ret < 0) {
1222 free(file);
1223 return ret;
1224 }
1225
1226 /* fill fields */
1227 file->no_write = 0; /* TODO allow copy of old img catalog???? */
1228 file->checksum_index = 0;
1229 file->nsections = 1;
1230 file->sections = calloc(1, sizeof(struct iso_file_section));
1231 file->sort_weight = target->catalog->sort_weight;
1232 file->stream = stream;
1233
1234 ret = iso_file_src_add(target, file, src);
1235 if (ret <= 0) {
1236 iso_stream_unref(stream);
1237 free(file);
1238 } else {
1239 target->cat = *src;
1240 }
1241 return ret;
1242 }
1243
1244 /******************* EL-TORITO WRITER *******************************/
1245
1246 /**
1247 * Insert boot info table content into buf.
1248 *
1249 * @return
1250 * 1 on success, 0 error (but continue), < 0 error
1251 */
make_boot_info_table(uint8_t * buf,uint32_t pvd_lba,uint32_t boot_lba,uint32_t imgsize)1252 int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
1253 uint32_t boot_lba, uint32_t imgsize)
1254 {
1255 struct boot_info_table *info;
1256 uint32_t checksum;
1257 uint32_t offset;
1258
1259 info = (struct boot_info_table *) (buf + 8);
1260 if (imgsize < 64)
1261 return ISO_ISOLINUX_CANT_PATCH;
1262
1263 /* compute checksum, as the the sum of all 32 bit words in boot image
1264 * from offset 64 */
1265 checksum = 0;
1266 offset = 64;
1267
1268 while (offset <= imgsize - 4) {
1269 checksum += iso_read_lsb(buf + offset, 4);
1270 offset += 4;
1271 }
1272 if (offset != imgsize) {
1273 /*
1274 * file length not multiple of 4
1275 * empty space in isofs is padded with zero;
1276 * assume same for last dword
1277 */
1278 checksum += iso_read_lsb(buf + offset, imgsize - offset);
1279 }
1280
1281 /*memset(info, 0, sizeof(struct boot_info_table));*/
1282 iso_lsb(info->bi_pvd, pvd_lba, 4);
1283 iso_lsb(info->bi_file, boot_lba, 4);
1284 iso_lsb(info->bi_length, imgsize, 4);
1285 iso_lsb(info->bi_csum, checksum, 4);
1286 memset(buf + 24, 0, 40);
1287 return ISO_SUCCESS;
1288 }
1289
1290 /**
1291 * Patch an El Torito boot image by a boot info table.
1292 *
1293 * @return
1294 * 1 on success, 0 error (but continue), < 0 error
1295 */
1296 static
patch_boot_info_table(uint8_t * buf,Ecma119Image * t,size_t imgsize,int idx)1297 int patch_boot_info_table(uint8_t *buf, Ecma119Image *t,
1298 size_t imgsize, int idx)
1299 {
1300 int ret;
1301
1302 if (imgsize < 64) {
1303 return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1304 "Isolinux image too small. We won't patch it.");
1305 }
1306 if (t->bootsrc[idx] == NULL)
1307 return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1308 "Cannot apply ISOLINUX patching outside of ISO 9660 filesystem.");
1309 ret = make_boot_info_table(buf, t->opts->ms_block + (uint32_t) 16,
1310 t->bootsrc[idx]->sections[0].block,
1311 (uint32_t) imgsize);
1312 return ret;
1313 }
1314
1315
1316 /**
1317 * Patch a GRUB2 El Torito boot image.
1318 */
1319 static
patch_grub2_boot_image(uint8_t * buf,Ecma119Image * t,size_t imgsize,int idx,size_t pos,int offst)1320 int patch_grub2_boot_image(uint8_t *buf, Ecma119Image *t,
1321 size_t imgsize, int idx,
1322 size_t pos, int offst)
1323 {
1324 uint64_t blk;
1325
1326 if (imgsize < pos + 8)
1327 return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1328 "Boot image too small for GRUB2. Will not patch it.");
1329 if (t->bootsrc[idx] == NULL)
1330 return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1331 "Cannot apply GRUB2 patching outside of ISO 9660 filesystem.");
1332 blk = ((uint64_t) t->bootsrc[idx]->sections[0].block) * 4 + offst;
1333 iso_lsb((buf + pos), blk & 0xffffffff, 4);
1334 iso_lsb((buf + pos + 4), blk >> 32, 4);
1335 return ISO_SUCCESS;
1336 }
1337
1338
1339 /* Patch the boot images if indicated */
iso_patch_eltoritos(Ecma119Image * t)1340 int iso_patch_eltoritos(Ecma119Image *t)
1341 {
1342 int ret, idx;
1343 size_t size;
1344 uint8_t *buf;
1345 IsoStream *new = NULL;
1346 IsoStream *original = NULL;
1347
1348 if (t->catalog == NULL)
1349 return ISO_SUCCESS;
1350
1351 for (idx = 0; idx < t->catalog->num_bootimages; idx++) {
1352 if (!(t->catalog->bootimages[idx]->isolinux_options & 0x201))
1353 continue;
1354 if (t->bootsrc[idx] == NULL)
1355 return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1356 "Cannot apply boot image patching outside of ISO 9660 filesystem");
1357
1358 original = t->bootsrc[idx]->stream;
1359 size = (size_t) iso_stream_get_size(original);
1360 if (size > Libisofs_elto_max_patchablE)
1361 return ISO_PATCH_OVERSIZED_BOOT;
1362 if (iso_stream_get_input_stream(original, 0) != NULL)
1363 return ISO_PATCH_FILTERED_BOOT;
1364 buf = calloc(1, size);
1365 if (buf == NULL) {
1366 return ISO_OUT_OF_MEM;
1367 }
1368 ret = iso_stream_open(original);
1369 if (ret < 0) {
1370 free(buf);
1371 return ret;
1372 }
1373 ret = iso_stream_read(original, buf, size);
1374 iso_stream_close(original);
1375 if (ret != (int) size) {
1376 if (ret >= 0)
1377 iso_msg_submit(t->image->id, ISO_FILE_READ_ERROR, 0,
1378 "Cannot read all bytes from El Torito boot image for boot info table");
1379 return (ret < 0) ? ret : (int) ISO_FILE_READ_ERROR;
1380 }
1381
1382 /* ok, patch the read buffer */
1383 if (t->catalog->bootimages[idx]->isolinux_options & 0x200) {
1384 /* GRUB2 boot provisions */
1385 ret = patch_grub2_boot_image(buf, t, size, idx,
1386 Libisofs_grub2_elto_patch_poS,
1387 Libisofs_grub2_elto_patch_offsT);
1388 if (ret < 0)
1389 return ret;
1390 }
1391 /* Must be done as last patching */
1392 if (t->catalog->bootimages[idx]->isolinux_options & 0x01) {
1393 /* Boot Info Table */
1394 ret = patch_boot_info_table(buf, t, size, idx);
1395 if (ret < 0)
1396 return ret;
1397 }
1398
1399 /* replace the original stream with a memory stream that reads from
1400 * the patched buffer */
1401 ret = iso_memory_stream_new(buf, size, &new);
1402 if (ret < 0) {
1403 return ret;
1404 }
1405 t->bootsrc[idx]->stream = new;
1406 iso_stream_unref(original);
1407 }
1408 return ISO_SUCCESS;
1409 }
1410
1411 static
eltorito_writer_compute_data_blocks(IsoImageWriter * writer)1412 int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
1413 {
1414 /*
1415 * We have nothing to write.
1416 */
1417 return ISO_SUCCESS;
1418 }
1419
1420
1421 /**
1422 * Write the Boot Record Volume Descriptor (ECMA-119, 8.2)
1423 */
1424 static
eltorito_writer_write_vol_desc(IsoImageWriter * writer)1425 int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
1426 {
1427 Ecma119Image *t;
1428 struct ecma119_boot_rec_vol_desc vol;
1429
1430 if (writer == NULL) {
1431 return ISO_NULL_POINTER;
1432 }
1433
1434 t = writer->target;
1435 iso_msg_debug(t->image->id, "Write El-Torito boot record");
1436
1437 memset(&vol, 0, sizeof(struct ecma119_boot_rec_vol_desc));
1438 vol.vol_desc_type[0] = 0;
1439 memcpy(vol.std_identifier, "CD001", 5);
1440 vol.vol_desc_version[0] = 1;
1441 memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23);
1442 iso_lsb(vol.boot_catalog,
1443 t->cat->sections[0].block - t->eff_partition_offset, 4);
1444 return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
1445 }
1446
1447 static
eltorito_writer_write_data(IsoImageWriter * writer)1448 int eltorito_writer_write_data(IsoImageWriter *writer)
1449 {
1450 /* nothing to do, the files are written by the file writer */
1451 return ISO_SUCCESS;
1452 }
1453
1454 static
eltorito_writer_free_data(IsoImageWriter * writer)1455 int eltorito_writer_free_data(IsoImageWriter *writer)
1456 {
1457 /* nothing to do */
1458 return ISO_SUCCESS;
1459 }
1460
eltorito_writer_create(Ecma119Image * target)1461 int eltorito_writer_create(Ecma119Image *target)
1462 {
1463 int ret, idx, outsource_efi = 0;
1464 IsoImageWriter *writer;
1465 IsoFile *bootimg = NULL;
1466 IsoFileSrc *src = NULL;
1467
1468 writer = calloc(1, sizeof(IsoImageWriter));
1469 if (writer == NULL) {
1470 return ISO_OUT_OF_MEM;
1471 }
1472
1473 writer->compute_data_blocks = eltorito_writer_compute_data_blocks;
1474 writer->write_vol_desc = eltorito_writer_write_vol_desc;
1475 writer->write_data = eltorito_writer_write_data;
1476 writer->free_data = eltorito_writer_free_data;
1477 writer->data = NULL;
1478 writer->target = target;
1479
1480 /* add this writer to image */
1481 target->writers[target->nwriters++] = writer;
1482
1483 /*
1484 * get catalog and image file sources.
1485 * Note that the catalog may be already added, when creating the low
1486 * level ECMA-119 tree.
1487 */
1488 if (target->cat == NULL) {
1489 ret = el_torito_catalog_file_src_create(target, &src);
1490 if (ret < 0) {
1491 return ret;
1492 }
1493 }
1494
1495 if (target->opts->efi_boot_partition != NULL)
1496 if (strcmp(target->opts->efi_boot_partition, "--efi-boot-image") == 0)
1497 outsource_efi = 1;
1498 for (idx = 0; idx < target->catalog->num_bootimages; idx++) {
1499 target->bootsrc[idx] = NULL;
1500 if (target->catalog->bootimages[idx]->appended_idx >= 0) {
1501 /* Use an appended partition as boot image rather than IsoFile */
1502 target->boot_appended_idx[idx] =
1503 target->catalog->bootimages[idx]->appended_idx;
1504 target->boot_intvl_start[idx] =
1505 target->catalog->bootimages[idx]->appended_start;
1506 target->boot_intvl_size[idx] =
1507 target->catalog->bootimages[idx]->appended_size;
1508 continue;
1509 }
1510
1511 bootimg = target->catalog->bootimages[idx]->image;
1512 ret = iso_file_src_create(target, bootimg, &src);
1513 if (ret < 0) {
1514 return ret;
1515 }
1516 target->bootsrc[idx] = src;
1517
1518 /* For patching an image, it needs to be copied always */
1519 if (target->catalog->bootimages[idx]->isolinux_options & 0x01) {
1520 src->no_write = 0;
1521 }
1522
1523 /* If desired: Recognize first EFI boot image that will be newly
1524 written, and mark it as claimed for being a partition.
1525 */
1526 if (outsource_efi &&
1527 target->catalog->bootimages[idx]->platform_id == 0xef &&
1528 src->no_write == 0) {
1529 target->efi_boot_part_filesrc = src;
1530 src->sections[0].block = 0xfffffffe;
1531 ((IsoNode *) bootimg)->hidden |=
1532 LIBISO_HIDE_ON_HFSPLUS | LIBISO_HIDE_ON_FAT;
1533 outsource_efi = 0;
1534 }
1535 }
1536
1537 /* we need the bootable volume descriptor */
1538 target->curblock++;
1539
1540 if (outsource_efi) {
1541 /* Disable EFI Boot partition and complain */
1542 free(target->opts->efi_boot_partition);
1543 target->opts->efi_boot_partition = NULL;
1544 iso_msg_submit(target->image->id, ISO_BOOT_NO_EFI_ELTO, 0,
1545 "No newly added El Torito EFI boot image found for exposure as GPT partition");
1546 return ISO_BOOT_NO_EFI_ELTO;
1547 }
1548
1549 return ISO_SUCCESS;
1550 }
1551
1552