"Fossies" - the Fresh Open Source Software Archive 
Member "xorriso-1.5.4/libisofs/eltorito.c" (30 Jan 2021, 45593 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "eltorito.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
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 */
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 */
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 */
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 */
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 */
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 */
114 int el_torito_get_load_size(ElToritoBootImage *bootimg)
115 {
116 return (int) bootimg->load_size;
117 }
118
119 /* API */
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 */
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 */
137 void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
138 {
139 bootimg->bootable = 0;
140 }
141
142 /* API */
143 int el_torito_get_bootable(ElToritoBootImage *bootimg)
144 {
145 return !!bootimg->bootable;
146 }
147
148 /* API */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
231 int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag)
232 {
233 return bootimg->isolinux_options & 0x03ff;
234 }
235
236 /* API */
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
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
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
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
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 */
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
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
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 */
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 */
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 */
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 */
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
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
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
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
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
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
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
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
1094 off_t catalog_get_size(IsoStream *stream)
1095 {
1096 return BLOCK_SIZE;
1097 }
1098
1099 static
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
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
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
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
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
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 */
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
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
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 */
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
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
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
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
1455 int eltorito_writer_free_data(IsoImageWriter *writer)
1456 {
1457 /* nothing to do */
1458 return ISO_SUCCESS;
1459 }
1460
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