1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2009 - 2020 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 /*
12 * Filesystem/FileSource implementation to access an ISO image, using an
13 * IsoDataSource to read image data.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "../config.h"
18 #endif
19
20 #include "libisofs.h"
21 #include "ecma119.h"
22 #include "messages.h"
23 #include "rockridge.h"
24 #include "image.h"
25 #include "tree.h"
26 #include "eltorito.h"
27 #include "node.h"
28 #include "aaip_0_2.h"
29 #include "system_area.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <locale.h>
34 #include <langinfo.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <ctype.h>
38
39
40 /* Enable this and write the correct absolute path into the include statement
41 below in order to test the pending contribution to syslinux:
42 http://www.syslinux.org/archives/2013-March/019755.html
43
44 # def ine Libisofs_syslinux_tesT 1
45
46 */
47 #ifdef Libisofs_syslinux_tesT
48 #define Isolinux_rockridge_in_libisofS 1
49 #include "/reiser/syslinux/core/fs/iso9660/susp_rr.c"
50 /*
51 # inc lude "/home/thomas/projekte/cdrskin_dir/libisoburn-develop/test/susp_rr.c"
52 */
53 #endif /* Libisofs_syslinux_tesT */
54
55
56 /**
57 * Options for image reading.
58 * There are four kind of options:
59 * - Related to multisession support.
60 * In most cases, an image begins at LBA 0 of the data source. However,
61 * in multisession discs, the later image begins in the last session on
62 * disc. The block option can be used to specify the start of that last
63 * session.
64 * - Related to the tree that will be read.
65 * As default, when Rock Ridge extensions are present in the image, that
66 * will be used to get the tree. If RR extensions are not present, libisofs
67 * will use the Joliet extensions if available. Finally, the plain ISO-9660
68 * tree is used if neither RR nor Joliet extensions are available. With
69 * norock, nojoliet, and preferjoliet options, you can change this
70 * default behavior.
71 * - Related to default POSIX attributes.
72 * When Rock Ridege extensions are not used, libisofs can't figure out what
73 * are the the permissions, uid or gid for the files. You should supply
74 * default values for that.
75 */
76 struct iso_read_opts
77 {
78 /**
79 * Block where the image begins, usually 0, can be different on a
80 * multisession disc.
81 */
82 uint32_t block;
83
84 unsigned int norock : 1; /*< Do not read Rock Ridge extensions */
85 unsigned int nojoliet : 1; /*< Do not read Joliet extensions */
86 unsigned int noiso1999 : 1; /*< Do not read ISO 9660:1999 enhanced tree */
87 unsigned int noaaip : 1; /* Do not read AAIP extension for xattr and ACL */
88 unsigned int nomd5 : 2; /* Do not read MD5 array */
89
90 /**
91 * Hand out new inode numbers and overwrite eventually read PX inode
92 * numbers. This will split apart any hardlinks.
93 */
94 unsigned int make_new_ino : 1 ;
95
96 /**
97 * When both Joliet and RR extensions are present, the RR tree is used.
98 * If you prefer using Joliet, set this to 1.
99 */
100 unsigned int preferjoliet : 1;
101
102 /**
103 * If neither Rock Ridge nor Joliet is used, the ECMA-119 names are mapped
104 * according to one of these rules
105 * 0 = unmapped: show name as recorded in ECMA-119 directory record
106 * (not suitable for writing it to a new ISO filesystem)
107 * 1 = stripped: like unmapped, but strip off trailing ";1" or ".;1"
108 * 2 = uppercase: like stripped, but {a-z} mapped to {A-Z}
109 * 3 = lowercase: like stripped, but {A-Z} mapped to {a-z}
110 */
111 unsigned int ecma119_map : 2;
112
113 /**
114 * If Joliet is used, apply one of these mapping rules:
115 * 0 = unmapped: show name as recorded in Joliet directory record
116 * (not suitable for writing it to a new ISO filesystem)
117 * 1 = stripped: strip off trailing ";1" or ".;1"
118 */
119 unsigned int joliet_map : 1;
120
121 uid_t uid; /**< Default uid when no RR */
122 gid_t gid; /**< Default uid when no RR */
123 mode_t dir_mode; /**< Default mode when no RR (only permissions) */
124 mode_t file_mode;
125 /* TODO #00024 : option to convert names to lower case for iso reading */
126
127 /**
128 * Input charset for RR file names. NULL to use default locale charset.
129 */
130 char *input_charset;
131
132 /**
133 * Enable or disable methods to automatically choose an input charset.
134 * This eventually overrides input_charset.
135 *
136 * bit0= allow to set the input character set automatically from
137 * attribute "isofs.cs" of root directory
138 */
139 int auto_input_charset;
140
141
142 /**
143 * Enable or disable loading of the first 32768 bytes of the session and
144 * submission by iso_write_opts_set_system_area(data, 0).
145 */
146 int load_system_area;
147
148 /**
149 * Keep data source of imported ISO filesystem in IsoImage.import_src
150 */
151 int keep_import_src;
152
153 /**
154 * What to do in case of name longer than truncate_length:
155 * 0= throw FAILURE
156 * 1= truncate to truncate_length with MD5 of whole name at end
157 */
158 int truncate_mode;
159 int truncate_length;
160
161 };
162
163 /**
164 * Return information for image.
165 * Both size, hasRR and hasJoliet will be filled by libisofs with suitable
166 * values.
167 */
168 struct iso_read_image_features
169 {
170 /**
171 * Will be filled with the size (in 2048 byte block) of the image, as
172 * reported in the PVM.
173 */
174 uint32_t size;
175
176 /** It will be set to 1 if RR extensions are present, to 0 if not. */
177 unsigned int hasRR :1;
178
179 /** It will be set to 1 if Joliet extensions are present, to 0 if not. */
180 unsigned int hasJoliet :1;
181
182 /**
183 * It will be set to 1 if the image is an ISO 9660:1999, i.e. it has
184 * a version 2 Enhanced Volume Descriptor.
185 */
186 unsigned int hasIso1999 :1;
187
188 /** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/
189 unsigned int hasElTorito :1;
190
191 /**
192 * Which tree was loaded:
193 * 0= ISO 9660 + Rock Ridge , 1= Joliet , 2= ISO 9660:1999
194 */
195 int tree_loaded;
196
197 /** Whether Rock Ridge info was used while loading: 0= no, 1= yes */
198 int rr_loaded;
199
200 };
201
202 static int ifs_fs_open(IsoImageFilesystem *fs);
203 static int ifs_fs_close(IsoImageFilesystem *fs);
204 static int iso_file_source_new_ifs(IsoImageFilesystem *fs,
205 IsoFileSource *parent, struct ecma119_dir_record *record,
206 IsoFileSource **src, int flag);
207
208 /** unique identifier for each image */
209 unsigned int fs_dev_id = 0;
210
211 /**
212 * Should the RR extensions be read?
213 */
214 enum read_rr_ext {
215 RR_EXT_NO = 0, /*< Do not use RR extensions */
216 RR_EXT_110 = 1, /*< RR extensions conforming version 1.10 */
217 RR_EXT_112 = 2 /*< RR extensions conforming version 1.12 */
218 };
219
220
221 /**
222 * Private data for the image IsoFilesystem
223 */
224 typedef struct
225 {
226 /** DataSource from where data will be read */
227 IsoDataSource *src;
228
229 /** unique id for the each image (filesystem instance) */
230 unsigned int id;
231
232 /**
233 * Counter of the times the filesystem has been opened still pending of
234 * close. It is used to keep track of when we need to actually open or
235 * close the IsoDataSource.
236 */
237 unsigned int open_count;
238
239 uid_t uid; /**< Default uid when no RR */
240 gid_t gid; /**< Default uid when no RR */
241 mode_t dir_mode; /**< Default mode when no RR (only permissions) */
242 mode_t file_mode;
243
244 int msgid;
245
246 char *input_charset; /**< Input charset for RR names */
247 char *local_charset; /**< For RR names, will be set to the locale one */
248
249 /**
250 * Enable or disable methods to automatically choose an input charset.
251 * This eventually overrides input_charset.
252 *
253 * bit0= allow to set the input character set automatically from
254 * attribute "isofs.cs" of root directory
255 */
256 int auto_input_charset;
257
258 /**
259 * Will be filled with the block lba of the extend for the root directory
260 * of the hierarchy that will be read, either from the PVD (ISO, RR) or
261 * from the SVD (Joliet)
262 */
263 uint32_t iso_root_block;
264
265 /**
266 * Will be filled with the block lba of the extend for the root directory,
267 * as read from the PVM
268 */
269 uint32_t pvd_root_block;
270
271 /**
272 * Will be filled with the block lba of the extend for the root directory,
273 * as read from the SVD
274 */
275 uint32_t svd_root_block;
276
277 /**
278 * Will be filled with the block lba of the extend for the root directory,
279 * as read from the enhanced volume descriptor (ISO 9660:1999)
280 */
281 uint32_t evd_root_block;
282
283 /**
284 * If we need to read RR extensions. i.e., if the image contains RR
285 * extensions, and the user wants to read them.
286 */
287 enum read_rr_ext rr;
288
289 /**
290 * Bytes skipped within the System Use field of a directory record, before
291 * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3.
292 */
293 uint8_t len_skp;
294
295 /* Volume attributes */
296 char *volset_id;
297 char *volume_id; /**< Volume identifier. */
298 char *publisher_id; /**< Volume publisher. */
299 char *data_preparer_id; /**< Volume data preparer. */
300 char *system_id; /**< Volume system identifier. */
301 char *application_id; /**< Volume application id */
302 char *copyright_file_id;
303 char *abstract_file_id;
304 char *biblio_file_id;
305 char *creation_time;
306 char *modification_time;
307 char *expiration_time;
308 char *effective_time;
309
310 /* extension information */
311
312 /**
313 * RR version being used in image.
314 * 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12
315 */
316 enum read_rr_ext rr_version;
317
318 /** If Joliet extensions are available on image */
319 unsigned int joliet : 1;
320
321 /** If ISO 9660:1999 is available on image */
322 unsigned int iso1999 : 1;
323
324 /**
325 * See struct iso_read_opts.
326 */
327 int truncate_mode;
328 int truncate_length;
329 unsigned int ecma119_map : 2;
330 unsigned int joliet_map : 1;
331
332 /** Whether AAIP info shall be loaded if it is present.
333 * 1 = yes , 0 = no
334 */
335 int aaip_load;
336
337 /** Whether the MD5 array shall be read if available.
338 * 2 = yes, but do not check tags , 1 = yes , 0 = no
339 */
340 int md5_load;
341
342 /** Whether AAIP is present. Version major.minor = major * 100 + minor
343 * Value -1 means that no AAIP ER was detected yet.
344 */
345 int aaip_version;
346
347 /**
348 * Start block of loaded session.
349 */
350 uint32_t session_lba;
351
352 /**
353 * Number of blocks of the volume, as reported in the PVM.
354 */
355 uint32_t nblocks;
356
357 /* el-torito information */
358 unsigned int eltorito : 1; /* is el-torito available */
359 int num_bootimgs;
360 unsigned char platform_ids[Libisofs_max_boot_imageS];
361 unsigned char id_strings[Libisofs_max_boot_imageS][28];
362 unsigned char selection_crits[Libisofs_max_boot_imageS][20];
363 unsigned char boot_flags[Libisofs_max_boot_imageS]; /* bit0= bootable */
364 unsigned char media_types[Libisofs_max_boot_imageS];
365 unsigned char partition_types[Libisofs_max_boot_imageS];
366 short load_segs[Libisofs_max_boot_imageS];
367 short load_sizes[Libisofs_max_boot_imageS];
368 /** Block addresses of for El-Torito boot images.
369 Needed to recognize them when the get read from the directory tree.
370 */
371 uint32_t bootblocks[Libisofs_max_boot_imageS];
372
373 uint32_t catblock; /**< Block for El-Torito catalog */
374 off_t catsize; /* Size of boot catalog in bytes */
375 char *catcontent;
376
377 /* Whether inode numbers from PX entries shall be discarded */
378 unsigned int make_new_ino : 1 ;
379
380 /* Inode number generator counter. 32 bit because for Rock Ridge PX. */
381 uint32_t inode_counter;
382
383 /* PX inode number status
384 bit0= there were nodes with PX inode numbers
385 bit1= there were nodes with PX but without inode numbers
386 bit2= there were nodes without PX
387 bit3= there were nodes with faulty PX
388 */
389 int px_ino_status;
390
391 /* Which Rock Ridge error messages already have occurred
392 bit0= Invalid PX entry
393 bit1= Invalid TF entry
394 bit2= New NM entry found without previous CONTINUE flag
395 bit3= Invalid NM entry
396 bit4= New SL entry found without previous CONTINUE flag
397 bit5= Invalid SL entry
398 bit6= Invalid CL entry, no child location / found in CL target
399 bit7= Invalid PN entry
400 bit8= Sparse files not supported
401 bit9= SP entry found in a directory entry other than '.' entry of root
402 bit10= ER entry found in a directory entry other than '.' entry of root
403 bit11= Invalid AA entry
404 bit12= Invalid AL entry
405 bit13= Invalid ZF entry
406 bit14= Rock Ridge PX entry is not present or invalid
407 bit15= Incomplete NM
408 bit16= Incomplete SL
409 bit17= Charset conversion error
410 bit18= Link without destination
411 bit19= SL with a non-link file
412 */
413 int rr_err_reported;
414 int rr_err_repeated;
415
416 size_t joliet_ucs2_failures;
417
418 } _ImageFsData;
419
420 typedef struct image_fs_data ImageFileSourceData;
421
422 /* IMPORTANT: Any change must be reflected by ifs_clone_src */
423 struct image_fs_data
424 {
425 IsoImageFilesystem *fs; /**< reference to the image it belongs to */
426 IsoFileSource *parent; /**< reference to the parent (NULL if root) */
427
428 struct stat info; /**< filled struct stat */
429 char *name; /**< name of this file */
430
431 /**
432 * Location of file extents.
433 */
434 struct iso_file_section *sections;
435 int nsections;
436
437 unsigned int opened : 2; /**< 0 not opened, 1 opened file, 2 opened dir */
438
439 #ifdef Libisofs_with_zliB
440 uint8_t zisofs_algo[2];
441 uint8_t header_size_div4;
442 uint8_t block_size_log2;
443 uint64_t uncompressed_size;
444 #endif
445
446 /* info for content reading */
447 struct
448 {
449 /**
450 * - For regular files, once opened it points to a temporary data
451 * buffer of 2048 bytes.
452 * - For dirs, once opened it points to a IsoFileSource* array with
453 * its children
454 * - For symlinks, it points to link destination
455 */
456 void *content;
457
458 /**
459 * - For regular files, number of bytes already read.
460 */
461 off_t offset;
462 } data;
463
464 /**
465 * malloc() storage for the string of AAIP fields which represent
466 * ACLs and XFS-style Extended Attributes. (Not to be confused with
467 * ECMA-119 Extended Attributes.)
468 */
469 unsigned char *aa_string;
470
471 };
472
473 struct child_list
474 {
475 IsoFileSource *file;
476 struct child_list *next;
477 };
478
child_list_free(struct child_list * list)479 void child_list_free(struct child_list *list)
480 {
481 struct child_list *temp;
482 struct child_list *next = list;
483 while (next != NULL) {
484 temp = next->next;
485 iso_file_source_unref(next->file);
486 free(next);
487 next = temp;
488 }
489 }
490
491 static
ifs_get_path(IsoFileSource * src)492 char* ifs_get_path(IsoFileSource *src)
493 {
494 ImageFileSourceData *data;
495 data = src->data;
496
497 if (data->parent == NULL) {
498 return strdup("");
499 } else {
500 char *path, *new_path;
501 int pathlen;
502
503 if (data->name == NULL)
504 return NULL;
505 path = ifs_get_path(data->parent);
506 if (path == NULL)
507 return NULL;
508 pathlen = strlen(path);
509 new_path = realloc(path, pathlen + strlen(data->name) + 2);
510 if (new_path == NULL) {
511 free(path);
512 return NULL;
513 }
514 path= new_path;
515 path[pathlen] = '/';
516 path[pathlen + 1] = '\0';
517 return strcat(path, data->name);
518 }
519 }
520
521 static
ifs_get_name(IsoFileSource * src)522 char* ifs_get_name(IsoFileSource *src)
523 {
524 ImageFileSourceData *data;
525 data = src->data;
526 return data->name == NULL ? NULL : strdup(data->name);
527 }
528
529 static
ifs_lstat(IsoFileSource * src,struct stat * info)530 int ifs_lstat(IsoFileSource *src, struct stat *info)
531 {
532 ImageFileSourceData *data;
533
534 if (src == NULL || info == NULL) {
535 return ISO_NULL_POINTER;
536 }
537
538 data = src->data;
539 if (data == NULL)
540 return ISO_NULL_POINTER;
541 *info = data->info;
542 return ISO_SUCCESS;
543 }
544
545 static
ifs_stat(IsoFileSource * src,struct stat * info)546 int ifs_stat(IsoFileSource *src, struct stat *info)
547 {
548 ImageFileSourceData *data;
549
550 if (src == NULL || info == NULL || src->data == NULL) {
551 return ISO_NULL_POINTER;
552 }
553
554 data = (ImageFileSourceData*)src->data;
555
556 if (S_ISLNK(data->info.st_mode)) {
557 /* TODO #00012 : support follow symlinks on image filesystem */
558 return ISO_FILE_BAD_PATH;
559 }
560 *info = data->info;
561 return ISO_SUCCESS;
562 }
563
564 static
ifs_access(IsoFileSource * src)565 int ifs_access(IsoFileSource *src)
566 {
567 /* we always have access, it is controlled by DataSource */
568 return ISO_SUCCESS;
569 }
570
571 /**
572 * Read all directory records in a directory, and creates an IsoFileSource for
573 * each of them, storing them in the data field of the IsoFileSource for the
574 * given dir.
575 */
576 static
read_dir(ImageFileSourceData * data)577 int read_dir(ImageFileSourceData *data)
578 {
579 int ret;
580 uint32_t size;
581 uint32_t block;
582 IsoImageFilesystem *fs;
583 _ImageFsData *fsdata;
584 struct ecma119_dir_record *record;
585 uint8_t *buffer = NULL;
586 IsoFileSource *child = NULL;
587 uint32_t pos = 0;
588 uint32_t tlen = 0;
589
590 if (data == NULL) {
591 ret = ISO_NULL_POINTER; goto ex;
592 }
593
594 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
595 fs = data->fs;
596 fsdata = fs->data;
597
598 /* a dir has always a single extent */
599 block = data->sections[0].block;
600 ret = fsdata->src->read_block(fsdata->src, block, buffer);
601 if (ret < 0) {
602 goto ex;
603 }
604
605 /* "." entry, get size of the dir and skip */
606 record = (struct ecma119_dir_record *)(buffer + pos);
607 size = iso_read_bb(record->length, 4, NULL);
608 tlen += record->len_dr[0];
609 pos += record->len_dr[0];
610
611 /* skip ".." */
612 record = (struct ecma119_dir_record *)(buffer + pos);
613 tlen += record->len_dr[0];
614 pos += record->len_dr[0];
615
616 while (tlen < size) {
617
618 record = (struct ecma119_dir_record *)(buffer + pos);
619 if (pos == 2048 || record->len_dr[0] == 0) {
620 /*
621 * The directory entries are split in several blocks
622 * read next block
623 */
624 ret = fsdata->src->read_block(fsdata->src, ++block, buffer);
625 if (ret < 0) {
626 goto ex;
627 }
628 tlen += 2048 - pos;
629 pos = 0;
630 continue;
631 }
632
633 /* (Vreixo:)
634 * What about ignoring files with existence flag?
635 * if (record->flags[0] & 0x01)
636 * continue;
637 * ts B20306 : >>> One should rather record that flag and write it
638 * >>> to the new image.
639 */
640
641 #ifdef Libisofs_wrongly_skip_rr_moveD
642 /* ts B20306 :
643 This skipping by name is wrong resp. redundant:
644 If no rr reading is enabled, then it is the only access point for
645 the content of relocated directories. So one should not ignore it.
646 If rr reading is enabled, then the RE entry of mkisofs' RR_MOVED
647 will cause it to be skipped.
648 */
649
650 /* (Vreixo:)
651 * For a extrange reason, mkisofs relocates directories under
652 * a RR_MOVED dir. It seems that it is only used for that purposes,
653 * and thus it should be removed from the iso tree before
654 * generating a new image with libisofs, that don't uses it.
655 */
656
657 if (data->parent == NULL && record->len_fi[0] == 8
658 && !strncmp((char*)record->file_id, "RR_MOVED", 8)) {
659
660 iso_msg_debug(fsdata->msgid, "Skipping RR_MOVE entry.");
661
662 tlen += record->len_dr[0];
663 pos += record->len_dr[0];
664 continue;
665 }
666
667 #endif /* Libisofs_wrongly_skip_rr_moveD */
668
669 /*
670 * We pass a NULL parent instead of dir, to prevent the circular
671 * reference from child to parent.
672 */
673 ret = iso_file_source_new_ifs(fs, NULL, record, &child, 0);
674 if (ret < 0) {
675 if (child) {
676 /*
677 * This can only happen with multi-extent files.
678 */
679 ImageFileSourceData *ifsdata = child->data;
680 free(ifsdata->sections);
681 free(ifsdata->name);
682 free(ifsdata);
683 free(child);
684 }
685 goto ex;
686 }
687
688 /* add to the child list */
689 if (ret == 1) {
690 struct child_list *node;
691 node = malloc(sizeof(struct child_list));
692 if (node == NULL) {
693 iso_file_source_unref(child);
694 {ret = ISO_OUT_OF_MEM; goto ex;}
695 }
696 /*
697 * Note that we insert in reverse order. This leads to faster
698 * addition here, but also when adding to the tree, as insertion
699 * will be done, sorted, in the first position of the list.
700 */
701 node->next = data->data.content;
702 node->file = child;
703 data->data.content = node;
704 child = NULL;
705 }
706
707 tlen += record->len_dr[0];
708 pos += record->len_dr[0];
709 }
710
711 ret = ISO_SUCCESS;
712 ex:;
713 LIBISO_FREE_MEM(buffer);
714 return ret;
715 }
716
717 static
ifs_open(IsoFileSource * src)718 int ifs_open(IsoFileSource *src)
719 {
720 int ret;
721 ImageFileSourceData *data;
722
723 if (src == NULL || src->data == NULL) {
724 return ISO_NULL_POINTER;
725 }
726 data = (ImageFileSourceData*)src->data;
727
728 if (data->opened) {
729 return ISO_FILE_ALREADY_OPENED;
730 }
731
732 if (S_ISDIR(data->info.st_mode)) {
733 /* ensure fs is opened */
734 ret = data->fs->open(data->fs);
735 if (ret < 0) {
736 return ret;
737 }
738
739 /*
740 * Cache all directory entries.
741 * This can waste more memory, but improves as disc is read in much more
742 * sequentially way, thus reducing jump between tracks on disc
743 */
744 ret = read_dir(data);
745 data->fs->close(data->fs);
746
747 if (ret < 0) {
748 /* free probably allocated children */
749 child_list_free((struct child_list*)data->data.content);
750 } else {
751 data->opened = 2;
752 }
753
754 return ret;
755 } else if (S_ISREG(data->info.st_mode)) {
756 /* ensure fs is opened */
757 ret = data->fs->open(data->fs);
758 if (ret < 0) {
759 return ret;
760 }
761 data->data.content = malloc(BLOCK_SIZE);
762 if (data->data.content == NULL) {
763 return ISO_OUT_OF_MEM;
764 }
765 data->data.offset = 0;
766 data->opened = 1;
767 } else {
768 /* symlinks and special files inside image can't be opened */
769 return ISO_FILE_ERROR;
770 }
771 return ISO_SUCCESS;
772 }
773
774 static
ifs_close(IsoFileSource * src)775 int ifs_close(IsoFileSource *src)
776 {
777 ImageFileSourceData *data;
778
779 if (src == NULL || src->data == NULL) {
780 return ISO_NULL_POINTER;
781 }
782 data = (ImageFileSourceData*)src->data;
783
784 if (!data->opened) {
785 return ISO_FILE_NOT_OPENED;
786 }
787
788 if (data->opened == 2) {
789 /*
790 * close a dir, free all pending pre-allocated children.
791 * not that we don't need to close the filesystem, it was already
792 * closed
793 */
794 child_list_free((struct child_list*) data->data.content);
795 data->data.content = NULL;
796 data->opened = 0;
797 } else if (data->opened == 1) {
798 /* close regular file */
799 free(data->data.content);
800 data->fs->close(data->fs);
801 data->data.content = NULL;
802 data->opened = 0;
803 } else {
804 /* TODO only dirs and files supported for now */
805 return ISO_ERROR;
806 }
807
808 return ISO_SUCCESS;
809 }
810
811 /**
812 * Computes the block where the given offset should start.
813 */
814 static
block_from_offset(int nsections,struct iso_file_section * sections,off_t offset)815 uint32_t block_from_offset(int nsections, struct iso_file_section *sections,
816 off_t offset)
817 {
818 int section = 0;
819 off_t bytes = 0;
820
821 do {
822 if ( (offset - bytes) < (off_t) sections[section].size ) {
823 return sections[section].block + (offset - bytes) / BLOCK_SIZE;
824 } else {
825 bytes += (off_t) sections[section].size;
826 section++;
827 }
828
829 } while(section < nsections);
830 return 0; /* should never happen */
831 }
832
833 /**
834 * Get the size available for reading on the corresponding block
835 */
836 static
size_available(int nsections,struct iso_file_section * sections,off_t offset)837 uint32_t size_available(int nsections, struct iso_file_section *sections,
838 off_t offset)
839 {
840 int section = 0;
841 off_t bytes = 0;
842
843 do {
844 if ( (offset - bytes) < (off_t) sections[section].size ) {
845 uint32_t curr_section_offset = (uint32_t)(offset - bytes);
846 uint32_t curr_section_left = sections[section].size - curr_section_offset;
847 uint32_t available = BLOCK_SIZE - curr_section_offset % BLOCK_SIZE;
848 return MIN(curr_section_left, available);
849 } else {
850 bytes += (off_t) sections[section].size;
851 section++;
852 }
853
854 } while(section < nsections);
855 return 0; /* should never happen */
856 }
857
858 /**
859 * Get the block offset for reading the given file offset
860 */
861 static
block_offset(int nsections,struct iso_file_section * sections,off_t offset)862 uint32_t block_offset(int nsections, struct iso_file_section *sections,
863 off_t offset)
864 {
865 int section = 0;
866 off_t bytes = 0;
867
868
869 do {
870 if ( (offset - bytes) < (off_t) sections[section].size ) {
871 return (uint32_t)(offset - bytes) % BLOCK_SIZE;
872 } else {
873 bytes += (off_t) sections[section].size;
874 section++;
875 }
876
877 } while(section < nsections);
878 return 0; /* should never happen */
879 }
880
881 /**
882 * Attempts to read up to count bytes from the given source into
883 * the buffer starting at buf.
884 *
885 * The file src must be open() before calling this, and close() when no
886 * more needed. Not valid for dirs. On symlinks it reads the destination
887 * file.
888 *
889 * @return
890 * number of bytes read, 0 if EOF, < 0 on error
891 * Error codes:
892 * ISO_FILE_ERROR
893 * ISO_NULL_POINTER
894 * ISO_FILE_NOT_OPENED
895 * ISO_FILE_IS_DIR
896 * ISO_OUT_OF_MEM
897 * ISO_INTERRUPTED
898 */
899 static
ifs_read(IsoFileSource * src,void * buf,size_t count)900 int ifs_read(IsoFileSource *src, void *buf, size_t count)
901 {
902 int ret;
903 ImageFileSourceData *data;
904 uint32_t read = 0;
905
906 if (src == NULL || src->data == NULL || buf == NULL) {
907 return ISO_NULL_POINTER;
908 }
909 if (count == 0) {
910 return ISO_WRONG_ARG_VALUE;
911 }
912 data = (ImageFileSourceData*)src->data;
913
914 if (!data->opened) {
915 return ISO_FILE_NOT_OPENED;
916 } else if (data->opened != 1) {
917 return ISO_FILE_IS_DIR;
918 }
919
920 while (read < count && data->data.offset < data->info.st_size) {
921 size_t bytes;
922 uint8_t *orig;
923
924 if (block_offset(data->nsections, data->sections, data->data.offset) == 0) {
925 /* we need to buffer next block */
926 uint32_t block;
927 _ImageFsData *fsdata;
928
929 if (data->data.offset >= data->info.st_size) {
930 /* EOF */
931 break;
932 }
933 fsdata = data->fs->data;
934 block = block_from_offset(data->nsections, data->sections,
935 data->data.offset);
936 ret = fsdata->src->read_block(fsdata->src, block,
937 data->data.content);
938 if (ret < 0) {
939 return ret;
940 }
941 }
942
943 /* how much can I read */
944 bytes = MIN(size_available(data->nsections, data->sections, data->data.offset),
945 count - read);
946 if (data->data.offset + (off_t)bytes > data->info.st_size) {
947 bytes = data->info.st_size - data->data.offset;
948 }
949 orig = data->data.content;
950 orig += block_offset(data->nsections, data->sections, data->data.offset);
951 memcpy((uint8_t*)buf + read, orig, bytes);
952 read += bytes;
953 data->data.offset += (off_t)bytes;
954 }
955 return read;
956 }
957
958 static
ifs_lseek(IsoFileSource * src,off_t offset,int flag)959 off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
960 {
961 ImageFileSourceData *data;
962
963 if (src == NULL) {
964 return (off_t)ISO_NULL_POINTER;
965 }
966 if (offset < (off_t)0) {
967 return (off_t)ISO_WRONG_ARG_VALUE;
968 }
969
970 data = src->data;
971
972 if (!data->opened) {
973 return (off_t)ISO_FILE_NOT_OPENED;
974 } else if (data->opened != 1) {
975 return (off_t)ISO_FILE_IS_DIR;
976 }
977
978 switch (flag) {
979 case 0: /* SEEK_SET */
980 data->data.offset = offset;
981 break;
982 case 1: /* SEEK_CUR */
983 data->data.offset += offset;
984 break;
985 case 2: /* SEEK_END */
986 /* do this make sense? */
987 data->data.offset = data->info.st_size + offset;
988 break;
989 default:
990 return (off_t)ISO_WRONG_ARG_VALUE;
991 }
992
993 /*
994 * We check for block_offset != 0 because if it is already 0, the block
995 * will be read from image in the read function
996 */
997 if (block_offset(data->nsections, data->sections, data->data.offset) != 0) {
998 /* we need to buffer the block */
999 uint32_t block;
1000 _ImageFsData *fsdata;
1001
1002 if (data->data.offset < data->info.st_size) {
1003 int ret;
1004 fsdata = data->fs->data;
1005 block = block_from_offset(data->nsections, data->sections,
1006 data->data.offset);
1007 ret = fsdata->src->read_block(fsdata->src, block,
1008 data->data.content);
1009 if (ret < 0) {
1010 return (off_t)ret;
1011 }
1012 }
1013 }
1014 return data->data.offset;
1015 }
1016
1017 static
ifs_readdir(IsoFileSource * src,IsoFileSource ** child)1018 int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
1019 {
1020 ImageFileSourceData *data, *cdata;
1021 struct child_list *children;
1022
1023 if (src == NULL || src->data == NULL || child == NULL) {
1024 return ISO_NULL_POINTER;
1025 }
1026 data = (ImageFileSourceData*)src->data;
1027
1028 if (!data->opened) {
1029 return ISO_FILE_NOT_OPENED;
1030 } else if (data->opened != 2) {
1031 return ISO_FILE_IS_NOT_DIR;
1032 }
1033
1034 /* return the first child and free it */
1035 if (data->data.content == NULL) {
1036 return 0; /* EOF */
1037 }
1038
1039 children = (struct child_list*)data->data.content;
1040 *child = children->file;
1041 cdata = (ImageFileSourceData*)(*child)->data;
1042
1043 /* set the ref to the parent */
1044 cdata->parent = src;
1045 iso_file_source_ref(src);
1046
1047 /* free the first element of the list */
1048 data->data.content = children->next;
1049 free(children);
1050
1051 return ISO_SUCCESS;
1052 }
1053
1054 /**
1055 * Read the destination of a symlink. You don't need to open the file
1056 * to call this.
1057 *
1058 * @param buf
1059 * allocated buffer of at least bufsiz bytes.
1060 * The dest. will be copied there, and it will be NULL-terminated
1061 * @param bufsiz
1062 * characters to be copied. Destination link will be truncated if
1063 * it is larger than given size. This include the \0 character.
1064 * @return
1065 * 1 on success, < 0 on error
1066 * Error codes:
1067 * ISO_FILE_ERROR
1068 * ISO_NULL_POINTER
1069 * ISO_WRONG_ARG_VALUE -> if bufsiz <= 0
1070 * ISO_FILE_IS_NOT_SYMLINK
1071 * ISO_OUT_OF_MEM
1072 * ISO_FILE_BAD_PATH
1073 * ISO_FILE_DOESNT_EXIST
1074 *
1075 */
1076 static
ifs_readlink(IsoFileSource * src,char * buf,size_t bufsiz)1077 int ifs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
1078 {
1079 char *dest;
1080 size_t len;
1081 int ret;
1082 ImageFileSourceData *data;
1083
1084 if (src == NULL || buf == NULL || src->data == NULL) {
1085 return ISO_NULL_POINTER;
1086 }
1087
1088 if (bufsiz <= 0) {
1089 return ISO_WRONG_ARG_VALUE;
1090 }
1091
1092 data = (ImageFileSourceData*)src->data;
1093
1094 if (!S_ISLNK(data->info.st_mode)) {
1095 return ISO_FILE_IS_NOT_SYMLINK;
1096 }
1097
1098 dest = (char*)data->data.content;
1099 len = strlen(dest);
1100
1101 ret = ISO_SUCCESS;
1102 if (len >= bufsiz) {
1103 ret = ISO_RR_PATH_TOO_LONG;
1104 len = bufsiz - 1;
1105 }
1106 strncpy(buf, dest, len);
1107 buf[len] = '\0';
1108 return ret;
1109 }
1110
1111 static
ifs_get_filesystem(IsoFileSource * src)1112 IsoFilesystem* ifs_get_filesystem(IsoFileSource *src)
1113 {
1114 ImageFileSourceData *data;
1115
1116 if (src == NULL) {
1117 return NULL;
1118 }
1119
1120 data = src->data;
1121 return data->fs;
1122 }
1123
1124 static
ifs_free(IsoFileSource * src)1125 void ifs_free(IsoFileSource *src)
1126 {
1127 ImageFileSourceData *data;
1128
1129 data = src->data;
1130
1131 /* close the file if it is already opened */
1132 if (data->opened) {
1133 src->class->close(src);
1134 }
1135
1136 /* free destination if it is a link */
1137 if (S_ISLNK(data->info.st_mode)) {
1138 free(data->data.content);
1139 }
1140 iso_filesystem_unref(data->fs);
1141 if (data->parent != NULL) {
1142 iso_file_source_unref(data->parent);
1143 }
1144
1145 free(data->sections);
1146 free(data->name);
1147 if (data->aa_string != NULL)
1148 free(data->aa_string);
1149 free(data);
1150 }
1151
1152
1153 static
ifs_get_aa_string(IsoFileSource * src,unsigned char ** aa_string,int flag)1154 int ifs_get_aa_string(IsoFileSource *src, unsigned char **aa_string, int flag)
1155 {
1156 size_t len;
1157 ImageFileSourceData *data;
1158
1159 data = src->data;
1160
1161 if ((flag & 1) || data->aa_string == NULL) {
1162 *aa_string = data->aa_string;
1163 data->aa_string = NULL;
1164 } else {
1165 len = aaip_count_bytes(data->aa_string, 0);
1166 *aa_string = calloc(len, 1);
1167 if (*aa_string == NULL)
1168 return ISO_OUT_OF_MEM;
1169 memcpy(*aa_string, data->aa_string, len);
1170 }
1171 return 1;
1172 }
1173
1174 static
ifs_clone_src(IsoFileSource * old_source,IsoFileSource ** new_source,int flag)1175 int ifs_clone_src(IsoFileSource *old_source,
1176 IsoFileSource **new_source, int flag)
1177 {
1178 IsoFileSource *src = NULL;
1179 ImageFileSourceData *old_data, *new_data = NULL;
1180 char *new_name = NULL;
1181 struct iso_file_section *new_sections = NULL;
1182 void *new_aa_string = NULL;
1183 int i, ret;
1184
1185 if (flag)
1186 return ISO_STREAM_NO_CLONE; /* unknown option required */
1187
1188 old_data = (ImageFileSourceData *) old_source->data;
1189 *new_source = NULL;
1190 src = calloc(1, sizeof(IsoFileSource));
1191 if (src == NULL)
1192 goto no_mem;
1193 new_name = strdup(old_data->name);
1194 if (new_name == NULL)
1195 goto no_mem;
1196 new_data = calloc(1, sizeof(ImageFileSourceData));
1197
1198 if (new_data == NULL)
1199 goto no_mem;
1200 if (old_data->nsections > 0) {
1201 new_sections = calloc(old_data->nsections,
1202 sizeof(struct iso_file_section));
1203 if (new_sections == NULL)
1204 goto no_mem;
1205 }
1206 ret = aaip_xinfo_cloner(old_data->aa_string, &new_aa_string, 0);
1207 if (ret < 0)
1208 goto no_mem;
1209
1210 new_data->fs = old_data->fs;
1211
1212 new_data->parent = old_data->parent;
1213
1214 memcpy(&(new_data->info), &(old_data->info), sizeof(struct stat));
1215 new_data->name = new_name;
1216 new_data->sections = new_sections;
1217 new_data->nsections = old_data->nsections;
1218 for (i = 0; i < new_data->nsections; i++)
1219 memcpy(new_data->sections + i, old_data->sections + i,
1220 sizeof(struct iso_file_section));
1221 new_data->opened = old_data->opened;
1222 #ifdef Libisofs_with_zliB
1223 new_data->header_size_div4 = old_data->header_size_div4;
1224 new_data->block_size_log2 = old_data->block_size_log2;
1225 new_data->uncompressed_size = old_data->uncompressed_size;
1226 #endif
1227 new_data->data.content = NULL;
1228 new_data->aa_string = (unsigned char *) new_aa_string;
1229
1230 src->class = old_source->class;
1231 src->refcount = 1;
1232 src->data = new_data;
1233 *new_source = src;
1234 iso_file_source_ref(new_data->parent);
1235 iso_filesystem_ref(new_data->fs);
1236 return ISO_SUCCESS;
1237 no_mem:;
1238 if (src != NULL)
1239 free((char *) src);
1240 if (new_data != NULL)
1241 free((char *) new_data);
1242 if (new_name != NULL)
1243 free(new_name);
1244 if (new_sections != NULL)
1245 free((char *) new_sections);
1246 if (new_aa_string != NULL)
1247 aaip_xinfo_func(new_aa_string, 1);
1248 return ISO_OUT_OF_MEM;
1249 }
1250
1251
1252 IsoFileSourceIface ifs_class = {
1253
1254 2, /* version */
1255 ifs_get_path,
1256 ifs_get_name,
1257 ifs_lstat,
1258 ifs_stat,
1259 ifs_access,
1260 ifs_open,
1261 ifs_close,
1262 ifs_read,
1263 ifs_readdir,
1264 ifs_readlink,
1265 ifs_get_filesystem,
1266 ifs_free,
1267 ifs_lseek,
1268 ifs_get_aa_string,
1269 ifs_clone_src
1270
1271 };
1272
1273
1274 /* Used from libisofs/stream.c : iso_stream_get_src_zf() */
iso_ifs_source_get_zf(IsoFileSource * src,uint8_t zisofs_algo[2],int * header_size_div4,int * block_size_log2,uint64_t * uncompressed_size,int flag)1275 int iso_ifs_source_get_zf(IsoFileSource *src, uint8_t zisofs_algo[2],
1276 int *header_size_div4, int *block_size_log2,
1277 uint64_t *uncompressed_size, int flag)
1278 {
1279
1280 #ifdef Libisofs_with_zliB
1281
1282 ImageFileSourceData *data;
1283
1284 if (src->class != &ifs_class)
1285 return 0;
1286 data = src->data;
1287 zisofs_algo[0] = data->zisofs_algo[0];
1288 zisofs_algo[1] = data->zisofs_algo[1];
1289 *header_size_div4 = data->header_size_div4;
1290 *block_size_log2 = data->block_size_log2;
1291 *uncompressed_size = data->uncompressed_size;
1292 return 1;
1293
1294 #else
1295
1296 return 0;
1297
1298 #endif /* ! Libisofs_with_zliB */
1299 }
1300
1301
1302 static
make_hopefully_unique_name(_ImageFsData * fsdata,char * str,size_t len,char ** name)1303 int make_hopefully_unique_name(_ImageFsData *fsdata,
1304 char *str, size_t len, char **name)
1305 {
1306 int ret, name_len, i;
1307 char c, *smashed = NULL, md5[16];
1308 void *md5_context = NULL;
1309
1310 /* Shorten so that 32 characters of MD5 fit.
1311 If shorter than 8, pad up to 8 by '_'.
1312 Smash characters to [0-9A-Za-z_.].
1313 Append MD5 of original str as hex digits.
1314 */
1315 name_len = len > 223 ? 223 : len;
1316 LIBISO_ALLOC_MEM(smashed, char, (name_len >= 8 ? name_len : 8) + 32 + 1);
1317 memcpy(smashed, str, name_len);
1318 for (; name_len < 8; name_len++)
1319 smashed[name_len] = '_';
1320 smashed[name_len] = 0;
1321 for (i = 0; i < name_len; i++) {
1322 c = smashed[i];
1323 if (c == '.' || (c >= '0' && c <= '9') ||
1324 c == '_' || (c >= 'a' && c <= 'z'))
1325 continue;
1326 smashed[i] = '_';
1327 }
1328 ret = iso_md5_start(&md5_context);
1329 if (ret != 1)
1330 goto ex;
1331 ret = iso_md5_compute(md5_context, str, len);
1332 if (ret != 1)
1333 goto ex;
1334 ret = iso_md5_end(&md5_context, md5);
1335 if (ret != 1)
1336 goto ex;
1337 for (i = 0; i < 16; i++)
1338 sprintf(smashed + i * 2 + name_len, "%2.2x",
1339 ((unsigned char *) md5)[i]);
1340 name_len += 32;
1341 smashed[name_len] = 0;
1342 *name = smashed; smashed = NULL;
1343
1344 ret = ISO_SUCCESS;
1345 ex:
1346 LIBISO_FREE_MEM(smashed);
1347 if (md5_context != NULL)
1348 iso_md5_end(&md5_context, md5);
1349 return ret;
1350 }
1351
1352
1353 /**
1354 * Read a file name from a directory record, doing the needed charset
1355 * conversion
1356 */
1357 static
get_name(_ImageFsData * fsdata,char * str,size_t len)1358 char *get_name(_ImageFsData *fsdata, char *str, size_t len)
1359 {
1360 int ret;
1361 char *name = NULL, *from_ucs = NULL;
1362
1363 if (strcmp(fsdata->local_charset, fsdata->input_charset)) {
1364 /* charset conversion needed */
1365 ret = strnconv(str, fsdata->input_charset, fsdata->local_charset, len,
1366 &name);
1367 if (ret == 1) {
1368 if (fsdata->iso_root_block == fsdata->svd_root_block) {
1369 /* Reading from Joliet : Check whether UTF-16 was needed */
1370 ret = strnconv(str, "UCS-2BE", fsdata->local_charset,
1371 len, &from_ucs);
1372 if (ret == 1)
1373 ret = (strcmp(name, from_ucs) == 0);
1374 if (ret != 1) {
1375 fsdata->joliet_ucs2_failures++;
1376 if (fsdata->joliet_ucs2_failures <=
1377 ISO_JOLIET_UCS2_WARN_MAX)
1378 iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
1379 "Joliet filename valid only with character set UTF-16 : \"%s\"",
1380 name);
1381
1382 }
1383 if (from_ucs != NULL)
1384 free(from_ucs);
1385 }
1386 return name;
1387 } else {
1388 ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET, ret,
1389 "Cannot convert from charset %s to %s",
1390 fsdata->input_charset, fsdata->local_charset);
1391 if (ret < 0) {
1392 return NULL; /* aborted */
1393 }
1394 /* fallback */
1395 ret = make_hopefully_unique_name(fsdata, str, len, &name);
1396 if (ret == ISO_SUCCESS)
1397 return name;
1398 return NULL;
1399 }
1400 }
1401
1402 /* we reach here when the charset conversion is not needed */
1403
1404 name = malloc(len + 1);
1405 if (name == NULL) {
1406 return NULL;
1407 }
1408 memcpy(name, str, len);
1409 name[len] = '\0';
1410 return name;
1411 }
1412
1413
1414 static
iso_rr_msg_submit(_ImageFsData * fsdata,int rr_err_bit,int errcode,int causedby,const char * msg)1415 int iso_rr_msg_submit(_ImageFsData *fsdata, int rr_err_bit,
1416 int errcode, int causedby, const char *msg)
1417 {
1418 int ret;
1419
1420 if ((fsdata->rr_err_reported & (1 << rr_err_bit)) &&
1421 (fsdata->rr_err_repeated & (1 << rr_err_bit))) {
1422 if (iso_msg_is_abort(errcode))
1423 return ISO_CANCELED;
1424 return 0;
1425 }
1426 if (fsdata->rr_err_reported & (1 << rr_err_bit)) {
1427 ret = iso_msg_submit(fsdata->msgid, errcode, causedby,
1428 "MORE THAN ONCE : %s", msg);
1429 fsdata->rr_err_repeated |= (1 << rr_err_bit);
1430 } else {
1431 ret = iso_msg_submit(fsdata->msgid, errcode, causedby, "%s", msg);
1432 fsdata->rr_err_reported |= (1 << rr_err_bit);
1433 }
1434 return ret;
1435 }
1436
1437
1438 /**
1439 *
1440 * @param src
1441 * if not-NULL, it points to a multi-extent file returned by a previous
1442 * call to this function.
1443 * @param flag
1444 * bit0= this is the root node attribute load call
1445 * (parameter parent is not reliable for this)
1446 * bit1= this is a call caused by CL. Do not obey CL again.
1447 * @return
1448 * 2 node is still incomplete (multi-extent)
1449 * 1 success, 0 record ignored (not an error, can be a relocated dir),
1450 * < 0 error
1451 */
1452 static
iso_file_source_new_ifs(IsoImageFilesystem * fs,IsoFileSource * parent,struct ecma119_dir_record * record,IsoFileSource ** src,int flag)1453 int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
1454 struct ecma119_dir_record *record,
1455 IsoFileSource **src, int flag)
1456 {
1457 int ret, ecma119_map, skip_nm = 0;
1458 struct stat atts;
1459 time_t recorded;
1460 _ImageFsData *fsdata;
1461 IsoFileSource *ifsrc = NULL;
1462 ImageFileSourceData *ifsdata = NULL;
1463
1464 int namecont = 0; /* 1 if found a NM with CONTINUE flag */
1465 char *name = NULL;
1466
1467 /* 1 if found a SL with CONTINUE flag,
1468 * 2 if found a component with continue flag */
1469 int linkdestcont = 0;
1470 char *linkdest = NULL;
1471
1472 uint32_t relocated_dir = 0;
1473
1474 unsigned char *aa_string = NULL;
1475 size_t aa_size = 0, aa_len = 0, prev_field = 0;
1476 int aa_done = 0;
1477 char *msg = NULL;
1478 uint8_t *buffer = NULL;
1479 char *cpt;
1480
1481 int has_px = 0;
1482
1483 #ifdef Libisofs_with_zliB
1484 uint8_t zisofs_alg[2], zisofs_hs4 = 0, zisofs_bsl2 = 0;
1485 uint64_t zisofs_usize = 0;
1486 #endif
1487
1488 if (fs == NULL || fs->data == NULL || record == NULL || src == NULL) {
1489 ret = ISO_NULL_POINTER; goto ex;
1490 }
1491
1492 fsdata = (_ImageFsData*)fs->data;
1493
1494 memset(&atts, 0, sizeof(struct stat));
1495 atts.st_nlink = 1;
1496
1497 /* Set preliminary file type */
1498 if (record->flags[0] & 0x02) {
1499 atts.st_mode = S_IFDIR;
1500 } else {
1501 atts.st_mode = S_IFREG;
1502 }
1503
1504 /*
1505 * First of all, check for unsupported ECMA-119 features
1506 */
1507
1508 /* check for unsupported interleaved mode */
1509 if (record->file_unit_size[0] || record->interleave_gap_size[0]) {
1510 iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
1511 "Unsupported image. This image has at least one file recorded "
1512 "in interleaved mode. We do not support this mode, as we think "
1513 "it is not used. If you are reading this, then we are wrong :) "
1514 "Please contact libisofs developers, so we can fix this.");
1515 {ret = ISO_UNSUPPORTED_ECMA119; goto ex;}
1516 }
1517
1518 /* TODO #00013 : check for unsupported flags when reading a dir record */
1519
1520 /*
1521 * If src is not-NULL, it refers to more extents of this file. We ensure
1522 * name matches, otherwise it means we are dealing with wrong image
1523 */
1524 if (*src != NULL) {
1525 ImageFileSourceData* data = (*src)->data;
1526 char* new_name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1527 if (new_name == NULL) {
1528 iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1529 "Cannot retrieve file name");
1530 {ret = ISO_WRONG_ECMA119; goto ex;}
1531 }
1532 if (strcmp(new_name, data->name)) {
1533 iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1534 "Multi-extent file lacks last entry.");
1535 free(new_name);
1536 {ret = ISO_WRONG_ECMA119; goto ex;}
1537 }
1538 free(new_name);
1539 }
1540
1541 /* check for multi-extent */
1542 if (record->flags[0] & 0x80) {
1543 iso_msg_debug(fsdata->msgid, "Found multi-extent file");
1544
1545 /*
1546 * Directory entries can only have one section (ECMA-119, 6.8.1)
1547 */
1548 if ((record->flags[0] & 0x02) || (flag & 1)) {
1549 iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1550 "Directories with more than one section are not allowed.");
1551 {ret = ISO_WRONG_ECMA119; goto ex;}
1552 }
1553
1554 if (*src == NULL) {
1555 ifsdata = calloc(1, sizeof(ImageFileSourceData));
1556 if (ifsdata == NULL) {
1557 ret = ISO_OUT_OF_MEM;
1558 goto ifs_cleanup;
1559 }
1560 ifsrc = calloc(1, sizeof(IsoFileSource));
1561 if (ifsrc == NULL) {
1562 ret = ISO_OUT_OF_MEM;
1563 goto ifs_cleanup;
1564 }
1565 ifsrc->data = ifsdata;
1566 ifsdata->name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1567 if (ifsdata->name == NULL) {
1568 iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1569 "Cannot retrieve file name");
1570 ret = ISO_WRONG_ECMA119;
1571 goto ifs_cleanup;
1572 }
1573
1574 *src = ifsrc;
1575 } else {
1576 ifsdata = (*src)->data;
1577 }
1578
1579 /* store current extent */
1580 ifsdata->sections = realloc(ifsdata->sections,
1581 (1 + ifsdata->nsections) * sizeof(struct iso_file_section));
1582 if (ifsdata->sections == NULL) {
1583 free(ifsdata->name);
1584 ret = ISO_OUT_OF_MEM;
1585 goto ifs_cleanup;
1586 }
1587 ifsdata->sections[ifsdata->nsections].block =
1588 iso_read_bb(record->block, 4, NULL) + record->len_xa[0];
1589 ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
1590
1591 ifsdata->info.st_size += (off_t) ifsdata->sections[ifsdata->nsections].size;
1592 ifsdata->nsections++;
1593 {ret = 2; goto ex;}
1594 }
1595
1596 /*
1597 * The idea is to read all the RR entries (if we want to do that and RR
1598 * extensions exist on image), storing the info we want from that.
1599 * Then, we need some sanity checks.
1600 * Finally, we select what kind of node it is, and set values properly.
1601 */
1602
1603 if (fsdata->rr) {
1604 struct susp_sys_user_entry *sue;
1605 SuspIterator *iter;
1606
1607
1608 iter = susp_iter_new(fsdata->src, record,
1609 fsdata->session_lba + fsdata->nblocks,
1610 fsdata->len_skp, fsdata->msgid);
1611 if (iter == NULL) {
1612 {ret = ISO_OUT_OF_MEM; goto ex;}
1613 }
1614
1615 while ((ret = susp_iter_next(iter, &sue, 0)) > 0) {
1616
1617 /* ignore entries from different version */
1618 if (sue->version[0] != 1 &&
1619 !(SUSP_SIG(sue, 'Z', 'F') || SUSP_SIG(sue, 'Z', '2')))
1620 continue;
1621
1622 if (SUSP_SIG(sue, 'P', 'X')) {
1623 has_px = 1;
1624 ret = read_rr_PX(sue, &atts);
1625 if (ret < 0) {
1626 /* notify and continue */
1627 ret = iso_rr_msg_submit(fsdata, 0, ISO_WRONG_RR_WARN, ret,
1628 "Invalid PX entry");
1629 fsdata->px_ino_status |= 8;
1630 } if (ret == 2) {
1631 if (fsdata->inode_counter < atts.st_ino)
1632 fsdata->inode_counter = atts.st_ino;
1633 fsdata->px_ino_status |= 1;
1634
1635 } else {
1636 fsdata->px_ino_status |= 2;
1637 }
1638
1639 } else if (SUSP_SIG(sue, 'T', 'F')) {
1640 ret = read_rr_TF(sue, &atts);
1641 if (ret < 0) {
1642 /* notify and continue */
1643 ret = iso_rr_msg_submit(fsdata, 1, ISO_WRONG_RR_WARN, ret,
1644 "Invalid TF entry");
1645 }
1646 } else if (SUSP_SIG(sue, 'N', 'M')) {
1647 if (skip_nm)
1648 continue; /* in NM error bailout mode */
1649
1650 if (name != NULL && namecont == 0) {
1651 /* ups, RR standard violation */
1652 ret = iso_rr_msg_submit(fsdata, 2, ISO_WRONG_RR_WARN, 0,
1653 "New NM entry found without previous"
1654 "CONTINUE flag. Ignored");
1655 skip_nm = 1;
1656 continue;
1657 }
1658 ret = read_rr_NM(sue, &name, &namecont);
1659 if (ret < 0) {
1660 /* notify and continue */
1661 ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret,
1662 "Invalid NM entry");
1663 continue;
1664 }
1665 if (name != NULL) if (strlen(name) > 4095) {
1666 /* Preliminarily truncate totally oversized name */
1667 ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret,
1668 "Totally oversized NM list");
1669 skip_nm = 1;
1670 continue;
1671 }
1672
1673 #ifdef Libisofs_syslinux_tesT
1674
1675 if (name != NULL && !namecont) {
1676 struct device syslinux_dev;
1677 struct iso_sb_info syslinux_sbi;
1678 struct fs_info syslinux_fsi;
1679 char *syslinux_name = NULL;
1680 int syslinux_name_len;
1681
1682 syslinux_dev.src = fsdata->src;
1683 memset(&(syslinux_sbi.root), 0, 256);
1684 syslinux_sbi.do_rr = 1;
1685 syslinux_sbi.susp_skip = 0;
1686 syslinux_fsi.fs_dev = &syslinux_dev;
1687 syslinux_fsi.fs_info = &syslinux_sbi;
1688 ret = susp_rr_get_nm(&syslinux_fsi, (char *) record,
1689 &syslinux_name, &syslinux_name_len);
1690 if (ret == 1) {
1691 if (name == NULL || syslinux_name == NULL)
1692 fprintf(stderr, "################ Hoppla. NULL\n");
1693 else if(strcmp(syslinux_name, name) != 0)
1694 fprintf(stderr,
1695 "################ libisofs '%s' != '%s' susp_rr_get_nm()\n",
1696 name, syslinux_name);
1697 } else if (ret == 0) {
1698 fprintf(stderr,
1699 "################ '%s' not found by susp_rr_get_nm()\n", name);
1700 } else {
1701 fprintf(stderr, "################ 'susp_rr_get_nm() returned error\n");
1702 }
1703 if (syslinux_name != NULL)
1704 free(syslinux_name);
1705
1706 }
1707
1708 #endif /* Libisofs_syslinux_tesT */
1709
1710
1711 } else if (SUSP_SIG(sue, 'S', 'L')) {
1712 if (linkdest != NULL && linkdestcont == 0) {
1713 /* ups, RR standard violation */
1714 ret = iso_rr_msg_submit(fsdata, 4, ISO_WRONG_RR_WARN, 0,
1715 "New SL entry found without previous"
1716 "CONTINUE flag. Ignored");
1717 continue;
1718 }
1719 ret = read_rr_SL(sue, &linkdest, &linkdestcont);
1720 if (ret < 0) {
1721 /* notify and continue */
1722 ret = iso_rr_msg_submit(fsdata, 5, ISO_WRONG_RR_WARN, ret,
1723 "Invalid SL entry");
1724 }
1725 } else if (SUSP_SIG(sue, 'R', 'E')) {
1726 /*
1727 * this directory entry refers to a relocated directory.
1728 * We simply ignore it, as it will be correctly handled
1729 * when found the CL
1730 */
1731 susp_iter_free(iter);
1732 free(name);
1733 if (flag & 1) {
1734 ret = iso_rr_msg_submit(fsdata, 3, ISO_NO_ROOT_DIR, 0,
1735 "Root directory is marked by RRIP RE as relocated");
1736 ret= ISO_NO_ROOT_DIR;
1737 goto ex;
1738 }
1739 {ret = 0; goto ex;} /* it's not an error */
1740 } else if (SUSP_SIG(sue, 'C', 'L') && (flag & 2)) {
1741 ret = iso_rr_msg_submit(fsdata, 6, ISO_WRONG_RR, 0,
1742 "Invalid CL entry, found in CL target");
1743
1744 } else if (SUSP_SIG(sue, 'C', 'L')) {
1745 /*
1746 * This entry is a placeholder for a relocated dir.
1747 * We need to ignore other entries, with the exception of NM.
1748 * Then we create a directory node that represents the
1749 * relocated dir, and iterate over its children.
1750 */
1751 relocated_dir = iso_read_bb(sue->data.CL.child_loc, 4, NULL);
1752 if (relocated_dir == 0) {
1753 ret = iso_rr_msg_submit(fsdata, 6, ISO_WRONG_RR, 0,
1754 "Invalid CL entry, no child location");
1755 break;
1756 }
1757 } else if (SUSP_SIG(sue, 'P', 'N')) {
1758 ret = read_rr_PN(sue, &atts);
1759 if (ret < 0) {
1760 /* notify and continue */
1761 ret = iso_rr_msg_submit(fsdata, 7, ISO_WRONG_RR_WARN, ret,
1762 "Invalid PN entry");
1763 }
1764 } else if (SUSP_SIG(sue, 'S', 'F')) {
1765 ret = iso_rr_msg_submit(fsdata, 8, ISO_UNSUPPORTED_RR, 0,
1766 "Sparse files not supported.");
1767 break;
1768 } else if (SUSP_SIG(sue, 'R', 'R')) {
1769 /* This was an optional flag byte in RRIP 1.09 which told the
1770 reader what other RRIP fields to expect.
1771 mkisofs emits it. We don't.
1772 */
1773 continue;
1774 } else if (SUSP_SIG(sue, 'S', 'P')) {
1775 /*
1776 * Ignore this, to prevent the hint message, if we are dealing
1777 * with root node (SP is only valid in "." of root node)
1778 */
1779 if (!(flag & 1)) {
1780 /* notify and continue */
1781 ret = iso_rr_msg_submit(fsdata, 9, ISO_WRONG_RR, 0,
1782 "SP entry found in a directory entry other "
1783 "than '.' entry of root node");
1784 }
1785 continue;
1786 } else if (SUSP_SIG(sue, 'E', 'R')) {
1787 /*
1788 * Ignore this, to prevent the hint message, if we are dealing
1789 * with root node (ER is only valid in "." of root node)
1790 */
1791 if (!(flag & 1)) {
1792 /* notify and continue */
1793 ret = iso_rr_msg_submit(fsdata, 10, ISO_WRONG_RR, 0,
1794 "ER entry found in a directory entry other "
1795 "than '.' entry of root node");
1796 }
1797 continue;
1798
1799 /* Need to read AA resp. AL in any case so it is available for
1800 S_IRWXG mapping in case that fsdata->aaip_load != 1
1801 */
1802 } else if (SUSP_SIG(sue, 'A', 'A')) {
1803
1804 ret = read_aaip_AA(sue, &aa_string, &aa_size, &aa_len,
1805 &prev_field, &aa_done, 0);
1806 if (ret < 0) {
1807 /* notify and continue */
1808 ret = iso_rr_msg_submit(fsdata, 11, ISO_WRONG_RR_WARN, ret,
1809 "Invalid AA entry");
1810 continue;
1811 }
1812
1813 } else if (SUSP_SIG(sue, 'A', 'L')) {
1814
1815 ret = read_aaip_AL(sue, &aa_string, &aa_size, &aa_len,
1816 &prev_field, &aa_done, 0);
1817 if (ret < 0) {
1818 /* notify and continue */
1819 ret = iso_rr_msg_submit(fsdata, 12, ISO_WRONG_RR_WARN, ret,
1820 "Invalid AL entry");
1821 continue;
1822 }
1823
1824 #ifdef Libisofs_with_zliB
1825
1826 } else if (SUSP_SIG(sue, 'Z', 'F') || SUSP_SIG(sue, 'Z', '2')) {
1827
1828 ret = read_zisofs_ZF(sue, zisofs_alg, &zisofs_hs4,
1829 &zisofs_bsl2, &zisofs_usize, 0);
1830 if (ret < 0) {
1831 invalid_zf:
1832 /* notify and continue */
1833 ret = iso_rr_msg_submit(fsdata, 13, ISO_WRONG_RR_WARN, ret,
1834 SUSP_SIG(sue, 'Z', 'F') ?
1835 "Invalid ZF entry" :
1836 "Invalid Z2 entry");
1837 zisofs_hs4 = 0;
1838 continue;
1839 }
1840 if (zisofs_alg[0] == 'p' || zisofs_alg[1] == 'z') {
1841 if (sue->version[0] != 1)
1842 goto invalid_zf;
1843 } else if (zisofs_alg[0] == 'P' || zisofs_alg[1] == 'Z') {
1844 if (sue->version[0] != 2)
1845 goto invalid_zf;
1846 } else {
1847 ret = 0;
1848 goto invalid_zf;
1849 }
1850
1851 #endif /* Libisofs_with_zliB */
1852
1853 /* This message is inflationary */
1854 /*
1855 } else {
1856 ret = iso_msg_submit(fsdata->msgid, ISO_SUSP_UNHANDLED, 0,
1857 "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]);
1858 */
1859
1860 }
1861 }
1862
1863 susp_iter_free(iter);
1864
1865 /* check for RR problems */
1866
1867 if (ret < 0) {
1868 /* error was already submitted above */
1869 iso_msg_debug(fsdata->msgid, "Error parsing RR entries");
1870 } else if (!relocated_dir && atts.st_mode == (mode_t) 0 ) {
1871 ret = iso_rr_msg_submit(fsdata, 14, ISO_WRONG_RR, 0, "Mandatory "
1872 "Rock Ridge PX entry is not present or it "
1873 "contains invalid values.");
1874 } else {
1875 /* ensure both name and link dest are finished */
1876 if (namecont != 0) {
1877 ret = iso_rr_msg_submit(fsdata, 15, ISO_WRONG_RR, 0,
1878 "Incomplete Rock Ridge name, last NM entry continues");
1879 }
1880 if (linkdestcont != 0) {
1881 ret = iso_rr_msg_submit(fsdata, 16, ISO_WRONG_RR, 0,
1882 "Incomplete link destination, last SL entry continues");
1883 }
1884 }
1885
1886 if (ret < 0) {
1887 free(name);
1888 goto ex;
1889 }
1890
1891 /* convert name to needed charset */
1892 if (strcmp(fsdata->input_charset, fsdata->local_charset) && name) {
1893 /* we need to convert name charset */
1894 char *newname = NULL;
1895 ret = strconv(name, fsdata->input_charset, fsdata->local_charset,
1896 &newname);
1897 if (ret < 0) {
1898 /* its just a hint message */
1899 LIBISO_FREE_MEM(msg);
1900 LIBISO_ALLOC_MEM(msg, char, 160);
1901 sprintf(msg,
1902 "Cannot convert from charset %.40s to %.40s",
1903 fsdata->input_charset, fsdata->local_charset);
1904 ret = iso_rr_msg_submit(fsdata, 17, ISO_FILENAME_WRONG_CHARSET,
1905 ret, msg);
1906 free(newname);
1907 if (ret < 0) {
1908 free(name);
1909 goto ex;
1910 }
1911 } else {
1912 free(name);
1913 name = newname;
1914 }
1915 }
1916
1917 /* convert link destination to needed charset */
1918 if (strcmp(fsdata->input_charset, fsdata->local_charset) && linkdest) {
1919 /* we need to convert name charset */
1920 char *newlinkdest = NULL;
1921 ret = strconv(linkdest, fsdata->input_charset,
1922 fsdata->local_charset, &newlinkdest);
1923 if (ret < 0) {
1924 LIBISO_FREE_MEM(msg);
1925 LIBISO_ALLOC_MEM(msg, char, 160);
1926 sprintf(msg,
1927 "Charset conversion error. Cannot convert from %.40s to %.40s",
1928 fsdata->input_charset, fsdata->local_charset);
1929 ret = iso_rr_msg_submit(fsdata, 17, ISO_FILENAME_WRONG_CHARSET,
1930 ret, msg);
1931 free(newlinkdest);
1932 if (ret < 0) {
1933 free(name);
1934 goto ex;
1935 }
1936 } else {
1937 free(linkdest);
1938 linkdest = newlinkdest;
1939 }
1940 }
1941
1942 } else {
1943 /* RR extensions are not read / used */
1944 atts.st_gid = fsdata->gid;
1945 atts.st_uid = fsdata->uid;
1946 if (record->flags[0] & 0x02) {
1947 atts.st_mode = S_IFDIR | fsdata->dir_mode;
1948 } else {
1949 atts.st_mode = S_IFREG | fsdata->file_mode;
1950 }
1951 }
1952
1953 if (!has_px) {
1954 fsdata->px_ino_status |= 4;
1955 }
1956
1957 /*
1958 * if we haven't RR extensions, or no NM entry is present,
1959 * we use the name in directory record
1960 */
1961 if (!name) {
1962 size_t len;
1963
1964 if (record->len_fi[0] == 1 && record->file_id[0] == 0) {
1965 /* "." entry, we can call this for root node, so... */
1966 if (!(atts.st_mode & S_IFDIR)) {
1967 ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1968 "Wrong ISO file name. \".\" not dir");
1969 goto ex;
1970 }
1971 } else {
1972
1973 name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1974 if (name == NULL) {
1975 ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1976 "Cannot retrieve file name");
1977 goto ex;
1978 }
1979
1980 /* remove trailing version number */
1981 len = strlen(name);
1982 if (fsdata->iso_root_block == fsdata->svd_root_block)
1983 ecma119_map = fsdata->joliet_map;
1984 else
1985 ecma119_map = fsdata->ecma119_map;
1986 if (ecma119_map >= 1 && ecma119_map <= 3 &&
1987 len > 2 && name[len-2] == ';' && name[len-1] == '1') {
1988 if (len > 3 && name[len-3] == '.') {
1989 /*
1990 * the "." is mandatory, so in most cases is included only
1991 * for standard compliance
1992 */
1993 name[len-3] = '\0';
1994 } else {
1995 name[len-2] = '\0';
1996 }
1997 }
1998
1999 if (ecma119_map == 2 || ecma119_map == 3) {
2000 for (cpt = name; *cpt != 0; cpt++) {
2001 if (ecma119_map == 2) {
2002 if (islower(*cpt))
2003 *cpt = toupper(*cpt);
2004 } else {
2005 if (isupper(*cpt))
2006 *cpt = tolower(*cpt);
2007 }
2008 }
2009 }
2010
2011 }
2012 }
2013
2014 if (name != NULL) {
2015 if ((int) strlen(name) > fsdata->truncate_length) {
2016 ret = iso_truncate_rr_name(fsdata->truncate_mode,
2017 fsdata->truncate_length, name, 0);
2018 if (ret < 0)
2019 goto ex;
2020 }
2021 }
2022
2023 if (relocated_dir) {
2024
2025 /*
2026 * We are dealing with a placeholder for a relocated dir.
2027 * Thus, we need to read attributes for this directory from the "."
2028 * entry of the relocated dir.
2029 */
2030
2031 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2032 ret = fsdata->src->read_block(fsdata->src, relocated_dir, buffer);
2033 if (ret < 0) {
2034 goto ex;
2035 }
2036
2037 /* Call with flag bit1 to prevent further CL relocation */
2038 ret = iso_file_source_new_ifs(fs, parent, (struct ecma119_dir_record*)
2039 buffer, src, flag | 2);
2040 if (ret <= 0) {
2041 goto ex;
2042 }
2043
2044 /* but the real name is the name of the placeholder */
2045 ifsdata = (ImageFileSourceData*) (*src)->data;
2046 if (ifsdata->name != NULL)
2047 free(ifsdata->name);
2048 ifsdata->name = name;
2049
2050 {ret = ISO_SUCCESS; goto ex;}
2051 }
2052
2053 /* Production of missing inode numbers is delayed until the image is
2054 complete. Then all nodes which shall get a new inode number will
2055 be served.
2056 */
2057
2058 /*
2059 * if we haven't RR extensions, or a needed TF time stamp is not present,
2060 * we use plain iso recording time
2061 */
2062 recorded = iso_datetime_read_7(record->recording_time);
2063 if (atts.st_atime == (time_t) 0) {
2064 atts.st_atime = recorded;
2065 }
2066 if (atts.st_ctime == (time_t) 0) {
2067 atts.st_ctime = recorded;
2068 }
2069 if (atts.st_mtime == (time_t) 0) {
2070 atts.st_mtime = recorded;
2071 }
2072
2073 /* the size is read from iso directory record */
2074 atts.st_size = iso_read_bb(record->length, 4, NULL);
2075
2076 /* Fill last entries */
2077 atts.st_dev = fsdata->id;
2078 atts.st_blksize = BLOCK_SIZE;
2079 atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
2080
2081 /* TODO #00014 : more sanity checks to ensure dir record info is valid */
2082 if (S_ISLNK(atts.st_mode) && (linkdest == NULL)) {
2083 ret = iso_rr_msg_submit(fsdata, 18, ISO_WRONG_RR, 0,
2084 "Link without destination.");
2085 free(name);
2086 goto ex;
2087 }
2088
2089 /* ok, we can now create the file source */
2090 if (*src == NULL) {
2091 ifsdata = calloc(1, sizeof(ImageFileSourceData));
2092 if (ifsdata == NULL) {
2093 ret = ISO_OUT_OF_MEM;
2094 goto ifs_cleanup;
2095 }
2096 ifsrc = calloc(1, sizeof(IsoFileSource));
2097 if (ifsrc == NULL) {
2098 ret = ISO_OUT_OF_MEM;
2099 goto ifs_cleanup;
2100 }
2101 } else {
2102 ifsdata = (*src)->data;
2103 ifsrc = (*src);
2104 free(ifsdata->name); /* we will assign a new one */
2105 ifsdata->name = NULL;
2106 atts.st_size += (off_t)ifsdata->info.st_size;
2107 if (ifsdata->aa_string != NULL)
2108 free(ifsdata->aa_string);
2109 ifsdata->aa_string = NULL;
2110 }
2111
2112 /* fill data */
2113 ifsdata->fs = fs;
2114 iso_filesystem_ref(fs);
2115 if (parent != NULL) {
2116 ifsdata->parent = parent;
2117 iso_file_source_ref(parent);
2118 }
2119 ifsdata->info = atts;
2120 ifsdata->name = name;
2121 ifsdata->aa_string = aa_string;
2122
2123 #ifdef Libisofs_with_zliB
2124 if (zisofs_hs4 > 0) {
2125 ifsdata->zisofs_algo[0] = zisofs_alg[0];
2126 ifsdata->zisofs_algo[1] = zisofs_alg[1];
2127 ifsdata->header_size_div4 = zisofs_hs4;
2128 ifsdata->block_size_log2 = zisofs_bsl2;
2129 ifsdata->uncompressed_size = zisofs_usize;
2130 } else {
2131 ifsdata->header_size_div4 = 0;
2132 }
2133 #endif
2134
2135 /* save extents */
2136 ifsdata->sections = realloc(ifsdata->sections,
2137 (1 + ifsdata->nsections) * sizeof(struct iso_file_section));
2138 if (ifsdata->sections == NULL) {
2139 free(ifsdata->name);
2140 ret = ISO_OUT_OF_MEM;
2141 goto ifs_cleanup;
2142 }
2143 ifsdata->sections[ifsdata->nsections].block =
2144 iso_read_bb(record->block, 4, NULL) + record->len_xa[0];
2145 ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
2146 ifsdata->nsections++;
2147
2148 if (S_ISLNK(atts.st_mode)) {
2149 ifsdata->data.content = linkdest;
2150 } else if (linkdest != NULL) {
2151 ret = iso_rr_msg_submit(fsdata, 19, ISO_WRONG_RR_WARN, 0,
2152 "RRIP SL link destination with file that is not a link.");
2153 free(linkdest);
2154 linkdest = NULL;
2155 }
2156
2157 ifsrc->class = &ifs_class;
2158 ifsrc->data = ifsdata;
2159 ifsrc->refcount = 1;
2160
2161 *src = ifsrc;
2162 {ret = ISO_SUCCESS; goto ex;}
2163
2164 ifs_cleanup: ;
2165 free(name);
2166 free(linkdest);
2167 free(ifsdata);
2168 free(ifsrc);
2169
2170 ex:;
2171 LIBISO_FREE_MEM(msg);
2172 LIBISO_FREE_MEM(buffer);
2173 return ret;
2174 }
2175
2176 static
ifs_get_root(IsoFilesystem * fs,IsoFileSource ** root)2177 int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root)
2178 {
2179 int ret;
2180 _ImageFsData *data;
2181 uint8_t *buffer = NULL;
2182
2183 if (fs == NULL || fs->data == NULL || root == NULL) {
2184 ret = ISO_NULL_POINTER; goto ex;
2185 }
2186
2187 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2188 data = (_ImageFsData*)fs->data;
2189
2190 /* open the filesystem */
2191 ret = ifs_fs_open((IsoImageFilesystem*)fs);
2192 if (ret < 0) {
2193 goto ex;
2194 }
2195
2196 /* read extend for root record */
2197 ret = data->src->read_block(data->src, data->iso_root_block, buffer);
2198 if (ret < 0) {
2199 ifs_fs_close((IsoImageFilesystem*)fs);
2200 goto ex;
2201 }
2202
2203 /* get root attributes from "." entry */
2204 *root = NULL;
2205 ret = iso_file_source_new_ifs((IsoImageFilesystem*)fs, NULL,
2206 (struct ecma119_dir_record*) buffer, root, 1);
2207
2208 ifs_fs_close((IsoImageFilesystem*)fs);
2209 ex:;
2210 LIBISO_FREE_MEM(buffer);
2211 return ret;
2212 }
2213
2214 /**
2215 * Find a file inside a node.
2216 *
2217 * @param file
2218 * it is not modified if requested file is not found
2219 * @return
2220 * 1 success, 0 not found, < 0 error
2221 */
2222 static
ifs_get_file(IsoFileSource * dir,const char * name,IsoFileSource ** file)2223 int ifs_get_file(IsoFileSource *dir, const char *name, IsoFileSource **file)
2224 {
2225 int ret;
2226 IsoFileSource *src;
2227
2228 ret = iso_file_source_open(dir);
2229 if (ret < 0) {
2230 return ret;
2231 }
2232 while ((ret = iso_file_source_readdir(dir, &src)) == 1) {
2233 char *fname = iso_file_source_get_name(src);
2234 if (!strcmp(name, fname)) {
2235 free(fname);
2236 *file = src;
2237 ret = ISO_SUCCESS;
2238 break;
2239 }
2240 free(fname);
2241 iso_file_source_unref(src);
2242 }
2243 iso_file_source_close(dir);
2244 return ret;
2245 }
2246
2247 static
ifs_get_by_path(IsoFilesystem * fs,const char * path,IsoFileSource ** file)2248 int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
2249 {
2250 int ret;
2251 IsoFileSource *src = NULL;
2252 char *ptr, *brk_info, *component;
2253
2254 if (fs == NULL || fs->data == NULL || path == NULL || file == NULL) {
2255 return ISO_NULL_POINTER;
2256 }
2257
2258 if (path[0] != '/') {
2259 /* only absolute paths supported */
2260 return ISO_FILE_BAD_PATH;
2261 }
2262
2263 /* open the filesystem */
2264 ret = ifs_fs_open((IsoImageFilesystem*)fs);
2265 if (ret < 0) {
2266 return ret;
2267 }
2268
2269 ret = ifs_get_root(fs, &src);
2270 if (ret < 0) {
2271 return ret;
2272 }
2273 if (!strcmp(path, "/")) {
2274 /* we are looking for root */
2275 *file = src;
2276 ret = ISO_SUCCESS;
2277 goto get_path_exit;
2278 }
2279
2280 ptr = strdup(path);
2281 if (ptr == NULL) {
2282 iso_file_source_unref(src);
2283 ret = ISO_OUT_OF_MEM;
2284 goto get_path_exit;
2285 }
2286
2287 component = strtok_r(ptr, "/", &brk_info);
2288 while (component) {
2289 IsoFileSource *child = NULL;
2290
2291 ImageFileSourceData *fdata;
2292 fdata = src->data;
2293 if (!S_ISDIR(fdata->info.st_mode)) {
2294 ret = ISO_FILE_BAD_PATH;
2295 break;
2296 }
2297
2298 ret = ifs_get_file(src, component, &child);
2299 iso_file_source_unref(src);
2300 src = NULL;
2301 if (ret <= 0) {
2302 break;
2303 }
2304
2305 src = child;
2306 component = strtok_r(NULL, "/", &brk_info);
2307 }
2308
2309 free(ptr);
2310 if (ret < 0) {
2311 if (src != NULL)
2312 iso_file_source_unref(src);
2313 } else if (ret == 0) {
2314 ret = ISO_FILE_DOESNT_EXIST;
2315 } else {
2316 *file = src;
2317 }
2318
2319 get_path_exit:;
2320 ifs_fs_close((IsoImageFilesystem*)fs);
2321 return ret;
2322 }
2323
ifs_get_id(IsoFilesystem * fs)2324 unsigned int ifs_get_id(IsoFilesystem *fs)
2325 {
2326 return ISO_IMAGE_FS_ID;
2327 }
2328
2329 static
ifs_fs_open(IsoImageFilesystem * fs)2330 int ifs_fs_open(IsoImageFilesystem *fs)
2331 {
2332 _ImageFsData *data;
2333
2334 if (fs == NULL || fs->data == NULL) {
2335 return ISO_NULL_POINTER;
2336 }
2337
2338 data = (_ImageFsData*)fs->data;
2339
2340 if (data->open_count == 0) {
2341 /* we need to actually open the data source */
2342 int res = data->src->open(data->src);
2343 if (res < 0) {
2344 return res;
2345 }
2346 }
2347 ++data->open_count;
2348 return ISO_SUCCESS;
2349 }
2350
2351 static
ifs_fs_close(IsoImageFilesystem * fs)2352 int ifs_fs_close(IsoImageFilesystem *fs)
2353 {
2354 _ImageFsData *data;
2355
2356 if (fs == NULL || fs->data == NULL) {
2357 return ISO_NULL_POINTER;
2358 }
2359
2360 data = (_ImageFsData*)fs->data;
2361
2362 if (--data->open_count == 0) {
2363 /* we need to actually close the data source */
2364 return data->src->close(data->src);
2365 }
2366 return ISO_SUCCESS;
2367 }
2368
2369 static
ifs_fs_free(IsoFilesystem * fs)2370 void ifs_fs_free(IsoFilesystem *fs)
2371 {
2372 _ImageFsData *data;
2373
2374 data = (_ImageFsData*) fs->data;
2375
2376 /* close data source if already opened */
2377 if (data->open_count > 0) {
2378 data->src->close(data->src);
2379 }
2380
2381 /* free our ref to datasource */
2382 iso_data_source_unref(data->src);
2383
2384 /* free volume atts */
2385 free(data->volset_id);
2386 free(data->volume_id);
2387 free(data->publisher_id);
2388 free(data->data_preparer_id);
2389 free(data->system_id);
2390 free(data->application_id);
2391 free(data->copyright_file_id);
2392 free(data->abstract_file_id);
2393 free(data->biblio_file_id);
2394 free(data->creation_time);
2395 free(data->modification_time);
2396 free(data->expiration_time);
2397 free(data->effective_time);
2398 free(data->input_charset);
2399 free(data->local_charset);
2400
2401 if(data->catcontent != NULL)
2402 free(data->catcontent);
2403
2404 free(data);
2405 }
2406
2407 /**
2408 * Read the SUSP system user entries of the "." entry of the root directory,
2409 * identifying when Rock Ridge extensions are being used.
2410 *
2411 * @return
2412 * 1 success, 0 ignored, < 0 error
2413 */
2414 static
read_root_susp_entries(_ImageFsData * data,uint32_t block)2415 int read_root_susp_entries(_ImageFsData *data, uint32_t block)
2416 {
2417 int ret;
2418 unsigned char *buffer = NULL;
2419 struct ecma119_dir_record *record;
2420 struct susp_sys_user_entry *sue;
2421 SuspIterator *iter;
2422
2423 LIBISO_ALLOC_MEM(buffer, unsigned char, 2048);
2424 ret = data->src->read_block(data->src, block, buffer);
2425 if (ret < 0) {
2426 goto ex;
2427 }
2428
2429 /* record will be the "." directory entry for the root record */
2430 record = (struct ecma119_dir_record *)buffer;
2431
2432 #ifdef Libisofs_syslinux_tesT
2433
2434 {
2435 struct device syslinux_dev;
2436 struct iso_sb_info syslinux_sbi;
2437 struct fs_info syslinux_fsi;
2438
2439 syslinux_dev.src = data->src;
2440 memcpy(&(syslinux_sbi.root), (char *) record, 256);
2441 syslinux_sbi.do_rr = 1;
2442 syslinux_sbi.susp_skip = 0;
2443 syslinux_fsi.fs_dev = &syslinux_dev;
2444 syslinux_fsi.fs_info = &syslinux_sbi;
2445
2446 ret = susp_rr_check_signatures(&syslinux_fsi, 1);
2447 fprintf(stderr, "--------- susp_rr_check_signatures == %d , syslinux_sbi.do_rr == %d\n", ret, syslinux_sbi.do_rr);
2448 }
2449
2450 #endif /* Libisofs_syslinux_tesT */
2451
2452
2453 /*
2454 * TODO #00015 : take care of CD-ROM XA discs when reading SP entry
2455 * SUSP specification claims that for CD-ROM XA the SP entry
2456 * is not at position BP 1, but at BP 15. Is that used?
2457 * In that case, we need to set info->len_skp to 15!!
2458 */
2459
2460 iter = susp_iter_new(data->src, record, data->session_lba + data->nblocks,
2461 data->len_skp, data->msgid);
2462 if (iter == NULL) {
2463 ret = ISO_OUT_OF_MEM; goto ex;
2464 }
2465
2466 /* first entry must be an SP system use entry */
2467 ret = susp_iter_next(iter, &sue, 1);
2468 if (ret < 0) {
2469 /* error */
2470 susp_iter_free(iter);
2471 goto ex;
2472 } else if (ret == 0 || !SUSP_SIG(sue, 'S', 'P') ) {
2473 iso_msg_debug(data->msgid, "SUSP/RR is not being used.");
2474 susp_iter_free(iter);
2475 {ret = ISO_SUCCESS; goto ex;}
2476 }
2477
2478 /* it is a SP system use entry */
2479 if (sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
2480 || sue->data.SP.ef[0] != 0xEF) {
2481
2482 susp_iter_free(iter);
2483 ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_SUSP, 0,
2484 "SUSP SP system use entry seems to be wrong. "
2485 "Ignoring Rock Ridge Extensions.");
2486 goto ex;
2487 }
2488
2489 iso_msg_debug(data->msgid, "SUSP/RR is being used.");
2490
2491 /*
2492 * The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the
2493 * number of bytes to be skipped within each System Use field.
2494 * I think this will be always 0, but given that support this standard
2495 * feature is easy...
2496 */
2497 data->len_skp = sue->data.SP.len_skp[0];
2498
2499 /*
2500 * Ok, now search for ER entry.
2501 * Just notice that the attributes for root dir are read elsewhere.
2502 *
2503 * TODO #00016 : handle non RR ER entries
2504 *
2505 * if several ER are present, we need to identify the position of
2506 * what refers to RR, and then look for corresponding ES entry in
2507 * each directory record. I have not implemented this (it's not used,
2508 * no?), but if we finally need it, it can be easily implemented in
2509 * the iterator, transparently for the rest of the code.
2510 */
2511 while ((ret = susp_iter_next(iter, &sue, 0)) > 0) {
2512
2513 /* ignore entries from different version */
2514 if (sue->version[0] != 1)
2515 continue;
2516
2517 if (SUSP_SIG(sue, 'E', 'R')) {
2518 /*
2519 * it seems that Rock Ridge can be identified with any
2520 * of the following
2521 */
2522 if ( sue->data.ER.len_id[0] == 10 &&
2523 !strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) {
2524
2525 iso_msg_debug(data->msgid,
2526 "Suitable Rock Ridge ER found. Version 1.10.");
2527 data->rr_version = RR_EXT_110;
2528
2529 } else if ( (sue->data.ER.len_id[0] == 10 &&
2530 !strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10))
2531 || (sue->data.ER.len_id[0] == 9 &&
2532 !strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9)) ) {
2533
2534 iso_msg_debug(data->msgid,
2535 "Suitable Rock Ridge ER found. Version 1.12.");
2536 data->rr_version = RR_EXT_112;
2537
2538 } else if (sue->data.ER.len_id[0] == 9 &&
2539 (strncmp((char*)sue->data.ER.ext_id, "AAIP_0002", 9) == 0 ||
2540 strncmp((char*)sue->data.ER.ext_id, "AAIP_0100", 9) == 0 ||
2541 strncmp((char*)sue->data.ER.ext_id, "AAIP_0200", 9) == 0)) {
2542
2543 /* Tolerate AAIP ER even if not supported */
2544 iso_msg_debug(data->msgid, "Suitable AAIP ER found.");
2545
2546 if (strncmp((char*)sue->data.ER.ext_id, "AAIP_0200", 9) == 0)
2547 data->aaip_version = 200;
2548 else if (((char*)sue->data.ER.ext_id)[6] == '1')
2549 data->aaip_version = 100;
2550 else
2551 data->aaip_version = 2;
2552 if (!data->aaip_load)
2553 iso_msg_submit(data->msgid, ISO_AAIP_IGNORED, 0,
2554 "Identifier for extension AAIP found, but loading is not enabled.");
2555
2556 } else {
2557 ret = iso_msg_submit(data->msgid, ISO_SUSP_MULTIPLE_ER, 0,
2558 "Unknown Extension Signature found in ER.\n"
2559 "It will be ignored, but can cause problems in "
2560 "image reading. Please notify us about this.");
2561 if (ret < 0) {
2562 break;
2563 }
2564 }
2565 }
2566 }
2567
2568 susp_iter_free(iter);
2569
2570 if (ret < 0) {
2571 goto ex;
2572 }
2573
2574 ret = ISO_SUCCESS;
2575 ex:
2576 LIBISO_FREE_MEM(buffer);
2577 return ret;
2578 }
2579
2580 static
read_pvd_block(IsoDataSource * src,uint32_t block,uint8_t * buffer,uint32_t * image_size)2581 int read_pvd_block(IsoDataSource *src, uint32_t block, uint8_t *buffer,
2582 uint32_t *image_size)
2583 {
2584 int ret;
2585 struct ecma119_pri_vol_desc *pvm;
2586
2587 ret = src->read_block(src, block, buffer);
2588 if (ret < 0)
2589 return ret;
2590 pvm = (struct ecma119_pri_vol_desc *)buffer;
2591
2592 /* sanity checks */
2593 if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
2594 || strncmp((char*)pvm->std_identifier, "CD001", 5)
2595 || pvm->file_structure_version[0] != 1) {
2596
2597 return ISO_WRONG_PVD;
2598 }
2599 if (image_size != NULL)
2600 *image_size = iso_read_bb(pvm->vol_space_size, 4, NULL);
2601 return ISO_SUCCESS;
2602 }
2603
2604 static
read_pvm(_ImageFsData * data,uint32_t block)2605 int read_pvm(_ImageFsData *data, uint32_t block)
2606 {
2607 int ret;
2608 struct ecma119_pri_vol_desc *pvm;
2609 struct ecma119_dir_record *rootdr;
2610 uint8_t *buffer = NULL;
2611
2612 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2613 ret = read_pvd_block(data->src, block, buffer, NULL);
2614 if (ret < 0)
2615 goto ex;
2616 /* ok, it is a valid PVD */
2617 pvm = (struct ecma119_pri_vol_desc *)buffer;
2618
2619 /* fill volume attributes */
2620 /* TODO take care of input charset */
2621 data->volset_id = iso_util_strcopy_untail((char*)pvm->vol_set_id, 128);
2622 data->volume_id = iso_util_strcopy_untail((char*)pvm->volume_id, 32);
2623 data->publisher_id =
2624 iso_util_strcopy_untail((char*)pvm->publisher_id, 128);
2625 data->data_preparer_id =
2626 iso_util_strcopy_untail((char*)pvm->data_prep_id, 128);
2627 data->system_id = iso_util_strcopy_untail((char*)pvm->system_id, 32);
2628 data->application_id =
2629 iso_util_strcopy_untail((char*)pvm->application_id, 128);
2630 data->copyright_file_id =
2631 iso_util_strcopy_untail((char*) pvm->copyright_file_id, 37);
2632 data->abstract_file_id =
2633 iso_util_strcopy_untail((char*) pvm->abstract_file_id, 37);
2634 data->biblio_file_id =
2635 iso_util_strcopy_untail((char*) pvm->bibliographic_file_id, 37);
2636 if (data->copyright_file_id[0] == '_' && data->copyright_file_id[1] == 0 &&
2637 data->abstract_file_id[0] == '_' && data->abstract_file_id[1] == 0 &&
2638 data->biblio_file_id[0] == '_' && data->biblio_file_id[1] == 0) {
2639 /* This is bug output from libisofs <= 0.6.23 . The texts mean file
2640 names and should have been empty to indicate that there are no such
2641 files. It is obvious that not all three roles can be fulfilled by
2642 one file "_" so that one cannot spoil anything by assuming them
2643 empty now.
2644 */
2645 data->copyright_file_id[0] = 0;
2646 data->abstract_file_id[0] = 0;
2647 data->biblio_file_id[0] = 0;
2648 }
2649 data->creation_time =
2650 iso_util_strcopy_untail((char*) pvm->vol_creation_time, 17);
2651 data->modification_time =
2652 iso_util_strcopy_untail((char*) pvm->vol_modification_time, 17);
2653 data->expiration_time =
2654 iso_util_strcopy_untail((char*) pvm->vol_expiration_time, 17);
2655 data->effective_time =
2656 iso_util_strcopy_untail((char*) pvm->vol_effective_time, 17);
2657
2658 data->session_lba = 0;
2659 if (block >= 16) /* The session begins 16 blocks before the PVD */
2660 data->session_lba = block - 16;
2661 data->nblocks = iso_read_bb(pvm->vol_space_size, 4, NULL);
2662
2663 rootdr = (struct ecma119_dir_record*) pvm->root_dir_record;
2664 data->pvd_root_block = iso_read_bb(rootdr->block, 4, NULL) +
2665 rootdr->len_xa[0];
2666
2667 /*
2668 * TODO #00017 : take advantage of other atts of PVD
2669 * PVD has other things that could be interesting, but that don't have a
2670 * member in IsoImage, such as creation date. In a multisession disc, we
2671 * could keep the creation date and update the modification date, for
2672 * example.
2673 */
2674
2675 ret = ISO_SUCCESS;
2676 ex:;
2677 LIBISO_FREE_MEM(buffer);
2678 return ret;
2679 }
2680
2681 /**
2682 * @return
2683 * 1 success, 0 ignored, < 0 error
2684 */
2685 static
read_el_torito_boot_catalog(_ImageFsData * data,uint32_t block)2686 int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
2687 {
2688 int ret, i, rx, last_done, idx, bufsize;
2689 struct el_torito_validation_entry *ve;
2690 struct el_torito_section_header *sh;
2691 struct el_torito_section_entry *entry; /* also usable as default_entry */
2692 unsigned char *buffer = NULL, *rpt;
2693
2694 LIBISO_ALLOC_MEM(buffer, unsigned char, BLOCK_SIZE);
2695 data->num_bootimgs = 0;
2696 data->catsize = 0;
2697 ret = data->src->read_block(data->src, block, buffer);
2698 if (ret < 0) {
2699 goto ex;
2700 }
2701
2702 ve = (struct el_torito_validation_entry*)buffer;
2703
2704 /* check if it is a valid catalog (TODO: check also the checksum)*/
2705 if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55)
2706 || (ve->key_byte2[0] != 0xAA) ) {
2707 iso_msg_submit(data->msgid, ISO_WRONG_EL_TORITO, 0,
2708 "Wrong or damaged El-Torito Catalog. El-Torito info "
2709 "will be ignored.");
2710 {ret = ISO_WRONG_EL_TORITO; goto ex;}
2711 }
2712
2713 /* ok, once we are here we assume it is a valid catalog */
2714
2715 /* parse the default entry */
2716 entry = (struct el_torito_section_entry *)(buffer + 32);
2717
2718 data->eltorito = 1;
2719 /* The Default Entry is declared mandatory */
2720 data->catsize = 64;
2721 data->num_bootimgs = 1;
2722 data->platform_ids[0] = ve->platform_id[0];
2723 memcpy(data->id_strings[0], ve->id_string, 24);
2724 memset(data->id_strings[0] + 24, 0, 4);
2725 data->boot_flags[0] = entry->boot_indicator[0] ? 1 : 0;
2726 data->media_types[0] = entry->boot_media_type[0];
2727 data->partition_types[0] = entry->system_type[0];
2728 data->load_segs[0] = iso_read_lsb(entry->load_seg, 2);
2729 data->load_sizes[0] = iso_read_lsb(entry->sec_count, 2);
2730 data->bootblocks[0] = iso_read_lsb(entry->block, 4);
2731 /* The Default Entry has no selection criterion */
2732 memset(data->selection_crits[0], 0, 20);
2733
2734 /* Read eventual more entries from the boot catalog */
2735 last_done = 0;
2736 for (rx = 64; (buffer[rx] & 0xfe) == 0x90 && !last_done; rx += 32) {
2737 last_done = buffer[rx] & 1;
2738 /* Read Section Header */
2739
2740 /* >>> ts B10703 : load a new buffer if needed */;
2741
2742 sh = (struct el_torito_section_header *) (buffer + rx);
2743 data->catsize += 32;
2744 for (i = 0; i < sh->num_entries[0]; i++) {
2745 rx += 32;
2746 data->catsize += 32;
2747
2748 /* >>> ts B10703 : load a new buffer if needed */;
2749
2750 if (data->num_bootimgs >= Libisofs_max_boot_imageS) {
2751
2752 /* >>> ts B10703 : need to continue rather than abort */;
2753
2754 iso_msg_submit(data->msgid, ISO_EL_TORITO_WARN, 0,
2755 "Too many boot images found. List truncated.");
2756 goto after_bootblocks;
2757 }
2758 /* Read bootblock from section entry */
2759 entry = (struct el_torito_section_entry *)(buffer + rx);
2760 idx = data->num_bootimgs;
2761 data->platform_ids[idx] = sh->platform_id[0];
2762 memcpy(data->id_strings[idx], sh->id_string, 28);
2763 data->boot_flags[idx] = entry->boot_indicator[0] ? 1 : 0;
2764 data->media_types[idx] = entry->boot_media_type[0];
2765 data->partition_types[idx] = entry->system_type[0];
2766 data->load_segs[idx] = iso_read_lsb(entry->load_seg, 2);
2767 data->load_sizes[idx] = iso_read_lsb(entry->sec_count, 2);
2768 data->bootblocks[idx] = iso_read_lsb(entry->block, 4);
2769 data->selection_crits[idx][0] = entry->selec_criteria[0];
2770 memcpy(data->selection_crits[idx] + 1, entry->vendor_sc, 19);
2771 data->num_bootimgs++;
2772 }
2773 }
2774 after_bootblocks:;
2775 if(data->catsize > 0) {
2776 if(data->catcontent != NULL)
2777 free(data->catcontent);
2778 if(data->catsize > 10 * BLOCK_SIZE)
2779 data->catsize = 10 * BLOCK_SIZE;
2780 bufsize = data->catsize;
2781 if (bufsize % BLOCK_SIZE)
2782 bufsize += BLOCK_SIZE - (bufsize % BLOCK_SIZE);
2783 data->catcontent = calloc(bufsize , 1);
2784 if(data->catcontent == NULL) {
2785 data->catsize = 0;
2786 ret = ISO_OUT_OF_MEM;
2787 goto ex;
2788 }
2789 for(rx = 0; rx < bufsize; rx += BLOCK_SIZE) {
2790 rpt = (unsigned char *) (data->catcontent + rx);
2791 ret = data->src->read_block(data->src, block + rx / BLOCK_SIZE, rpt);
2792 if (ret < 0)
2793 goto ex;
2794 }
2795 }
2796 ret = ISO_SUCCESS;
2797 ex:;
2798 LIBISO_FREE_MEM(buffer);
2799 return ret;
2800 }
2801
2802
2803 /*
2804 @return 1= ok, checked, go on with loading
2805 2= no checksum tags found, go on with loading
2806 <0= libisofs error
2807 especially ISO_SB_TREE_CORRUPTED
2808 */
2809 static
iso_src_check_sb_tree(IsoDataSource * src,uint32_t start_lba,int flag)2810 int iso_src_check_sb_tree(IsoDataSource *src, uint32_t start_lba, int flag)
2811 {
2812 int tag_type, ret;
2813 char *block = NULL, md5[16];
2814 int desired = (1 << 2);
2815 void *ctx = NULL;
2816 uint32_t next_tag = 0, i;
2817
2818 LIBISO_ALLOC_MEM(block, char, 2048);
2819 ret = iso_md5_start(&ctx);
2820 if (ret < 0)
2821 goto ex;
2822 if (start_lba == 0)
2823 desired |= (1 << 4);
2824 for (i = 0; i < 32; i++) {
2825 ret = src->read_block(src, start_lba + i, (uint8_t *) block);
2826 if (ret < 0)
2827 goto ex;
2828 ret = 0;
2829 if (i >= 16)
2830 ret = iso_util_eval_md5_tag(block, desired, start_lba + i,
2831 ctx, start_lba, &tag_type, &next_tag, 0);
2832 iso_md5_compute(ctx, block, 2048);
2833 if (ret == (int) ISO_MD5_TAG_COPIED) {/* growing without emulated TOC */
2834 ret = 2;
2835 goto ex;
2836 }
2837 if (ret == (int) ISO_MD5_AREA_CORRUPTED ||
2838 ret == (int) ISO_MD5_TAG_MISMATCH)
2839 ret = ISO_SB_TREE_CORRUPTED;
2840 if (ret < 0)
2841 goto ex;
2842 if (ret == 1)
2843 break;
2844 }
2845 if (i >= 32) {
2846 ret = 2;
2847 goto ex;
2848 }
2849 if (tag_type == 4) {
2850 /* Relocated Superblock: restart checking at real session start */
2851 if (next_tag < 32) {
2852 /* Non plausible session_start address */
2853 ret = ISO_SB_TREE_CORRUPTED;
2854 iso_msg_submit(-1, ret, 0, NULL);
2855 goto ex;
2856 }
2857 /* Check real session */
2858 ret = iso_src_check_sb_tree(src, next_tag, 0);
2859 goto ex;
2860 }
2861
2862 /* Go on with tree */
2863 for (i++; start_lba + i <= next_tag; i++) {
2864 ret = src->read_block(src, start_lba + i, (uint8_t *) block);
2865 if (ret < 0)
2866 goto ex;
2867 if (start_lba + i < next_tag)
2868 iso_md5_compute(ctx, block, 2048);
2869 }
2870 ret = iso_util_eval_md5_tag(block, (1 << 3), start_lba + i - 1,
2871 ctx, start_lba, &tag_type, &next_tag, 0);
2872 if (ret == (int) ISO_MD5_AREA_CORRUPTED ||
2873 ret == (int) ISO_MD5_TAG_MISMATCH)
2874 ret = ISO_SB_TREE_CORRUPTED;
2875 if (ret < 0)
2876 goto ex;
2877
2878 ret = 1;
2879 ex:
2880 if (ctx != NULL)
2881 iso_md5_end(&ctx, md5);
2882 LIBISO_FREE_MEM(block);
2883 return ret;
2884 }
2885
2886
iso_image_filesystem_new(IsoDataSource * src,struct iso_read_opts * opts,int msgid,IsoImageFilesystem ** fs)2887 int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
2888 int msgid, IsoImageFilesystem **fs)
2889 {
2890 int ret, i;
2891 uint32_t block;
2892 IsoImageFilesystem *ifs;
2893 _ImageFsData *data;
2894 uint8_t *buffer = NULL;
2895
2896 if (src == NULL || opts == NULL || fs == NULL) {
2897 ret = ISO_NULL_POINTER; goto ex;
2898 }
2899
2900 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2901 data = calloc(1, sizeof(_ImageFsData));
2902 if (data == NULL) {
2903 ret = ISO_OUT_OF_MEM; goto ex;
2904 }
2905
2906 ifs = calloc(1, sizeof(IsoImageFilesystem));
2907 if (ifs == NULL) {
2908 free(data);
2909 {ret = ISO_OUT_OF_MEM; goto ex;}
2910 }
2911 data->rr = RR_EXT_NO;
2912
2913 /* get our ref to IsoDataSource */
2914 data->src = src;
2915 iso_data_source_ref(src);
2916 data->open_count = 0;
2917
2918 data->catcontent = NULL;
2919
2920 /* get an id for the filesystem */
2921 data->id = ++fs_dev_id;
2922
2923 /* fill data from opts */
2924 data->gid = opts->gid;
2925 data->uid = opts->uid;
2926 data->file_mode = opts->file_mode & ~S_IFMT;
2927 data->dir_mode = opts->dir_mode & ~S_IFMT;
2928 data->msgid = msgid;
2929 data->aaip_load = !opts->noaaip;
2930 if (opts->nomd5 == 0)
2931 data->md5_load = 1;
2932 else if (opts->nomd5 == 2)
2933 data->md5_load = 2;
2934 else
2935 data->md5_load = 0;
2936 data->aaip_version = -1;
2937 data->make_new_ino = opts->make_new_ino;
2938 data->num_bootimgs = 0;
2939 for (i = 0; i < Libisofs_max_boot_imageS; i++)
2940 data->bootblocks[i] = 0;
2941 data->inode_counter = 0;
2942 data->px_ino_status = 0;
2943 data->rr_err_reported = 0;
2944 data->rr_err_repeated = 0;
2945 data->joliet_ucs2_failures = 0;
2946
2947
2948 data->local_charset = strdup(iso_get_local_charset(0));
2949 if (data->local_charset == NULL) {
2950 ret = ISO_OUT_OF_MEM;
2951 LIBISO_FREE_MEM(data);
2952 data = NULL;
2953 goto fs_cleanup;
2954 }
2955
2956 memcpy(ifs->type, "iso ", 4);
2957 ifs->data = data;
2958 ifs->refcount = 1;
2959 ifs->version = 0;
2960 ifs->get_root = ifs_get_root;
2961 ifs->get_by_path = ifs_get_by_path;
2962 ifs->get_id = ifs_get_id;
2963 ifs->open = ifs_fs_open;
2964 ifs->close = ifs_fs_close;
2965 ifs->free = ifs_fs_free;
2966
2967 /* read Volume Descriptors and ensure it is a valid image */
2968 if (data->md5_load == 1) {
2969 /* From opts->block on : check for superblock and tree tags */;
2970 ret = iso_src_check_sb_tree(src, opts->block, 0);
2971 if (ret < 0) {
2972 iso_msgs_submit(0,
2973 "Image loading aborted due to MD5 mismatch of image tree data",
2974 0, "FAILURE", 0);
2975 iso_msgs_submit(0,
2976 "You may override this refusal by disabling MD5 checking",
2977 0, "HINT", 0);
2978 goto fs_cleanup;
2979 }
2980 }
2981
2982 /* 1. first, open the filesystem */
2983 ifs_fs_open(ifs);
2984
2985 /* 2. read primary volume description */
2986 ret = read_pvm(data, opts->block + 16);
2987 if (ret < 0) {
2988 goto fs_cleanup;
2989 }
2990
2991 /* 3. read next volume descriptors */
2992 block = opts->block + 17;
2993 do {
2994 ret = src->read_block(src, block, buffer);
2995 if (ret < 0) {
2996 /* cleanup and exit */
2997 goto fs_cleanup;
2998 }
2999 switch (buffer[0]) {
3000 case 0:
3001 /* boot record */
3002 {
3003 struct ecma119_boot_rec_vol_desc *vol;
3004 vol = (struct ecma119_boot_rec_vol_desc*)buffer;
3005
3006 /* some sanity checks */
3007 if (strncmp((char*)vol->std_identifier, "CD001", 5)
3008 || vol->vol_desc_version[0] != 1
3009 || strncmp((char*)vol->boot_sys_id,
3010 "EL TORITO SPECIFICATION", 23)) {
3011 iso_msg_submit(data->msgid,
3012 ISO_UNSUPPORTED_EL_TORITO, 0,
3013 "Unsupported Boot Vol. Desc. Only El-Torito "
3014 "Specification, Version 1.0 Volume "
3015 "Descriptors are supported. Ignoring boot info");
3016 } else {
3017 data->catblock = iso_read_lsb(vol->boot_catalog, 4);
3018 ret = read_el_torito_boot_catalog(data, data->catblock);
3019 if (ret < 0 && ret != (int) ISO_UNSUPPORTED_EL_TORITO &&
3020 ret != (int) ISO_WRONG_EL_TORITO) {
3021 goto fs_cleanup;
3022 }
3023 }
3024 }
3025 break;
3026 case 2:
3027 /* supplementary volume descritor */
3028 {
3029 struct ecma119_sup_vol_desc *sup;
3030 struct ecma119_dir_record *root;
3031
3032 sup = (struct ecma119_sup_vol_desc*)buffer;
3033 if (sup->esc_sequences[0] == 0x25 &&
3034 sup->esc_sequences[1] == 0x2F &&
3035 (sup->esc_sequences[2] == 0x40 ||
3036 sup->esc_sequences[2] == 0x43 ||
3037 sup->esc_sequences[2] == 0x45) ) {
3038
3039 /* it's a Joliet Sup. Vol. Desc. */
3040 iso_msg_debug(data->msgid, "Found Joliet extensions");
3041 data->joliet = 1;
3042 root = (struct ecma119_dir_record*)sup->root_dir_record;
3043 data->svd_root_block = iso_read_bb(root->block, 4, NULL) +
3044 root->len_xa[0];
3045 /* TODO #00019 : set IsoImage attribs from Joliet SVD? */
3046 /* TODO #00020 : handle RR info in Joliet tree */
3047 } else if (sup->vol_desc_version[0] == 2) {
3048 /*
3049 * It is an Enhanced Volume Descriptor, image is an
3050 * ISO 9660:1999
3051 */
3052 iso_msg_debug(data->msgid, "Found ISO 9660:1999");
3053 data->iso1999 = 1;
3054 root = (struct ecma119_dir_record*)sup->root_dir_record;
3055 data->evd_root_block = iso_read_bb(root->block, 4, NULL) +
3056 root->len_xa[0];
3057 /* TODO #00021 : handle RR info in ISO 9660:1999 tree */
3058 } else {
3059 ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
3060 "Unsupported Sup. Vol. Desc found.");
3061 if (ret < 0) {
3062 goto fs_cleanup;
3063 }
3064 }
3065 }
3066 break;
3067 case 255:
3068 /*
3069 * volume set terminator
3070 * ignore, as it's checked in loop end condition
3071 */
3072 break;
3073 default:
3074 iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
3075 "Ignoring Volume descriptor %x.", buffer[0]);
3076 break;
3077 }
3078 block++;
3079 } while (buffer[0] != 255);
3080
3081 /* 4. check if RR extensions are being used */
3082 ret = read_root_susp_entries(data, data->pvd_root_block);
3083 if (ret < 0)
3084 goto fs_cleanup;
3085 if (!opts->norock)
3086 data->rr = data->rr_version;
3087
3088 /* select what tree to read */
3089 if (data->rr) {
3090 /* RR extensions are available */
3091 if (!opts->nojoliet && opts->preferjoliet && data->joliet) {
3092 /* if user prefers joliet, that is used */
3093 iso_msg_debug(data->msgid, "Reading Joliet extensions.");
3094 /* Although Joliet prescribes UCS-2BE, interpret names by its
3095 superset UTF-16BE in order to avoid conversion failures.
3096 */
3097 data->input_charset = strdup("UTF-16BE");
3098 data->rr = RR_EXT_NO;
3099 data->iso_root_block = data->svd_root_block;
3100 } else {
3101 /* RR will be used */
3102 iso_msg_debug(data->msgid, "Reading Rock Ridge extensions.");
3103 data->iso_root_block = data->pvd_root_block;
3104 }
3105 } else {
3106 /* RR extensions are not available */
3107 if (!opts->nojoliet && data->joliet) {
3108 /* joliet will be used */
3109 iso_msg_debug(data->msgid, "Reading Joliet extensions.");
3110 data->input_charset = strdup("UTF-16BE");
3111 data->iso_root_block = data->svd_root_block;
3112 } else if (!opts->noiso1999 && data->iso1999) {
3113 /* we will read ISO 9660:1999 */
3114 iso_msg_debug(data->msgid, "Reading ISO-9660:1999 tree.");
3115 data->iso_root_block = data->evd_root_block;
3116 } else {
3117 /* default to plain iso */
3118 iso_msg_debug(data->msgid, "Reading plain ISO-9660 tree.");
3119 data->iso_root_block = data->pvd_root_block;
3120 data->input_charset = strdup("ASCII");
3121 }
3122 }
3123 data->truncate_mode = opts->truncate_mode;
3124 data->truncate_length = opts->truncate_length;
3125 data->ecma119_map = opts->ecma119_map;
3126 data->joliet_map = opts->joliet_map;
3127
3128 if (data->input_charset == NULL) {
3129 if (opts->input_charset != NULL) {
3130 data->input_charset = strdup(opts->input_charset);
3131 } else {
3132 data->input_charset = strdup(data->local_charset);
3133 }
3134 }
3135 if (data->input_charset == NULL) {
3136 ret = ISO_OUT_OF_MEM;
3137 goto fs_cleanup;
3138 }
3139 data->auto_input_charset = opts->auto_input_charset;
3140
3141 /* and finally return. Note that we keep the DataSource opened */
3142
3143 *fs = ifs;
3144 {ret = ISO_SUCCESS; goto ex;}
3145
3146 fs_cleanup: ;
3147 ifs_fs_free(ifs);
3148 free(ifs);
3149
3150 ex:;
3151 LIBISO_FREE_MEM(buffer);
3152 return ret;
3153 }
3154
3155
3156 /* Take over aa_string from file source to node or discard it after making
3157 the necessary change in node->mode group permissions.
3158 node->mode must already be set.
3159 */
3160 static
src_aa_to_node(IsoFileSource * src,IsoNode * node,int flag)3161 int src_aa_to_node(IsoFileSource *src, IsoNode *node, int flag)
3162 {
3163 int ret;
3164 unsigned char *aa_string;
3165 ImageFileSourceData *data;
3166 _ImageFsData *fsdata;
3167 char *a_text = NULL, *d_text = NULL;
3168
3169 data = (ImageFileSourceData*)src->data;
3170 fsdata = data->fs->data;
3171
3172 /* Obtain ownership of eventual AAIP string */
3173 ret = iso_file_source_get_aa_string(src, &aa_string, 1);
3174 if (ret != 1 || aa_string == NULL)
3175 return 1;
3176 if (fsdata->aaip_load == 1) {
3177 /* Attach aa_string to node */
3178 ret = iso_node_add_xinfo(node, aaip_xinfo_func, aa_string);
3179 if (ret < 0)
3180 return ret;
3181 } else {
3182 /* Look for ACL and perform S_IRWXG mapping */
3183 iso_aa_get_acl_text(aa_string, node->mode, &a_text, &d_text, 16);
3184 if (a_text != NULL)
3185 aaip_cleanout_st_mode(a_text, &(node->mode), 4 | 16);
3186 /* Dispose ACL a_text and d_text */
3187 iso_aa_get_acl_text(aa_string, node->mode, &a_text, &d_text, 1 << 15);
3188 /* Dispose aa_string */
3189 aaip_xinfo_func(aa_string, 1);
3190 }
3191 return 1;
3192 }
3193
3194
3195 static
image_builder_create_node(IsoNodeBuilder * builder,IsoImage * image,IsoFileSource * src,char * in_name,IsoNode ** node)3196 int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
3197 IsoFileSource *src, char *in_name,
3198 IsoNode **node)
3199 {
3200 int ret, idx, to_copy;
3201 struct stat info;
3202 IsoNode *new = NULL;
3203 IsoBoot *bootcat;
3204 char *name = NULL;
3205 char *dest = NULL;
3206 ImageFileSourceData *data;
3207 _ImageFsData *fsdata;
3208
3209 #ifdef Libisofs_with_zliB
3210 /* Intimate friendship with this function in filters/zisofs.c */
3211 int ziso_add_osiz_filter(IsoFile *file, uint8_t zisofs_algo[2],
3212 uint8_t header_size_div4, uint8_t block_size_log2,
3213 uint64_t uncompressed_size, int flag);
3214 #endif /* Libisofs_with_zliB */
3215
3216
3217 if (builder == NULL || src == NULL || node == NULL || src->data == NULL) {
3218 ret = ISO_NULL_POINTER; goto ex;
3219 }
3220
3221 data = (ImageFileSourceData*)src->data;
3222 fsdata = data->fs->data;
3223
3224 if (in_name == NULL) {
3225 name = iso_file_source_get_name(src);
3226 } else {
3227 name = strdup(in_name);
3228 if (name == NULL) {
3229 ret = ISO_OUT_OF_MEM; goto ex;
3230 }
3231 }
3232
3233 /* get info about source */
3234 ret = iso_file_source_lstat(src, &info);
3235 if (ret < 0) {
3236 goto ex;
3237 }
3238
3239 switch (info.st_mode & S_IFMT) {
3240 case S_IFREG:
3241 {
3242 /* source is a regular file */
3243
3244 /* El-Torito images have only one section */
3245 if (fsdata->eltorito && data->sections[0].block == fsdata->catblock) {
3246
3247 if (image->bootcat->node != NULL) {
3248 ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
3249 "More than one catalog node has been found. "
3250 "We can continue, but that could lead to "
3251 "problems");
3252 if (ret < 0)
3253 goto ex;
3254 iso_node_unref((IsoNode*)image->bootcat->node);
3255 }
3256
3257 /* we create a placeholder for the catalog instead of
3258 * a regular file */
3259 new = calloc(1, sizeof(IsoBoot));
3260 if (new == NULL) {
3261 ret = ISO_OUT_OF_MEM; goto ex;
3262 }
3263 bootcat = (IsoBoot *) new;
3264 bootcat->lba = data->sections[0].block;
3265 bootcat->size = info.st_size;
3266 if (bootcat->size > 10 * BLOCK_SIZE)
3267 bootcat->size = 10 * BLOCK_SIZE;
3268 bootcat->content = NULL;
3269 if (bootcat->size > 0) {
3270 bootcat->content = calloc(1, bootcat->size);
3271 if (bootcat->content == NULL) {
3272 ret = ISO_OUT_OF_MEM; goto ex;
3273 }
3274 to_copy = bootcat->size;
3275 if (bootcat->size > fsdata->catsize)
3276 to_copy = fsdata->catsize;
3277 memcpy(bootcat->content, fsdata->catcontent, to_copy);
3278 }
3279
3280 /* and set the image node */
3281 image->bootcat->node = bootcat;
3282 new->type = LIBISO_BOOT;
3283 new->refcount = 1;
3284 } else {
3285 IsoStream *stream;
3286 IsoFile *file;
3287
3288 ret = iso_file_source_stream_new(src, &stream);
3289 if (ret < 0)
3290 goto ex;
3291
3292 /* take a ref to the src, as stream has taken our ref */
3293 iso_file_source_ref(src);
3294
3295 file = calloc(1, sizeof(IsoFile));
3296 if (file == NULL) {
3297 iso_stream_unref(stream);
3298 {ret = ISO_OUT_OF_MEM; goto ex;}
3299 }
3300
3301 /* mark file as from old session */
3302 file->from_old_session = 1;
3303
3304 /*
3305 * and we set the sort weight based on the block on image, to
3306 * improve performance on image modifying.
3307 *
3308 * This was too obtrusive because it occupied the highest
3309 * possible weight ranks:
3310 * file->sort_weight = INT_MAX - data->sections[0].block;
3311 *
3312 * So a try to be more nice and rely on caching with tiles
3313 * of at least 16 blocks. This occupies a range within
3314 * the interval of 1 to 2 exp 28 = 268,435,456.
3315 * (Dividing each number separately saves from integer
3316 * rollover problems.)
3317 */
3318 file->sort_weight =
3319 fsdata->nblocks / 16 - data->sections[0].block / 16 + 1;
3320
3321 file->stream = stream;
3322 file->node.type = LIBISO_FILE;
3323
3324 #ifdef Libisofs_with_zliB
3325
3326 if (data->header_size_div4 > 0) {
3327 ret = ziso_add_osiz_filter(file, data->zisofs_algo,
3328 data->header_size_div4,
3329 data->block_size_log2,
3330 data->uncompressed_size, 0);
3331 if (ret < 0) {
3332 iso_stream_unref(stream);
3333 goto ex;
3334 }
3335 }
3336
3337 #endif /* Libisofs_with_zliB */
3338
3339 new = (IsoNode*) file;
3340 new->refcount = 0;
3341
3342 if (data->sections[0].size > 0) {
3343 for (idx = 0; idx < fsdata->num_bootimgs; idx++)
3344 if (fsdata->eltorito && data->sections[0].block ==
3345 fsdata->bootblocks[idx])
3346 break;
3347 } else {
3348 idx = fsdata->num_bootimgs;
3349 }
3350 if (idx < fsdata->num_bootimgs) {
3351 /* it is boot image node */
3352 if (image->bootcat->bootimages[idx]->image != NULL) {
3353 /* idx is already occupied, try to find unoccupied one
3354 which has the same block address.
3355 */
3356 for (; idx < fsdata->num_bootimgs; idx++)
3357 if (fsdata->eltorito && data->sections[0].block ==
3358 fsdata->bootblocks[idx] &&
3359 image->bootcat->bootimages[idx]->image == NULL)
3360 break;
3361 }
3362 if (idx >= fsdata->num_bootimgs) {
3363 ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
3364 "More than one ISO node has been found for the same boot image.");
3365 if (ret < 0) {
3366 iso_stream_unref(stream);
3367 goto ex;
3368 }
3369 } else {
3370 /* and set the image node */
3371 image->bootcat->bootimages[idx]->image = file;
3372 new->refcount++;
3373 }
3374 }
3375 }
3376 }
3377 break;
3378 case S_IFDIR:
3379 {
3380 /* source is a directory */
3381 new = calloc(1, sizeof(IsoDir));
3382 if (new == NULL) {
3383 {ret = ISO_OUT_OF_MEM; goto ex;}
3384 }
3385 new->type = LIBISO_DIR;
3386 new->refcount = 0;
3387 }
3388 break;
3389 case S_IFLNK:
3390 {
3391 /* source is a symbolic link */
3392 IsoSymlink *link;
3393
3394 LIBISO_ALLOC_MEM(dest, char, LIBISOFS_NODE_PATH_MAX);
3395
3396 ret = iso_file_source_readlink(src, dest, LIBISOFS_NODE_PATH_MAX);
3397 if (ret < 0) {
3398 goto ex;
3399 }
3400 link = calloc(1, sizeof(IsoSymlink));
3401 if (link == NULL) {
3402 {ret = ISO_OUT_OF_MEM; goto ex;}
3403 }
3404 link->dest = strdup(dest);
3405 link->node.type = LIBISO_SYMLINK;
3406 link->fs_id = ISO_IMAGE_FS_ID;
3407 link->st_dev = info.st_dev;
3408 link->st_ino = info.st_ino;
3409 new = (IsoNode*) link;
3410 new->refcount = 0;
3411 }
3412 break;
3413 case S_IFSOCK:
3414 case S_IFBLK:
3415 case S_IFCHR:
3416 case S_IFIFO:
3417 {
3418 /* source is an special file */
3419 IsoSpecial *special;
3420 special = calloc(1, sizeof(IsoSpecial));
3421 if (special == NULL) {
3422 ret = ISO_OUT_OF_MEM; goto ex;
3423 }
3424 special->dev = info.st_rdev;
3425 special->node.type = LIBISO_SPECIAL;
3426 special->fs_id = ISO_IMAGE_FS_ID;
3427 special->st_dev = info.st_dev;
3428 special->st_ino = info.st_ino;
3429 new = (IsoNode*) special;
3430 new->refcount = 0;
3431 }
3432 break;
3433 default:
3434 ret = ISO_BAD_ISO_FILETYPE; goto ex;
3435 }
3436 /* fill fields */
3437 new->refcount++;
3438 new->name = name; name = NULL;
3439 new->mode = info.st_mode;
3440 new->uid = info.st_uid;
3441 new->gid = info.st_gid;
3442 new->atime = info.st_atime;
3443 new->mtime = info.st_mtime;
3444 new->ctime = info.st_ctime;
3445
3446 new->hidden = 0;
3447
3448 new->parent = NULL;
3449 new->next = NULL;
3450
3451 ret = src_aa_to_node(src, new, 0);
3452 if (ret < 0) {
3453 goto ex;
3454 }
3455
3456 /* Attach ino as xinfo if valid and no IsoStream is involved */
3457 if (info.st_ino != 0 && (info.st_mode & S_IFMT) != S_IFREG &&
3458 !fsdata->make_new_ino) {
3459 ret = iso_node_set_ino(new, info.st_ino, 0);
3460 if (ret < 0)
3461 goto ex;
3462 }
3463
3464 *node = new; new = NULL;
3465 {ret = ISO_SUCCESS; goto ex;}
3466
3467 ex:;
3468 if (name != NULL)
3469 free(name);
3470 if (new != NULL)
3471 iso_node_unref(new);
3472 LIBISO_FREE_MEM(dest);
3473 return ret;
3474 }
3475
3476 /**
3477 * Create a new builder, that is exactly a copy of an old builder, but where
3478 * create_node() function has been replaced by image_builder_create_node.
3479 */
3480 static
iso_image_builder_new(IsoNodeBuilder * old,IsoNodeBuilder ** builder)3481 int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder)
3482 {
3483 IsoNodeBuilder *b;
3484
3485 if (builder == NULL) {
3486 return ISO_NULL_POINTER;
3487 }
3488
3489 b = malloc(sizeof(IsoNodeBuilder));
3490 if (b == NULL) {
3491 return ISO_OUT_OF_MEM;
3492 }
3493
3494 b->refcount = 1;
3495 b->create_file_data = old->create_file_data;
3496 b->create_node_data = old->create_node_data;
3497 b->create_file = old->create_file;
3498 b->create_node = image_builder_create_node;
3499 b->free = old->free;
3500
3501 *builder = b;
3502 return ISO_SUCCESS;
3503 }
3504
3505 /**
3506 * Create a file source to access the El-Torito boot image, when it is not
3507 * accessible from the ISO filesystem.
3508 */
3509 static
create_boot_img_filesrc(IsoImageFilesystem * fs,IsoImage * image,int idx,IsoFileSource ** src)3510 int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, int idx,
3511 IsoFileSource **src)
3512 {
3513 int ret;
3514 struct stat atts;
3515 _ImageFsData *fsdata;
3516 IsoFileSource *ifsrc = NULL;
3517 ImageFileSourceData *ifsdata = NULL;
3518
3519 if (fs == NULL || fs->data == NULL || src == NULL) {
3520 return ISO_NULL_POINTER;
3521 }
3522
3523 fsdata = (_ImageFsData*)fs->data;
3524
3525 memset(&atts, 0, sizeof(struct stat));
3526 atts.st_mode = S_IFREG;
3527 atts.st_ino = img_give_ino_number(image, 0);
3528 atts.st_nlink = 1;
3529
3530 /*
3531 * this is the greater problem. We don't know the size. For now, we
3532 * just use a single block of data. In a future, maybe we could figure out
3533 * a better idea. Another alternative is to use several blocks, that way
3534 * is less probable that we throw out valid data.
3535 */
3536 atts.st_size = (off_t)BLOCK_SIZE;
3537
3538 /* Fill last entries */
3539 atts.st_dev = fsdata->id;
3540 atts.st_blksize = BLOCK_SIZE;
3541 atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
3542
3543 /* ok, we can now create the file source */
3544 ifsdata = calloc(1, sizeof(ImageFileSourceData));
3545 if (ifsdata == NULL) {
3546 ret = ISO_OUT_OF_MEM;
3547 goto boot_fs_cleanup;
3548 }
3549 ifsrc = calloc(1, sizeof(IsoFileSource));
3550 if (ifsrc == NULL) {
3551 ret = ISO_OUT_OF_MEM;
3552 goto boot_fs_cleanup;
3553 }
3554
3555 ifsdata->sections = malloc(sizeof(struct iso_file_section));
3556 if (ifsdata->sections == NULL) {
3557 ret = ISO_OUT_OF_MEM;
3558 goto boot_fs_cleanup;
3559 }
3560
3561 /* fill data */
3562 ifsdata->fs = fs;
3563 iso_filesystem_ref(fs);
3564 ifsdata->parent = NULL;
3565 ifsdata->info = atts;
3566 ifsdata->name = NULL;
3567 ifsdata->sections[0].block = fsdata->bootblocks[idx];
3568 ifsdata->sections[0].size = BLOCK_SIZE;
3569 ifsdata->nsections = 1;
3570
3571 ifsrc->class = &ifs_class;
3572 ifsrc->data = ifsdata;
3573 ifsrc->refcount = 1;
3574
3575 *src = ifsrc;
3576 return ISO_SUCCESS;
3577
3578 boot_fs_cleanup: ;
3579 free(ifsdata);
3580 free(ifsrc);
3581 return ret;
3582 }
3583
3584 /** ??? >>> ts B00428 : should the max size become public ? */
3585 #define Libisofs_boot_image_max_sizE (4096*1024)
3586
3587 /** Guess which of the loaded boot images contain boot information tables.
3588 Set boot->seems_boot_info_table accordingly.
3589 */
3590 static
iso_image_eval_boot_info_table(IsoImage * image,struct iso_read_opts * opts,IsoDataSource * src,uint32_t iso_image_size,int flag)3591 int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts,
3592 IsoDataSource *src, uint32_t iso_image_size, int flag)
3593 {
3594 int i, j, ret, section_count, todo, chunk;
3595 uint32_t img_lba, img_size, boot_pvd_found, image_pvd, alleged_size;
3596 struct iso_file_section *sections = NULL;
3597 struct el_torito_boot_image *boot;
3598 uint8_t *boot_image_buf = NULL, boot_info_found[16], *buf = NULL;
3599 IsoStream *stream = NULL;
3600 IsoFile *boot_file;
3601 uint64_t blk;
3602
3603 if (image->bootcat == NULL)
3604 {ret = ISO_SUCCESS; goto ex;}
3605 LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
3606 for (i = 0; i < image->bootcat->num_bootimages; i++) {
3607 boot = image->bootcat->bootimages[i];
3608 boot_file = boot->image;
3609 boot->seems_boot_info_table = 0;
3610 boot->seems_grub2_boot_info = 0;
3611 boot->seems_isohybrid_capable = 0;
3612 img_size = iso_file_get_size(boot_file);
3613 if (img_size > Libisofs_boot_image_max_sizE || img_size < 64)
3614 continue;
3615 img_lba = 0;
3616 sections = NULL;
3617 ret = iso_file_get_old_image_sections(boot_file,
3618 §ion_count, §ions, 0);
3619 if (ret == 1 && section_count > 0)
3620 img_lba = sections[0].block;
3621 if (sections != NULL) {
3622 free(sections);
3623 sections = NULL;
3624 }
3625 if(img_lba == 0)
3626 continue;
3627
3628 boot_image_buf = calloc(1, img_size);
3629 if (boot_image_buf == NULL) {
3630 ret = ISO_OUT_OF_MEM;
3631 goto ex;
3632 }
3633 stream = iso_file_get_stream(boot_file);
3634 ret = iso_stream_open(stream);
3635 if (ret < 0) {
3636 stream = NULL;
3637 goto ex;
3638 }
3639 for (todo = img_size; todo > 0; ) {
3640 if (todo > BLOCK_SIZE)
3641 chunk = BLOCK_SIZE;
3642 else
3643 chunk = todo;
3644 ret = iso_stream_read(stream, boot_image_buf + (img_size - todo),
3645 chunk);
3646 if (ret != chunk) {
3647 ret = (ret < 0) ? ret : (int) ISO_FILE_READ_ERROR;
3648 goto ex;
3649 }
3650 todo -= chunk;
3651 }
3652 iso_stream_close(stream);
3653 stream = NULL;
3654
3655 memcpy(boot_info_found, boot_image_buf + 8, 16);
3656 boot_pvd_found = iso_read_lsb(boot_info_found, 4);
3657 image_pvd = (uint32_t) (opts->block + 16);
3658
3659 /* Accommodate to eventually relocated superblock */
3660 if (image_pvd != boot_pvd_found &&
3661 image_pvd == 16 && boot_pvd_found < iso_image_size) {
3662 /* Check whether there is a PVD at boot_pvd_found
3663 and whether it bears the same image size
3664 */
3665 ret = read_pvd_block(src, boot_pvd_found, buf, &alleged_size);
3666 if (ret == 1 &&
3667 alleged_size + boot_pvd_found == iso_image_size + image_pvd)
3668 image_pvd = boot_pvd_found;
3669 }
3670
3671 ret = make_boot_info_table(boot_image_buf, image_pvd,
3672 img_lba, img_size);
3673 if (ret < 0)
3674 goto ex;
3675 if (memcmp(boot_image_buf + 8, boot_info_found, 16) == 0)
3676 boot->seems_boot_info_table = 1;
3677
3678 if (img_size >= Libisofs_grub2_elto_patch_poS + 8) {
3679 blk = 0;
3680 for (j = Libisofs_grub2_elto_patch_poS + 7;
3681 j >= Libisofs_grub2_elto_patch_poS; j--)
3682 blk = (blk << 8) | boot_image_buf[j];
3683 if (blk == img_lba * 4 + Libisofs_grub2_elto_patch_offsT)
3684 boot->seems_grub2_boot_info = 1;
3685 }
3686 if (img_size >= 68 && boot->seems_boot_info_table)
3687 if (boot_image_buf[64] == 0xfb && boot_image_buf[65] == 0xc0 &&
3688 boot_image_buf[66] == 0x78 && boot_image_buf[67] == 0x70)
3689 boot->seems_isohybrid_capable = 1;
3690
3691 free(boot_image_buf);
3692 boot_image_buf = NULL;
3693 }
3694 ret = 1;
3695 ex:;
3696 if (boot_image_buf != NULL)
3697 free(boot_image_buf);
3698 if (stream != NULL)
3699 iso_stream_close(stream);
3700 LIBISO_FREE_MEM(buf);
3701 return ret;
3702 }
3703
3704
3705 static
issue_collision_warning_summary(size_t failures)3706 void issue_collision_warning_summary(size_t failures)
3707 {
3708 if (failures > ISO_IMPORT_COLL_WARN_MAX) {
3709 iso_msg_submit(-1, ISO_IMPORT_COLLISION, 0,
3710 "More file name collisions had to be resolved");
3711 }
3712 if (failures > 0) {
3713 iso_msg_submit(-1, ISO_IMPORT_COLLISION, 0,
3714 "Sum of resolved file name collisions: %.f",
3715 (double) failures);
3716 }
3717 }
3718
3719 /* Mark all non-matching combinations of head_per_cyl and sectors_per_head
3720 in the matches bitmap. This is a brute force approach to find the common
3721 intersections of up to 8 hyperbolas additionally intersected with the grid
3722 of integer coordinates {1..255}x{1..63}.
3723 Given the solution space size of only 14 bits, it seems inappropriate to
3724 employ any algebra.
3725 */
3726 static
iso_scan_hc_sh(uint32_t lba,int c,int h,int s,uint8_t * matches)3727 void iso_scan_hc_sh(uint32_t lba, int c, int h, int s, uint8_t *matches)
3728 {
3729 int i, j;
3730 uint32_t res;
3731
3732 /*
3733 fprintf(stderr, "iso_scan_hc_sh :%d = %4d/%3d/%2d :\n", lba, c, h, s);
3734 */
3735 if (lba == ((uint32_t) s) - 1 && c == 0 && h == 0) /* trivial solutions */
3736 return;
3737 if (c == 1023 && h >= 254 && s == 63) /* Indicators for invalid CHS */
3738 return;
3739
3740 /* matches(i=0,j=1) == 0 indicates presence of non-trivial equations */
3741 matches[0] &= ~1;
3742
3743 for (i = 1; i <= 255; i++) {
3744 for (j = 1; j <= 63; j++) {
3745 res = ((c * i) + h) * j + (s - 1);
3746 if (res != lba) {
3747 matches[(i / 8) * 32 + (j - 1)] &= ~(1 << (i % 8));
3748 /*
3749 } else {
3750 if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8)))
3751 fprintf(stderr,
3752 "iso_scan_hc_sh :%d = %4d/%3d/%2d : H/C= %3d S/H= %2d\n",
3753 lba, c, h, s, i, j);
3754 */
3755 }
3756 }
3757 }
3758 }
3759
3760 /* Pick a good remaining solution from the matches bitmap.
3761 */
3762 static
iso_get_hc_sh(uint8_t * matches,uint32_t iso_image_size,int * hc,int * sh,int flag)3763 void iso_get_hc_sh(uint8_t *matches, uint32_t iso_image_size,
3764 int *hc, int *sh, int flag)
3765 {
3766 int i, j, k;
3767 static int pref[][2] = {{64, 32}, {255, 63}}, prefs = 2;
3768
3769 *hc = *sh = 0;
3770
3771 if (matches[0] & 1)
3772 return; /* Only trivial equations seen */
3773
3774 /* Look for preferred layouts */
3775 for (k = 0; k < prefs; k++) {
3776 i = pref[k][0];
3777 j = pref[k][1];
3778 if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
3779 continue;
3780 if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
3781 *hc = i;
3782 *sh = j;
3783 return;
3784 }
3785 }
3786
3787 /* Look for largest possible cylinder */
3788 for (i = 1; i <= 255; i++) {
3789 for (j = 1; j <= 63; j++) {
3790 if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
3791 continue;
3792 if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
3793 if( i * j < *hc * *sh)
3794 continue;
3795 *hc = i;
3796 *sh = j;
3797 }
3798 }
3799 }
3800 }
3801
3802 static
iso_analyze_mbr_ptable(IsoImage * image,int flag)3803 int iso_analyze_mbr_ptable(IsoImage *image, int flag)
3804 {
3805 int i, j, ret, cyl_align_mode, part_after_image = 0;
3806 uint32_t start_h, start_s, start_c, end_h, end_s, end_c, sph = 0, hpc = 0;
3807 uint32_t start_lba, num_blocks, end_chs_lba, image_size, lba, cyl_size;
3808 uint8_t *data, pstatus, ptype, *hc_sh = NULL;
3809 struct iso_imported_sys_area *sai;
3810
3811 /* Bitmap for finding head_per_cyl and sectors_per_head. */
3812 LIBISO_ALLOC_MEM(hc_sh, uint8_t, 32 * 63);
3813 memset(hc_sh, 0xff, 32 * 63);
3814
3815 sai = image->imported_sa_info;
3816 image_size = sai->image_size;
3817 for (i = 0; i < 4; i++) {
3818 data = (uint8_t *) (image->system_area_data + 446 + 16 * i);
3819 for (j = 0; j < 16; j++)
3820 if (data[j])
3821 break;
3822 if (j == 16)
3823 continue;
3824 pstatus = data[0];
3825 ptype = data[4];
3826 start_c = ((data[2] & 0xc0) << 2) | data[3];
3827 start_h = data[1];
3828 start_s = data[2] & 63;
3829 end_c = ((data[6] & 0xc0) << 2) | data[7];
3830 end_h = data[5];
3831 end_s = data[6] & 63;
3832 start_lba = iso_read_lsb(data + 8, 4);
3833 num_blocks = iso_read_lsb(data + 12, 4);
3834 if (num_blocks <= 0)
3835 continue;
3836 if (sph > 0) {
3837 if (end_s != sph)
3838 sph = 0xffffffff;
3839 } else if (sph == 0) {
3840 sph = end_s;
3841 }
3842 if (hpc > 0) {
3843 if (end_h + 1 != hpc)
3844 hpc = 0xffffffff;
3845 } else if (hpc == 0) {
3846 hpc = end_h + 1;
3847 }
3848 /* Check whether start_lba + num_blocks - 1 matches chs,hpc,spc */
3849 end_chs_lba = ((end_c * hpc) + end_h) * sph + end_s;
3850 if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff)
3851 if (end_chs_lba != start_lba + num_blocks)
3852 hpc = sph = 0xffffffff;
3853 /* In case that end CHS does not give cylinder layout */
3854 iso_scan_hc_sh(start_lba, start_c, start_h, start_s, hc_sh);
3855 iso_scan_hc_sh(start_lba + num_blocks - 1, end_c, end_h, end_s, hc_sh);
3856
3857 /* Register partition as iso_mbr_partition_request */
3858 if (sai->mbr_req == NULL) {
3859 sai->mbr_req = calloc(ISO_MBR_ENTRIES_MAX,
3860 sizeof(struct iso_mbr_partition_request *));
3861 if (sai->mbr_req == NULL)
3862 {ret = ISO_OUT_OF_MEM; goto ex;}
3863 }
3864 ret = iso_quick_mbr_entry(sai->mbr_req, &(sai->mbr_req_count),
3865 (uint64_t) start_lba, (uint64_t) num_blocks,
3866 ptype, pstatus, i + 1);
3867 if (ret < 0)
3868 goto ex;
3869 if ((start_lba + num_blocks + 3) / 4 > image_size)
3870 image_size = (start_lba + num_blocks + 3) / 4;
3871 }
3872
3873 if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff) {
3874 sai->partition_secs_per_head = sph;
3875 sai->partition_heads_per_cyl = hpc;
3876 } else {
3877 /* Look for the best C/H/S parameters caught in scan */
3878 iso_get_hc_sh(hc_sh, image_size, &(sai->partition_heads_per_cyl),
3879 &(sai->partition_secs_per_head), 0);
3880 }
3881
3882 cyl_align_mode = 2; /* off */
3883 if (sai->partition_secs_per_head >0 && sai->partition_heads_per_cyl > 0 &&
3884 sai->mbr_req_count > 0) {
3885 /* Check for cylinder alignment */
3886 for (i = 0; i < sai->mbr_req_count; i++) {
3887 cyl_size = sai->partition_secs_per_head *
3888 sai->partition_heads_per_cyl;
3889 lba = sai->mbr_req[i]->start_block + sai->mbr_req[i]->block_count;
3890 if (sai->mbr_req[i]->start_block >= sai->image_size)
3891 part_after_image = 1;
3892 end_c = lba / cyl_size;
3893 if (end_c * cyl_size != lba)
3894 break;
3895 }
3896 if (i == sai->mbr_req_count && part_after_image)
3897 cyl_align_mode = 3; /* all */
3898 else if (i >= 1)
3899 cyl_align_mode = 1; /* on */
3900 }
3901 sai->system_area_options &= ~(3 << 8);
3902 sai->system_area_options |= (cyl_align_mode << 8);
3903 ret = 1;
3904 ex:
3905 LIBISO_FREE_MEM(hc_sh);
3906 return ret;
3907
3908 }
3909
3910 /* @return 0= no hybrid detected
3911 1= ISOLINUX isohybrid (options & 2)
3912 2= GRUB2 MBR patching (options & (1 << 14))
3913 */
3914 static
iso_analyze_isohybrid(IsoImage * image,int flag)3915 int iso_analyze_isohybrid(IsoImage *image, int flag)
3916 {
3917 uint8_t *sad;
3918 uint32_t eltorito_lba = 0;
3919 uint64_t mbr_lba;
3920 int i, section_count, ret;
3921 ElToritoBootImage *boot;
3922 struct iso_file_section *sections;
3923
3924 sad = (uint8_t *) image->system_area_data;
3925
3926 /* Learn LBA of boot image */;
3927 if (image->bootcat == NULL)
3928 return 0;
3929 if (image->bootcat->num_bootimages < 1)
3930 return 0;
3931 boot = image->bootcat->bootimages[0];
3932 if (boot == NULL)
3933 return 0;
3934 ret = iso_file_get_old_image_sections(boot->image, §ion_count,
3935 §ions, 0);
3936 if (ret < 0)
3937 return ret;
3938 if (ret > 0 && section_count > 0)
3939 eltorito_lba = sections[0].block;
3940 free(sections);
3941
3942 /* Check MBR whether it is ISOLINUX and learn LBA to which it points */
3943 if (!boot->seems_isohybrid_capable)
3944 goto try_grub2_mbr;
3945 for (i= 0; i < 426; i++)
3946 if(strncmp((char *) (sad + i), "isolinux", 8) == 0)
3947 break;
3948 if (i < 426) { /* search text was found */
3949 mbr_lba = iso_read_lsb(sad + 432, 4);
3950 mbr_lba /= 4;
3951 if (mbr_lba == eltorito_lba)
3952 return 1;
3953 goto try_grub2_mbr;
3954 }
3955
3956 try_grub2_mbr:;
3957 /* Check for GRUB2 MBR patching */
3958 mbr_lba = iso_read_lsb64(sad + 0x1b0);
3959 if (mbr_lba / 4 - 1 == eltorito_lba)
3960 return 2;
3961
3962 return 0;
3963 }
3964
3965 static
iso_analyze_partition_offset(IsoImage * image,IsoDataSource * src,uint64_t start_block,uint64_t block_count,int flag)3966 int iso_analyze_partition_offset(IsoImage *image, IsoDataSource *src,
3967 uint64_t start_block, uint64_t block_count,
3968 int flag)
3969 {
3970 int ret;
3971 uint8_t *buf = NULL;
3972 uint32_t iso_size;
3973 off_t p_offset;
3974 struct ecma119_pri_vol_desc *pvm;
3975 struct iso_imported_sys_area *sai;
3976
3977 sai = image->imported_sa_info;
3978
3979 /* Check for PVD at partition start with same end */
3980 LIBISO_ALLOC_MEM(buf, uint8_t, 2048);
3981 p_offset = start_block / 4;
3982 ret = src->read_block(src, p_offset + 16, buf);
3983 if (ret > 0) {
3984 pvm = (struct ecma119_pri_vol_desc *) buf;
3985 iso_size = iso_read_lsb(pvm->vol_space_size, 4);
3986 if (strncmp((char*) pvm->std_identifier, "CD001", 5) == 0 &&
3987 pvm->vol_desc_type[0] == 1 &&
3988 pvm->vol_desc_version[0] == 1 &&
3989 pvm->file_structure_version[0] == 1 &&
3990 (iso_size + p_offset == sai->image_size ||
3991 iso_size == block_count / 4))
3992
3993 sai->partition_offset = p_offset;
3994 }
3995 ret = 1;
3996 ex:;
3997 LIBISO_FREE_MEM(buf);
3998 return ret;
3999 }
4000
4001 static
iso_analyze_mbr(IsoImage * image,IsoDataSource * src,int flag)4002 int iso_analyze_mbr(IsoImage *image, IsoDataSource *src, int flag)
4003 {
4004 int sub_type = 2, ret, is_isohybrid = 0, is_grub2_mbr = 0;
4005 int is_protective_label = 0;
4006 uint64_t part2_start;
4007 char *sad;
4008 struct iso_imported_sys_area *sai;
4009 struct iso_mbr_partition_request *part;
4010
4011 sad = image->system_area_data;
4012 sai = image->imported_sa_info;
4013
4014 /* Is it an MBR ? */
4015 if (((unsigned char *) sad)[510] != 0x55 ||
4016 ((unsigned char *) sad)[511] != 0xaa)
4017 {ret = 0; goto ex;}
4018
4019 ret = iso_analyze_mbr_ptable(image, 0);
4020 if (ret <= 0)
4021 goto ex;
4022
4023 ret = iso_analyze_isohybrid(image, 0);
4024 if (ret < 0)
4025 goto ex;
4026 if (ret == 1) {
4027 sub_type = 0;
4028 is_isohybrid = 1;
4029 } else if(ret == 2) {
4030 /* will become sub_type 0 if protective_label */
4031 is_grub2_mbr = 1;
4032 }
4033
4034 if (sai->mbr_req_count == 3 && !is_isohybrid) {
4035 /* Check for libisofs PReP partitions :
4036 0xee or 0xcd from 0 to a-1
4037 0x41 from a to b
4038 0x0c or 0xcd from b+1 to end
4039 */
4040 if ((sai->mbr_req[0]->start_block == 0 &&
4041 (sai->mbr_req[0]->type_byte == 0xee ||
4042 sai->mbr_req[0]->type_byte == 0xcd)) &&
4043 sai->mbr_req[0]->block_count == sai->mbr_req[1]->start_block &&
4044 sai->mbr_req[1]->type_byte == 0x41 &&
4045 (sai->mbr_req[1]->start_block % 4) == 0 &&
4046 sai->mbr_req[1]->start_block + sai->mbr_req[1]->block_count ==
4047 sai->mbr_req[2]->start_block &&
4048 (sai->mbr_req[2]->type_byte == 0x0c ||
4049 sai->mbr_req[2]->type_byte == 0xcd) &&
4050 (sai->mbr_req[2]->start_block + sai->mbr_req[2]->block_count) / 4
4051 == sai->image_size) {
4052 sai->prep_part_start = sai->mbr_req[1]->start_block / 4;
4053 sai->prep_part_size = (sai->mbr_req[1]->block_count + 3) / 4;
4054 sub_type = 0;
4055 }
4056 }
4057 if (sai->mbr_req_count >= 1 &&
4058 (sai->mbr_req[0]->type_byte == 0xee || !is_isohybrid) &&
4059 !(sai->prep_part_start > 0)) {
4060 part = sai->mbr_req[0];
4061 part2_start = 0;
4062 if (sai->mbr_req_count >= 2)
4063 part2_start = sai->mbr_req[1]->start_block;
4064 if (part->start_block == 1 &&
4065 (part->block_count + 1 == ((uint64_t) sai->image_size) * 4 ||
4066 (part->type_byte == 0xee &&
4067 part->block_count + 1 >= ((uint64_t) sai->image_size) * 4 &&
4068 (sai->mbr_req_count == 1 ||
4069 (sai->mbr_req_count == 2 &&
4070 sai->mbr_req[1]->type_byte == 0x00))) ||
4071 part->block_count + 1 == part2_start)) {
4072 /* libisofs protective msdos label for GRUB2 */
4073 is_protective_label = 1;
4074 sub_type = 0;
4075 } else if (sai->mbr_req_count == 1 && part->start_block == 0 &&
4076 part->block_count <= ((uint64_t) sai->image_size) * 4 &&
4077 part->block_count + 600 >= ((uint64_t) sai->image_size) * 4 &&
4078 part->type_byte == 0x96) {
4079 /* CHRP (possibly without padding) */
4080 sub_type = 1;
4081 } else if (sai->mbr_req_count == 1 &&
4082 sai->mbr_req[0]->start_block > 0 &&
4083 (sai->mbr_req[0]->start_block % 4) == 0 &&
4084 (sai->mbr_req[0]->start_block +
4085 sai->mbr_req[0]->block_count) / 4 <= sai->image_size &&
4086 part->type_byte == 0x41) {
4087 /* mkisofs PReP partition */
4088 sai->prep_part_start = sai->mbr_req[0]->start_block / 4;
4089 sai->prep_part_size = (sai->mbr_req[0]->block_count + 3) / 4;
4090 sub_type = 0;
4091 }
4092 }
4093
4094 /* Check for partition offset with extra set of meta data */
4095 if (sai->mbr_req_count > 0) {
4096 part = sai->mbr_req[0];
4097 if ((part->status_byte == 0x80 || part->status_byte == 0) &&
4098 part->start_block >= 64 && part->block_count >= 72 &&
4099 part->start_block <= 2048 &&
4100 part->start_block % 4 == 0 && part->block_count % 4 == 0 &&
4101 (part->start_block + part->block_count) / 4 <= sai->image_size) {
4102
4103 ret = iso_analyze_partition_offset(image, src, part->start_block,
4104 part->block_count, 0);
4105 if (ret < 0)
4106 goto ex;
4107 }
4108 }
4109
4110 /* Set sa type 0, sub type as chosen */
4111 sai->system_area_options = (sai->system_area_options & 0xffff8300) |
4112 is_protective_label |
4113 (is_isohybrid << 1) |
4114 (sub_type << 10) |
4115 (is_grub2_mbr << 14);
4116 ret = 1;
4117 ex:;
4118 return ret;
4119 }
4120
4121 static
iso_seems_usable_gpt_head(uint8_t * head,int flag)4122 int iso_seems_usable_gpt_head(uint8_t *head, int flag)
4123 {
4124 uint32_t head_size, entry_size;
4125
4126 if (strncmp((char *) head, "EFI PART", 8) != 0) /* signature */
4127 return 0;
4128 if (head[8] || head[9] || head[10] != 1 || head[11]) /* revision */
4129 return 0;
4130 head_size = iso_read_lsb(head + 12, 4);
4131 if (head_size < 92)
4132 return 0;
4133 entry_size = iso_read_lsb(head + 84, 4);
4134 if (entry_size != 128)
4135 return 0;
4136 return 1;
4137 }
4138
4139 static
iso_analyze_gpt_backup(IsoImage * image,IsoDataSource * src,int flag)4140 int iso_analyze_gpt_backup(IsoImage *image, IsoDataSource *src, int flag)
4141 {
4142 struct iso_imported_sys_area *sai;
4143 uint64_t part_start;
4144 uint32_t iso_block, found_crc, crc, entry_count, array_crc;
4145 uint8_t *head, *part_array, *b_part, *m_part;
4146 int ret, i, num_iso_blocks, l, j, entries_diff;
4147 unsigned char *buf = NULL;
4148 char *comments = NULL;
4149
4150 sai = image->imported_sa_info;
4151 LIBISO_ALLOC_MEM(buf, unsigned char, 34 * 1024);
4152 LIBISO_ALLOC_MEM(comments, char, 4096);
4153
4154 /* Read ISO block with backup head */
4155 if (sai->gpt_backup_lba >= ((uint64_t) sai->image_size) * 4 &&
4156 (sai->mbr_req_count < 1 ||
4157 sai->mbr_req[0]->start_block + sai->mbr_req[0]->block_count
4158 > sai->gpt_backup_lba + 1))
4159 sprintf(comments + strlen(comments), "Implausible header LBA %.f, ",
4160 (double) sai->gpt_backup_lba);
4161 iso_block = sai->gpt_backup_lba / 4;
4162 ret = src->read_block(src, iso_block, buf);
4163 if (ret < 0) {
4164 sprintf(comments + strlen(comments),
4165 "Cannot read header block at 2k LBA %.f, ",
4166 (double) iso_block);
4167 ret = 0; goto ex;
4168 }
4169 head = buf + (sai->gpt_backup_lba % 4) * 512;
4170 ret = iso_seems_usable_gpt_head(head, 0);
4171 if (ret == 0)
4172 strcat(comments,
4173 "Not a GPT 1.0 header of 92 bytes for 128 bytes per entry, ");
4174 if (ret <= 0) {
4175 ret = 0; goto ex;
4176 }
4177
4178 /* Check head CRC */
4179 found_crc = iso_read_lsb(head + 16, 4);
4180 memset(head + 16, 0, 4);
4181 crc = iso_crc32_gpt((unsigned char *) head, 92, 0);
4182 if (found_crc != crc) {
4183 sprintf(comments + strlen(comments),
4184 "Head CRC 0x%8x wrong. Should be 0x%8x",
4185 found_crc, crc);
4186 crc = iso_crc32_gpt((unsigned char *) head, 512, 0);
4187 if (found_crc == crc) {
4188 strcat(comments, ". Matches all 512 block bytes, ");
4189 } else {
4190 strcat(comments, ", ");
4191 ret = 0; goto ex;
4192 }
4193 }
4194 for (i = 0; i < 16; i ++)
4195 if (head[i + 56] != sai->gpt_disk_guid[i])
4196 break;
4197 if (i < 16) {
4198 sprintf(comments + strlen(comments), "Disk GUID differs (");
4199 iso_util_bin_to_hex(comments + strlen(comments), head + 56, 16, 0);
4200 sprintf(comments + strlen(comments), "), ");
4201 }
4202
4203 /* Header content will possibly be overwritten now */
4204 array_crc = iso_read_lsb(head + 88, 4);
4205 part_start = iso_read_lsb64(head + 72);
4206 entry_count = iso_read_lsb(head + 80, 4);
4207 head = NULL;
4208
4209 /* Read backup array */
4210 if (entry_count != sai->gpt_max_entries) {
4211 sprintf(comments + strlen(comments),
4212 "Number of array entries %u differs from main GPT %u, ",
4213 entry_count, sai->gpt_max_entries);
4214 ret = 0; goto ex;
4215 }
4216 if (part_start + (entry_count + 3) / 4 != sai->gpt_backup_lba)
4217 sprintf(comments + strlen(comments), "Implausible array LBA %.f, ",
4218 (double) part_start);
4219 iso_block = part_start / 4;
4220 num_iso_blocks = (part_start + (entry_count + 3) / 4) / 4 - iso_block + 1;
4221 for (i = 0; i < num_iso_blocks; i++) {
4222 ret = src->read_block(src, iso_block + (uint32_t) i, buf + i * 2048);
4223 if (ret < 0) {
4224 sprintf(comments + strlen(comments),
4225 "Cannot read array block at 2k LBA %.f, ",
4226 (double) iso_block);
4227 ret = 0; goto ex;
4228 }
4229 }
4230 part_array = buf + (part_start % 4) * 512;
4231
4232 crc = iso_crc32_gpt((unsigned char *) part_array, 128 * entry_count, 0);
4233 if (crc != array_crc)
4234 sprintf(comments + strlen(comments),
4235 "Array CRC 0x%8x wrong. Should be 0x%8x, ", array_crc, crc);
4236
4237 /* Compare entries */
4238 entries_diff = 0;
4239 for (i = 0; i < (int) entry_count; i++) {
4240 b_part = part_array + 128 * i;
4241 m_part = ((uint8_t *) image->system_area_data) +
4242 sai->gpt_part_start * 512 + 128 * i;
4243 for (j = 0; j < 128; j++)
4244 if (b_part[j] != m_part[j])
4245 break;
4246 if (j < 128) {
4247 if (!entries_diff) {
4248 strcat(comments, "Entries differ for partitions");
4249 entries_diff = 1;
4250 }
4251 sprintf(comments + strlen(comments), " %d", i + 1);
4252 }
4253 }
4254 if (entries_diff) {
4255 strcat(comments, ", ");
4256 ret = 0; goto ex;
4257 }
4258
4259 ret = 1;
4260 ex:;
4261 if (comments != NULL) {
4262 l = strlen(comments);
4263 if (l > 2)
4264 if (comments[l - 2] == ',' && comments[l - 1] == ' ')
4265 comments[l - 2] = 0;
4266 sai->gpt_backup_comments = strdup(comments);
4267 if (sai->gpt_backup_comments == NULL)
4268 ret = ISO_OUT_OF_MEM;
4269 }
4270 LIBISO_FREE_MEM(comments);
4271 LIBISO_FREE_MEM(buf);
4272 return ret;
4273 }
4274
4275 static
iso_analyze_gpt_head(IsoImage * image,IsoDataSource * src,int flag)4276 int iso_analyze_gpt_head(IsoImage *image, IsoDataSource *src, int flag)
4277 {
4278 struct iso_imported_sys_area *sai;
4279 uint8_t *head;
4280 uint32_t crc;
4281 uint64_t part_start;
4282 int ret;
4283 unsigned char *crc_buf = NULL;
4284
4285 sai = image->imported_sa_info;
4286 head = ((uint8_t *) image->system_area_data) + 512;
4287 LIBISO_ALLOC_MEM(crc_buf, unsigned char, 512);
4288
4289 /* Is this a GPT header with digestible parameters ? */
4290 ret = iso_seems_usable_gpt_head(head, 0);
4291 if (ret <= 0)
4292 goto ex;
4293 memcpy(crc_buf, head, 512);
4294 memset(crc_buf + 16, 0, 4); /* CRC is computed when head_crc is 0 */
4295 sai->gpt_head_crc_found = iso_read_lsb(head + 16, 4);
4296 sai->gpt_head_crc_should = iso_crc32_gpt((unsigned char *) crc_buf, 92, 0);
4297 if (sai->gpt_head_crc_found != sai->gpt_head_crc_should) {
4298 /* There was a bug during libisofs-1.2.4 to libisofs-1.2.8
4299 (fixed in rev 1071). So accept the buggy CRC if it matches the
4300 whole GPT header block. */
4301 crc = iso_crc32_gpt((unsigned char *) crc_buf, 512, 0);
4302 if (sai->gpt_head_crc_found != crc)
4303 {ret = 0; goto ex;}
4304 }
4305 part_start = iso_read_lsb64(head + 72);
4306 sai->gpt_max_entries = iso_read_lsb(head + 80, 4);
4307 if (part_start + (sai->gpt_max_entries + 3) / 4 > 64)
4308 {ret = 0; goto ex;}
4309
4310 /* Fetch desired information */
4311 memcpy(sai->gpt_disk_guid, head + 56, 16);
4312 sai->gpt_part_start = part_start;
4313 sai->gpt_backup_lba = iso_read_lsb64(head + 32);
4314 sai->gpt_first_lba = iso_read_lsb64(head + 40);
4315 sai->gpt_last_lba = iso_read_lsb64(head + 48);
4316 sai->gpt_array_crc_found = iso_read_lsb(head + 88, 4);
4317 sai->gpt_array_crc_should =
4318 iso_crc32_gpt((unsigned char *) image->system_area_data +
4319 sai->gpt_part_start * 512,
4320 sai->gpt_max_entries * 128, 0);
4321
4322 ret = iso_analyze_gpt_backup(image, src, 0);
4323 if (ret < 0)
4324 goto ex;
4325
4326 ret = 1;
4327 ex:
4328 LIBISO_FREE_MEM(crc_buf);
4329 return ret;
4330 }
4331
4332 static
iso_analyze_gpt(IsoImage * image,IsoDataSource * src,int flag)4333 int iso_analyze_gpt(IsoImage *image, IsoDataSource *src, int flag)
4334 {
4335 int ret, i, j;
4336 uint64_t start_block, block_count, flags, end_block, j_end, j_start;
4337 uint8_t *part;
4338 struct iso_imported_sys_area *sai;
4339
4340 sai = image->imported_sa_info;
4341
4342 ret = iso_analyze_gpt_head(image, src, 0);
4343 if (ret <= 0)
4344 return ret;
4345
4346 for (i = 0; i < (int) sai->gpt_max_entries; i++) {
4347 part = ((uint8_t *) image->system_area_data) +
4348 sai->gpt_part_start * 512 + 128 * i;
4349 for (j = 0; j < 128; j++)
4350 if (part[j])
4351 break;
4352 if (j >= 128) /* all zero, invalid entry */
4353 continue;
4354 start_block = iso_read_lsb64(part + 32);
4355 block_count = iso_read_lsb64(part + 40);
4356 flags = iso_read_lsb64(part + 48);
4357 if ((start_block == 0 && block_count == 0) ||
4358 block_count + 1 < start_block)
4359 continue;
4360 block_count = block_count + 1 - start_block;
4361 if (sai->gpt_req == NULL) {
4362 sai->gpt_req = calloc(ISO_GPT_ENTRIES_MAX,
4363 sizeof(struct iso_gpt_partition_request *));
4364 if (sai->gpt_req == NULL)
4365 return ISO_OUT_OF_MEM;
4366 }
4367 ret = iso_quick_gpt_entry(sai->gpt_req, &(sai->gpt_req_count),
4368 start_block, block_count,
4369 part, part + 16, flags, part + 56);
4370 if (ret < 0)
4371 return ret;
4372 sai->gpt_req[sai->gpt_req_count - 1]->idx = i + 1;
4373 }
4374
4375 /* sai->gpt_req_flags :
4376 bit0= GPT partitions may overlap
4377 >>> bit1= with bit0: neatly nested partitions
4378 without : neatly divided disk
4379 */
4380 for (i = 0; i < (int) sai->gpt_req_count && !(sai->gpt_req_flags & 1);
4381 i++) {
4382 if (sai->gpt_req[i]->block_count == 0)
4383 continue;
4384 start_block = sai->gpt_req[i]->start_block;
4385 end_block = start_block + sai->gpt_req[i]->block_count;
4386 for (j = i + 1; j < (int) sai->gpt_req_count; j++) {
4387 if (sai->gpt_req[j]->block_count == 0)
4388 continue;
4389 j_start = sai->gpt_req[j]->start_block;
4390 j_end = j_start + sai->gpt_req[j]->block_count;
4391 if ((start_block <= j_start && j_start < end_block) ||
4392 (start_block <= j_end && j_end < end_block) ||
4393 (j_start <= start_block && start_block < j_end)) {
4394 sai->gpt_req_flags |= 1;
4395 break;
4396 }
4397 }
4398 }
4399
4400 /* Check first GPT partition for ISO partition offset */
4401 if (sai->partition_offset == 0 && sai->mbr_req_count > 0 &&
4402 sai->gpt_req_count > 0) {
4403 if (sai->mbr_req[0]->type_byte == 0xee &&
4404 sai->mbr_req[0]->start_block == 1) { /* protective MBR */
4405 start_block = sai->gpt_req[0]->start_block;
4406 block_count = sai->gpt_req[0]->block_count;
4407 if (start_block >= 64 && block_count >= 72 &&
4408 start_block <= 2048 && start_block % 4 == 0 &&
4409 block_count % 4 == 0) {
4410
4411 ret = iso_analyze_partition_offset(image, src, start_block,
4412 block_count, 0);
4413 if (ret < 0)
4414 return ret;
4415 }
4416 }
4417 }
4418
4419 return 1;
4420 }
4421
4422
4423 static
iso_analyze_apm_head(IsoImage * image,IsoDataSource * src,int flag)4424 int iso_analyze_apm_head(IsoImage *image, IsoDataSource *src, int flag)
4425 {
4426 struct iso_imported_sys_area *sai;
4427 char *sad;
4428 uint32_t block_size;
4429
4430 sai = image->imported_sa_info;
4431 sad = image->system_area_data;
4432
4433 if (sad[0] != 'E' || sad[1] != 'R')
4434 return 0;
4435 block_size = iso_read_msb(((uint8_t *) sad) + 2, 2);
4436 if (block_size != 2048 && block_size != 512)
4437 return 0;
4438 sai->apm_block_size = block_size;
4439 sai->apm_req_flags |= 4 | 2; /* start_block and block_count are in
4440 block_size units, do not fill gaps */
4441 return 1;
4442 }
4443
4444 static
iso_analyze_apm(IsoImage * image,IsoDataSource * src,int flag)4445 int iso_analyze_apm(IsoImage *image, IsoDataSource *src, int flag)
4446 {
4447 int ret, i;
4448 uint32_t map_entries, start_block, block_count, flags;
4449 char *sad, *part, name[33], type_string[33];
4450 struct iso_imported_sys_area *sai;
4451
4452 sai = image->imported_sa_info;
4453 sad = image->system_area_data;
4454
4455 ret = iso_analyze_apm_head(image, src, 0);
4456 if (ret <= 0)
4457 return ret;
4458
4459 part = sad + sai->apm_block_size;
4460 map_entries = iso_read_msb(((uint8_t *) part) + 4, 4);
4461 for (i = 0; i < (int) map_entries; i++) {
4462 part = sad + (i + 1) * sai->apm_block_size;
4463 if (part[0] != 'P' || part[1] != 'M')
4464 break;
4465 flags = iso_read_msb(((uint8_t *) part) + 88, 4);
4466 if (!(flags & 3))
4467 continue;
4468 memcpy(type_string, part + 48, 32);
4469 type_string[32] = 0;
4470 if(strcmp(type_string, "Apple_partition_map") == 0)
4471 continue;
4472 start_block = iso_read_msb(((uint8_t *) part) + 8, 4);
4473 block_count = iso_read_msb(((uint8_t *) part + 12), 4);
4474 memcpy(name, part + 16, 32);
4475 name[32] = 0;
4476 if (sai->apm_req == NULL) {
4477 sai->apm_req = calloc(ISO_APM_ENTRIES_MAX,
4478 sizeof(struct iso_apm_partition_request *));
4479 if (sai->apm_req == NULL)
4480 return ISO_OUT_OF_MEM;
4481 }
4482 ret = iso_quick_apm_entry(sai->apm_req, &(sai->apm_req_count),
4483 start_block, block_count, name, type_string);
4484 if (ret <= 0)
4485 return ret;
4486 if (strncmp(name, "Gap", 3) == 0 &&
4487 strcmp(type_string, "ISO9660_data") == 0) {
4488 if ('0' <= name[3] && name[3] <= '9' && (name[4] == 0 ||
4489 ('0' <= name[4] && name[4] <= '9' && name[5] == 0))) {
4490 sai->apm_gap_count++;
4491 sai->apm_req_flags &= ~2;
4492 }
4493 }
4494 }
4495 return 1;
4496 }
4497
4498 static
iso_analyze_mips(IsoImage * image,IsoDataSource * src,int flag)4499 int iso_analyze_mips(IsoImage *image, IsoDataSource *src, int flag)
4500 {
4501 int ret = 0, spt, bps, i, j, idx;
4502 uint32_t magic, chk, head_chk;
4503 char *sad;
4504 uint8_t *usad, *upart;
4505 struct iso_imported_sys_area *sai;
4506 IsoNode *node;
4507
4508 sai = image->imported_sa_info;
4509 sad = image->system_area_data;
4510 usad = (uint8_t *) sad;
4511
4512 magic = iso_read_msb(usad, 4);
4513 if (magic != 0x0be5a941)
4514 return 0;
4515 spt = iso_read_msb(usad + 38, 2);
4516 bps = iso_read_msb(usad + 40, 2);
4517 if (spt != 32 || bps != 512)
4518 return 0;
4519 chk = 0;
4520 for (i = 0; i < 504; i += 4)
4521 chk -= iso_read_msb(usad + i, 4);
4522 head_chk = iso_read_msb(usad + 504, 4);
4523 if (chk != head_chk)
4524 return 0;
4525
4526 /* Verify that partitions 1 to 8 are empty */
4527 for (j = 312; j < 408; j++)
4528 if (sad[j])
4529 return 0;
4530
4531 /* >>> verify that partitions 9 and 10 match the image size */;
4532
4533 for (i = 0; i < 15; i++) {
4534 upart = usad + 72 + 16 * i;
4535 for (j = 0; j < 16; j++)
4536 if (upart[j])
4537 break;
4538 if (j == 16)
4539 continue;
4540 if (sai->mips_vd_entries == NULL) {
4541 sai->mips_boot_file_paths = calloc(15, sizeof(char *));
4542 sai->mips_vd_entries = calloc(15,
4543 sizeof(struct iso_mips_voldir_entry *));
4544 if (sai->mips_vd_entries == NULL ||
4545 sai->mips_boot_file_paths == NULL)
4546 return ISO_OUT_OF_MEM;
4547 sai->num_mips_boot_files = 0;
4548 for (j = 0; j < 15; j++) {
4549 sai->mips_boot_file_paths[j] = NULL;
4550 sai->mips_vd_entries[j] = NULL;
4551 }
4552 }
4553
4554 /* Assess boot file entry */
4555 if (sai->num_mips_boot_files >= 15)
4556 return ISO_BOOT_TOO_MANY_MIPS;
4557 idx = sai->num_mips_boot_files;
4558 sai->mips_vd_entries[idx] =
4559 calloc(1, sizeof(struct iso_mips_voldir_entry));
4560 if (sai->mips_vd_entries[idx] == NULL)
4561 return ISO_OUT_OF_MEM;
4562 memcpy(sai->mips_vd_entries[idx]->name, upart, 8);
4563 sai->mips_vd_entries[idx]->name[8] = 0;
4564 sai->mips_vd_entries[idx]->boot_block = iso_read_msb(upart + 8, 4);
4565 sai->mips_vd_entries[idx]->boot_bytes = iso_read_msb(upart + 12, 4);
4566 ret = iso_tree_get_node_of_block(image, NULL,
4567 sai->mips_vd_entries[idx]->boot_block / 4,
4568 &node, NULL, 0);
4569 if (ret > 0)
4570 sai->mips_boot_file_paths[idx] = iso_tree_get_node_path(node);
4571 sai->num_mips_boot_files++;
4572 }
4573 if (sai->num_mips_boot_files > 0)
4574 sai->system_area_options = (1 << 2);/* MIPS Big Endian Volume Header */
4575
4576 return ret;
4577 }
4578
4579 static
iso_analyze_mipsel(IsoImage * image,IsoDataSource * src,int flag)4580 int iso_analyze_mipsel(IsoImage *image, IsoDataSource *src, int flag)
4581 {
4582 int ret = 0, i, section_count;
4583 char *sad;
4584 uint8_t *usad;
4585 uint32_t magic;
4586 struct iso_imported_sys_area *sai;
4587 IsoNode *node;
4588 IsoFile *file;
4589 struct iso_file_section *sections = NULL;
4590
4591 sai = image->imported_sa_info;
4592 sad = image->system_area_data;
4593 usad = (uint8_t *) sad;
4594
4595 for (i = 0; i < 8; i++)
4596 if (sad[i])
4597 return 0;
4598 magic = iso_read_lsb(usad + 8, 4);
4599 if (magic != 0x0002757a)
4600 return 0;
4601
4602 sai->mipsel_p_vaddr = iso_read_lsb(usad + 16, 4);
4603 sai->mipsel_e_entry = iso_read_lsb(usad + 20, 4);
4604 sai->mipsel_p_filesz = iso_read_lsb(usad + 24, 4) * 512;
4605 sai->mipsel_seg_start = iso_read_lsb(usad + 28, 4);
4606 ret = iso_tree_get_node_of_block(image, NULL, sai->mipsel_seg_start / 4,
4607 &node, NULL, 0);
4608 if (ret > 0) {
4609 sai->mipsel_boot_file_path = iso_tree_get_node_path(node);
4610 file = (IsoFile *) node;
4611 ret = iso_file_get_old_image_sections(file, §ion_count,
4612 §ions, 0);
4613 if (ret > 0 && section_count > 0) {
4614 if (sections[0].block < (1 << 30) &&
4615 sections[0].block * 4 < sai->mipsel_seg_start)
4616 sai->mipsel_p_offset = sai->mipsel_seg_start -
4617 sections[0].block * 4;
4618 free(sections);
4619 }
4620 }
4621 /* DEC Boot Block for MIPS Little Endian */
4622 sai->system_area_options = (2 << 2);
4623
4624 return 1;
4625 }
4626
4627 static
iso_analyze_sun(IsoImage * image,IsoDataSource * src,int flag)4628 int iso_analyze_sun(IsoImage *image, IsoDataSource *src, int flag)
4629 {
4630 int ret = 0, i, idx;
4631 char *sad;
4632 uint8_t *usad, checksum[2];
4633 uint16_t perms;
4634 uint64_t last_core_block;
4635 struct iso_imported_sys_area *sai;
4636 IsoNode *node;
4637
4638 sai = image->imported_sa_info;
4639 sad = image->system_area_data;
4640 usad = (uint8_t *) sad;
4641
4642 if (iso_read_msb(usad + 128, 4) != 1 ||
4643 iso_read_msb(usad + 140, 2) != 8 ||
4644 iso_read_msb(usad + 188, 4) != 0x600ddeee ||
4645 iso_read_msb(usad + 430, 2) != 1 ||
4646 iso_read_msb(usad + 508, 2) != 0xdabe)
4647 return 0;
4648 if (iso_read_msb(usad + 142, 2) != 4 ||
4649 iso_read_msb(usad + 144, 2) != 0x10 ||
4650 iso_read_msb(usad + 444, 4) != 0 ||
4651 sai->image_size > 0x3fffffff ||
4652 iso_read_msb(usad + 448, 4) < ((int64_t) sai->image_size * 4) - 600 ||
4653 iso_read_msb(usad + 448, 4) > sai->image_size * 4)
4654 return 0;
4655 checksum[0] = checksum[1] = 0;
4656 for (i = 0; i < 510; i += 2) {
4657 checksum[0] ^= usad[i];
4658 checksum[1] ^= usad[i + 1];
4659 }
4660 if (checksum[0] != usad[510] || checksum[1] != usad[511])
4661 return 0;
4662
4663 sai->sparc_disc_label = calloc(1, 129);
4664 if (sai->sparc_disc_label == NULL)
4665 return ISO_OUT_OF_MEM;
4666 memcpy(sai->sparc_disc_label, sad, 128);
4667 sai->sparc_disc_label[128] = 0;
4668 sai->sparc_heads_per_cyl = iso_read_msb(usad + 436, 2);
4669 sai->sparc_secs_per_head = iso_read_msb(usad + 438, 2);
4670
4671 for (i = 0; i < 8; i++) {
4672 perms = iso_read_msb(usad + 144 + 4 * i, 2);
4673 if (perms == 0)
4674 continue;
4675 if (sai->sparc_entries == NULL) {
4676 sai->sparc_entries = calloc(8,
4677 sizeof(struct iso_sun_disk_label_entry));
4678 if (sai->sparc_entries == NULL)
4679 return ISO_OUT_OF_MEM;
4680 }
4681 idx = sai->sparc_entry_count;
4682 sai->sparc_entries[idx].idx = i + 1;
4683 sai->sparc_entries[idx].id_tag = iso_read_msb(usad + 142 + 4 * i, 2);
4684 sai->sparc_entries[idx].permissions = perms;
4685 sai->sparc_entries[idx].start_cyl =
4686 iso_read_msb(usad + 444 + 8 * i, 4);
4687 sai->sparc_entries[idx].num_blocks =
4688 iso_read_msb(usad + 448 + 8 * i, 4);
4689 sai->sparc_entry_count++;
4690 }
4691
4692 /* GRUB2 SUN SPARC Core File Address */
4693 sai->sparc_grub2_core_adr = iso_read_msb64(usad + 552);
4694 sai->sparc_grub2_core_size = iso_read_msb(usad + 560, 4);
4695 last_core_block = (sai->sparc_grub2_core_adr +
4696 sai->sparc_grub2_core_size + 2047) / 2048;
4697 if (last_core_block > 0)
4698 last_core_block--;
4699 if (last_core_block > 17 && last_core_block < sai->image_size) {
4700 ret = iso_tree_get_node_of_block(image, NULL,
4701 (uint32_t) last_core_block, &node,
4702 NULL, 0);
4703 if (ret > 0) {
4704 iso_node_ref(node);
4705 sai->sparc_core_node = (IsoFile *) node;
4706 }
4707 } else {
4708 sai->sparc_grub2_core_adr = 0;
4709 sai->sparc_grub2_core_size = 0;
4710 }
4711
4712 /* SUN Disk Label for SUN SPARC */
4713 sai->system_area_options = (3 << 2);
4714
4715 return 1;
4716 }
4717
4718 static
iso_analyze_hppa(IsoImage * image,IsoDataSource * src,int flag)4719 int iso_analyze_hppa(IsoImage *image, IsoDataSource *src, int flag)
4720 {
4721 int ret = 0, i, cmd_adr, cmd_len;
4722 char *sad, *paths[4];
4723 uint8_t *usad;
4724 uint16_t magic;
4725 uint32_t adrs[4];
4726 struct iso_imported_sys_area *sai;
4727 IsoNode *node;
4728
4729 sai = image->imported_sa_info;
4730 sad = image->system_area_data;
4731 usad = (uint8_t *) sad;
4732
4733 magic = iso_read_msb(usad, 2);
4734 if (magic != 0x8000 || strncmp(sad + 2, "PALO", 5) != 0 ||
4735 sad[7] < 4 || sad[7] > 5)
4736 return 0;
4737
4738 sai->hppa_hdrversion = sad[7];
4739 if (sai->hppa_hdrversion == 4) {
4740 cmd_len = 127;
4741 cmd_adr = 24;
4742 } else {
4743 cmd_len = 1023;
4744 cmd_adr = 1024;
4745 }
4746 sai->hppa_cmdline = calloc(1, cmd_len + 1);
4747 if (sai->hppa_cmdline == NULL)
4748 return ISO_OUT_OF_MEM;
4749 memcpy(sai->hppa_cmdline, sad + cmd_adr, cmd_len);
4750 sai->hppa_cmdline[cmd_len] = 0;
4751 adrs[0] = sai->hppa_kern32_adr = iso_read_msb(usad + 8, 4);
4752 sai->hppa_kern32_len = iso_read_msb(usad + 12, 4);
4753 adrs[1] = sai->hppa_kern64_adr = iso_read_msb(usad + 232, 4);
4754 sai->hppa_kern64_len = iso_read_msb(usad + 236, 4);
4755 adrs[2] = sai->hppa_ramdisk_adr = iso_read_msb(usad + 16, 4);
4756 sai->hppa_ramdisk_len = iso_read_msb(usad + 20, 4);
4757 adrs[3] = sai->hppa_bootloader_adr = iso_read_msb(usad + 240, 4);
4758 sai->hppa_bootloader_len = iso_read_msb(usad + 244, 4);
4759 for (i = 0; i < 4; i++) {
4760 paths[i] = NULL;
4761 ret = iso_tree_get_node_of_block(image, NULL, adrs[i] / 2048,
4762 &node, NULL, 0);
4763 if (ret > 0)
4764 paths[i] = iso_tree_get_node_path(node);
4765 }
4766 sai->hppa_kernel_32 = paths[0];
4767 sai->hppa_kernel_64 = paths[1];
4768 sai->hppa_ramdisk = paths[2];
4769 sai->hppa_bootloader = paths[3];
4770
4771 if (sai->hppa_hdrversion == 5)
4772 sai->hppa_ipl_entry = iso_read_msb(usad + 248, 4);
4773
4774 /* HP-PA PALO boot sector version 4 or 5 for HP PA-RISC */
4775 sai->system_area_options = (sai->hppa_hdrversion << 2);
4776
4777 return 1;
4778 }
4779
4780 static
iso_analyze_alpha_boot(IsoImage * image,IsoDataSource * src,int flag)4781 int iso_analyze_alpha_boot(IsoImage *image, IsoDataSource *src, int flag)
4782 {
4783 int ret = 0, i, section_count;
4784 char *sad;
4785 uint8_t *usad;
4786 struct iso_imported_sys_area *sai;
4787 IsoNode *node;
4788 IsoFile *file;
4789 uint64_t checksum_found, checksum_should = 0, size;
4790 struct iso_file_section *sections = NULL;
4791
4792 sai = image->imported_sa_info;
4793 sad = image->system_area_data;
4794 usad = (uint8_t *) sad;
4795
4796 checksum_found = iso_read_lsb64(usad + 504);
4797 for (i = 0; i < 63; i++)
4798 checksum_should += iso_read_lsb64(usad + 8 * i);
4799 if (checksum_found != checksum_should)
4800 return 0;
4801 sai->alpha_boot_image = NULL;
4802 sai->alpha_boot_image_size = (uint64_t) iso_read_lsb64(usad + 480);
4803 sai->alpha_boot_image_adr = (uint64_t) iso_read_lsb64(usad + 488);
4804 ret = iso_tree_get_node_of_block(image, NULL,
4805 (uint32_t) (sai->alpha_boot_image_adr / 4),
4806 &node, NULL, 0);
4807 if (ret > 0) {
4808 if (iso_node_get_type(node) != LIBISO_FILE)
4809 return 0;
4810 file = (IsoFile *) node;
4811 ret = iso_file_get_old_image_sections(file, §ion_count,
4812 §ions, 0);
4813 if (ret > 0 && section_count > 0) {
4814 size = sections[0].size / 512 + !!(sections[0].size % 512);
4815 free(sections);
4816 if (size != sai->alpha_boot_image_size)
4817 return 0;
4818 }
4819 sai->alpha_boot_image = iso_tree_get_node_path(node);
4820 } else if (strncmp(sad, "Linux/Alpha aboot for ISO filesystem.", 37) != 0
4821 || sad[37] != 0) {
4822 return 0; /* Want to see either boot file or genisoimage string */
4823 }
4824 sai->system_area_options = (6 << 2);
4825 return 1;
4826 }
4827
4828
4829 struct iso_impsysa_result {
4830 char *buf;
4831 int byte_count;
4832 char **lines;
4833 int line_count;
4834 };
4835
4836 static
iso_impsysa_result_new(struct iso_impsysa_result ** r,int flag)4837 int iso_impsysa_result_new(struct iso_impsysa_result **r, int flag)
4838 {
4839 int ret;
4840
4841 LIBISO_ALLOC_MEM(*r, struct iso_impsysa_result, 1);
4842 (*r)->buf = NULL;
4843 (*r)->lines = NULL;
4844 ret = 1;
4845 ex:
4846 if (ret <= 0) {
4847 LIBISO_FREE_MEM(*r);
4848 *r = NULL;
4849 }
4850 return ret;
4851 }
4852
4853 static
iso_impsysa_result_destroy(struct iso_impsysa_result ** r,int flag)4854 void iso_impsysa_result_destroy(struct iso_impsysa_result **r, int flag)
4855 {
4856 if (*r == NULL)
4857 return;
4858 if ((*r)->buf != NULL)
4859 free((*r)->buf);
4860 if ((*r)->lines != NULL)
4861 free((*r)->lines);
4862 free(*r);
4863 *r = NULL;
4864 }
4865
4866 static
iso_impsysa_line(struct iso_impsysa_result * target,char * msg)4867 void iso_impsysa_line(struct iso_impsysa_result *target, char *msg)
4868 {
4869 if (target->buf != NULL)
4870 strcpy(target->buf + target->byte_count, msg);
4871 if (target->lines != NULL)
4872 target->lines[target->line_count] = target->buf + target->byte_count;
4873 target->byte_count += strlen(msg) + 1;
4874 target->line_count++;
4875 }
4876
4877 static
iso_impsysa_report_text(struct iso_impsysa_result * target,char * msg,char * path,int flag)4878 void iso_impsysa_report_text(struct iso_impsysa_result *target,
4879 char *msg, char *path, int flag)
4880 {
4881 if (strlen(msg) + strlen(path) >= ISO_MAX_SYSAREA_LINE_LENGTH)
4882 sprintf(msg + strlen(msg), "(too long to show here)");
4883 else
4884 strcat(msg, path);
4885 iso_impsysa_line(target, msg);
4886 }
4887
4888 static
iso_impsysa_reduce_na(uint32_t block,uint32_t * na,uint32_t claim)4889 void iso_impsysa_reduce_na(uint32_t block, uint32_t *na, uint32_t claim)
4890 {
4891 if ((*na == 0 || *na > claim) && block < claim)
4892 *na = claim;
4893 }
4894
4895 static
iso_impsysa_reduce_next_above(IsoImage * image,uint32_t block,uint32_t * next_above,int flag)4896 int iso_impsysa_reduce_next_above(IsoImage *image, uint32_t block,
4897 uint32_t *next_above, int flag)
4898 {
4899 int i, section_count, ret;
4900 struct iso_imported_sys_area *sai;
4901 struct el_torito_boot_image *img;
4902 struct iso_file_section *sections = NULL;
4903
4904 sai = image->imported_sa_info;
4905
4906 /* PVD, path table, root directory of active and of first session */
4907 for (i = 0; i < sai->num_meta_struct_blocks; i++)
4908 iso_impsysa_reduce_na(block, next_above, sai->meta_struct_blocks[i]);
4909
4910 /* Partition tables */
4911 for (i = 0; i < sai->mbr_req_count; i++) {
4912 iso_impsysa_reduce_na(block, next_above,
4913 (uint32_t) (sai->mbr_req[i]->start_block / 4));
4914 iso_impsysa_reduce_na(block, next_above,
4915 (uint32_t) ((sai->mbr_req[i]->start_block +
4916 sai->mbr_req[i]->block_count) / 4));
4917 }
4918 for (i = 0; i < sai->gpt_req_count; i++) {
4919 iso_impsysa_reduce_na(block, next_above,
4920 (uint32_t) (sai->gpt_req[i]->start_block / 4));
4921 iso_impsysa_reduce_na(block, next_above,
4922 (uint32_t) ((sai->gpt_req[i]->start_block +
4923 sai->gpt_req[i]->block_count) / 4));
4924 }
4925 for (i = 0; i < sai->apm_req_count; i++) {
4926 iso_impsysa_reduce_na(block, next_above,
4927 (uint32_t) (sai->apm_req[i]->start_block /
4928 (2048 / sai->apm_block_size)));
4929 iso_impsysa_reduce_na(block, next_above,
4930 (uint32_t) ((sai->apm_req[i]->start_block +
4931 sai->apm_req[i]->block_count) /
4932 (2048 / sai->apm_block_size)));
4933 }
4934 if (image->bootcat != NULL) {
4935 if (image->bootcat->node != NULL)
4936 iso_impsysa_reduce_na(block, next_above,
4937 image->bootcat->node->lba);
4938 for (i= 0; i < image->bootcat->num_bootimages; i++) {
4939 img = image->bootcat->bootimages[i];
4940 ret = iso_file_get_old_image_sections(img->image, §ion_count,
4941 §ions, 0);
4942 if (ret > 0 && section_count > 0)
4943 if (block != sections[0].block)
4944 iso_impsysa_reduce_na(block, next_above,
4945 sections[0].block);
4946 if (sections != NULL) {
4947 free(sections);
4948 sections = NULL;
4949 }
4950 }
4951 }
4952
4953 iso_impsysa_reduce_na(block, next_above, sai->image_size);
4954
4955 return ISO_SUCCESS;
4956 }
4957
4958 /* @param flag bit0= try to estimate the size if no path is found
4959 */
4960 static
iso_impsysa_report_blockpath(IsoImage * image,struct iso_impsysa_result * target,char * msg,uint32_t start_block,int flag)4961 void iso_impsysa_report_blockpath(IsoImage *image,
4962 struct iso_impsysa_result *target, char *msg,
4963 uint32_t start_block, int flag)
4964 {
4965 int ret;
4966 char *path = NULL, *cpt;
4967 IsoNode *node;
4968 uint32_t next_above = 0;
4969 uint32_t size;
4970
4971 ret = iso_tree_get_node_of_block(image, NULL, start_block,
4972 &node, &next_above, 0);
4973 if (ret <= 0) {
4974 if (!(flag & 1))
4975 return;
4976 /* Look for next claimed block for estimating file size.
4977 next_above already holds the best data file candidate.
4978 */
4979 ret = iso_impsysa_reduce_next_above(image, start_block, &next_above, 0);
4980 if (ret < 0)
4981 return;
4982 if (next_above == 0)
4983 return;
4984 size = next_above - start_block;
4985
4986 /* Replace in msg "path" by "blks", report number in blocks of 2048 */
4987 cpt = strstr(msg, "path");
4988 if (cpt == NULL)
4989 return;
4990 path = iso_alloc_mem(strlen(msg) + 20, 1, 0);
4991 if (path == NULL)
4992 return;
4993 strcpy(path, msg);
4994 memcpy(path + (cpt - msg), "blks", 4);
4995 sprintf(path + strlen(path), "%u", (unsigned int) size);
4996 iso_impsysa_report_text(target, path, "", 0);
4997 free(path);
4998 return;
4999 }
5000 path = iso_tree_get_node_path(node);
5001 if (path != NULL) {
5002 iso_impsysa_report_text(target, msg, path, 0);
5003 free(path);
5004 }
5005 }
5006
5007 static
iso_impsysa_report(IsoImage * image,struct iso_impsysa_result * target,int flag)5008 int iso_impsysa_report(IsoImage *image, struct iso_impsysa_result *target,
5009 int flag)
5010 {
5011 char *msg = NULL, *local_name = NULL, *path;
5012 int i, j, sa_type, sao, sa_sub, ret, idx;
5013 size_t local_len;
5014 struct iso_imported_sys_area *sai;
5015 struct iso_mbr_partition_request *part;
5016 struct iso_gpt_partition_request *gpt_entry;
5017 struct iso_apm_partition_request *apm_entry;
5018 static char *alignments[4] = {"auto", "on", "off", "all"};
5019 IsoWriteOpts *opts = NULL;
5020 struct iso_sun_disk_label_entry *sparc_entry;
5021
5022 sai = image->imported_sa_info;
5023
5024 LIBISO_ALLOC_MEM(msg, char, ISO_MAX_SYSAREA_LINE_LENGTH);
5025
5026 if (sai == NULL)
5027 {ret = 0; goto ex;}
5028 if (!sai->is_not_zero)
5029 {ret = 0; goto ex;}
5030 sao = sai->system_area_options;
5031 sprintf(msg, "System area options: 0x%-8.8x", (unsigned int) sao);
5032 iso_impsysa_line(target, msg);
5033
5034 /* Human readable form of system_area_options */
5035 sa_type = (sao >> 2) & 63;
5036 sa_sub = (sao >> 10) & 15;
5037 strcpy(msg, "System area summary:");
5038 if (sa_type == 0) {
5039 if ((sao & 3) || sa_sub == 1 || sa_sub == 2) {
5040 strcat(msg, " MBR");
5041 if (sao & 2)
5042 strcat(msg, " isohybrid");
5043 else if (sao & 1)
5044 strcat(msg, " protective-msdos-label");
5045 else if (sa_sub == 1) {
5046 strcat(msg, " CHRP");
5047 }
5048 if ((sao & (1 << 14)) && !(sao & 2))
5049 strcat(msg, " grub2-mbr");
5050 sprintf(msg + strlen(msg), " cyl-align-%s",
5051 alignments[(sao >> 8) & 3]);
5052 } else if (sai->prep_part_start > 0 && sai->prep_part_size > 0) {
5053 strcat(msg, " PReP");
5054 } else if (sai->mbr_req_count > 0) {
5055 strcat(msg, " MBR");
5056 } else {
5057 strcat(msg, " not-recognized");
5058 }
5059 } else if (sa_type == 1) {
5060 strcat(msg, " MIPS-Big-Endian");
5061 } else if (sa_type == 2) {
5062 strcat(msg, " MIPS-Little-Endian");
5063 } else if (sa_type == 3) {
5064 strcat(msg, " SUN-SPARC-Disk-Label");
5065 } else if (sa_type == 4 || sa_type == 5) {
5066 sprintf(msg + strlen(msg), " HP-PA-PALO");
5067 } else if (sa_type == 6) {
5068 sprintf(msg + strlen(msg), " DEC-Alpha");
5069 } else {
5070 sprintf(msg + strlen(msg), " unkown-system-area-type-%d", sa_type);
5071 }
5072 if (sai->gpt_req_count > 0)
5073 strcat(msg, " GPT");
5074 if (sai->apm_req_count > 0)
5075 strcat(msg, " APM");
5076
5077 iso_impsysa_line(target, msg); /* System area summary */
5078
5079 sprintf(msg, "ISO image size/512 : %.f",
5080 ((double) sai->image_size) * 4.0);
5081 iso_impsysa_line(target, msg);
5082 if (sai->mbr_req_count > 0 && sa_type == 0) {
5083 sprintf(msg, "Partition offset : %d", sai->partition_offset);
5084 iso_impsysa_line(target, msg);
5085 }
5086 if (sa_type >= 4 && sa_type <= 5) {
5087 sprintf(msg, "PALO header version: %d", sai->hppa_hdrversion);
5088 iso_impsysa_line(target, msg);
5089 sprintf(msg, "HP-PA cmdline : ");
5090 iso_impsysa_report_text(target, msg, sai->hppa_cmdline, 0);
5091 sprintf(msg, "HP-PA boot files : ByteAddr ByteSize Path");
5092 iso_impsysa_line(target, msg);
5093 sprintf(msg, "HP-PA 32-bit kernel: %10u %10u ",
5094 sai->hppa_kern32_adr, sai->hppa_kern32_len);
5095 iso_impsysa_report_text(target, msg,
5096 sai->hppa_kernel_32 != NULL ?
5097 sai->hppa_kernel_32 : "(not found in ISO)", 0);
5098 sprintf(msg, "HP-PA 64-bit kernel: %10u %10u ",
5099 sai->hppa_kern64_adr, sai->hppa_kern64_len);
5100 iso_impsysa_report_text(target, msg,
5101 sai->hppa_kernel_64 != NULL ?
5102 sai->hppa_kernel_64 : "(not found in ISO)", 0);
5103 sprintf(msg, "HP-PA ramdisk : %10u %10u ",
5104 sai->hppa_ramdisk_adr, sai->hppa_ramdisk_len);
5105 iso_impsysa_report_text(target, msg,
5106 sai->hppa_ramdisk != NULL ?
5107 sai->hppa_ramdisk : "(not found in ISO)", 0);
5108 sprintf(msg, "HP-PA bootloader : %10u %10u ",
5109 sai->hppa_bootloader_adr, sai->hppa_bootloader_len);
5110 iso_impsysa_report_text(target, msg,
5111 sai->hppa_bootloader != NULL ?
5112 sai->hppa_bootloader : "(not found in ISO)", 0);
5113 } else if (sa_type == 6) {
5114 sprintf(msg, "DEC Alpha ldr size : %.f",
5115 (double) sai->alpha_boot_image_size);
5116 iso_impsysa_line(target, msg);
5117 sprintf(msg, "DEC Alpha ldr adr : %.f",
5118 (double) sai->alpha_boot_image_adr);
5119 iso_impsysa_line(target, msg);
5120 if (sai->alpha_boot_image != NULL) {
5121 sprintf(msg, "DEC Alpha ldr path : %s", sai->alpha_boot_image);
5122 iso_impsysa_line(target, msg);
5123 }
5124 }
5125 if (sai->mbr_req_count > 0) {
5126 sprintf(msg, "MBR heads per cyl : %d", sai->partition_heads_per_cyl);
5127 iso_impsysa_line(target, msg);
5128 sprintf(msg, "MBR secs per head : %d", sai->partition_secs_per_head);
5129 iso_impsysa_line(target, msg);
5130 sprintf(msg,
5131 "MBR partition table: N Status Type Start Blocks");
5132 iso_impsysa_line(target, msg);
5133 }
5134 for (i = 0; i < sai->mbr_req_count; i++) {
5135 part = sai->mbr_req[i];
5136 sprintf(msg,
5137 "MBR partition : %3d 0x%2.2x 0x%2.2x %11.f %11.f",
5138 part->desired_slot,
5139 (unsigned int) part->status_byte,
5140 (unsigned int) part->type_byte,
5141 (double) part->start_block, (double) part->block_count);
5142 iso_impsysa_line(target, msg);
5143 }
5144 for (i = 0; i < sai->mbr_req_count; i++) {
5145 part = sai->mbr_req[i];
5146 if (part->block_count == 0)
5147 continue;
5148 sprintf(msg, "MBR partition path : %3d ", part->desired_slot);
5149 iso_impsysa_report_blockpath(image, target, msg,
5150 (uint32_t) (part->start_block / 4), 0);
5151 }
5152 if (sai->prep_part_start > 0 && sai->prep_part_size > 0) {
5153 sprintf(msg, "PReP boot partition: %u %u",
5154 sai->prep_part_start, sai->prep_part_size);
5155 iso_impsysa_line(target, msg);
5156 }
5157
5158 if (sa_type == 1) {
5159 sprintf(msg,
5160 "MIPS-BE volume dir : N Name Block Bytes");
5161 iso_impsysa_line(target, msg);
5162 for (i = 0; i < sai->num_mips_boot_files; i++) {
5163 sprintf(msg,
5164 "MIPS-BE boot entry : %3d %8s %10u %10u",
5165 i + 1, sai->mips_vd_entries[i]->name,
5166 sai->mips_vd_entries[i]->boot_block,
5167 sai->mips_vd_entries[i]->boot_bytes);
5168 iso_impsysa_line(target, msg);
5169 if (sai->mips_boot_file_paths[i] != NULL) {
5170 sprintf(msg, "MIPS-BE boot path : %3d ", i + 1);
5171 iso_impsysa_report_text(target, msg,
5172 sai->mips_boot_file_paths[i], 0);
5173 }
5174 }
5175 } else if (sa_type == 2) {
5176 sprintf(msg,
5177 "MIPS-LE boot map : LoadAddr ExecAddr SegmentSize SegmentStart");
5178 iso_impsysa_line(target, msg);
5179 sprintf(msg, "MIPS-LE boot params: %10u %10u %10u %10u",
5180 sai->mipsel_p_vaddr, sai->mipsel_e_entry, sai->mipsel_p_filesz,
5181 sai->mipsel_seg_start);
5182 iso_impsysa_line(target, msg);
5183 if (sai->mipsel_boot_file_path != NULL) {
5184 sprintf(msg, "MIPS-LE boot path : ");
5185 iso_impsysa_report_text(target, msg,
5186 sai->mipsel_boot_file_path, 0);
5187 sprintf(msg, "MIPS-LE elf offset : %u", sai->mipsel_p_offset);
5188 iso_impsysa_line(target, msg);
5189 }
5190 } else if (sa_type == 3) {
5191 sprintf(msg, "SUN SPARC disklabel: %s", sai->sparc_disc_label);
5192 iso_impsysa_line(target, msg);
5193 sprintf(msg, "SUN SPARC secs/head: %d", sai->sparc_secs_per_head);
5194 iso_impsysa_line(target, msg);
5195 sprintf(msg, "SUN SPARC heads/cyl: %d", sai->sparc_heads_per_cyl);
5196 iso_impsysa_line(target, msg);
5197 sprintf(msg,
5198 "SUN SPARC partmap : N IdTag Perms StartCyl NumBlocks");
5199 iso_impsysa_line(target, msg);
5200 for (i = 0; i < sai->sparc_entry_count; i++) {
5201 sparc_entry = sai->sparc_entries + i;
5202 sprintf(msg,
5203 "SUN SPARC partition: %3d 0x%4.4x 0x%4.4x %10u %10u",
5204 sparc_entry->idx,
5205 sparc_entry->id_tag, sparc_entry->permissions,
5206 sparc_entry->start_cyl, sparc_entry->num_blocks);
5207 iso_impsysa_line(target, msg);
5208 }
5209 if (sai->sparc_grub2_core_adr > 0) {
5210 sprintf(msg, "SPARC GRUB2 core : %.f %u",
5211 (double) sai->sparc_grub2_core_adr,
5212 sai->sparc_grub2_core_size);
5213 iso_impsysa_line(target, msg);
5214 if (sai->sparc_core_node != NULL) {
5215 path = iso_tree_get_node_path((IsoNode *) sai->sparc_core_node);
5216 if (path != NULL) {
5217 sprintf(msg, "SPARC GRUB2 path : ");
5218 iso_impsysa_report_text(target, msg, path, 0);
5219 free(path);
5220 }
5221 }
5222 }
5223 }
5224
5225 if (sai->gpt_req_count > 0) {
5226 sprintf(msg, "GPT : N Info");
5227 iso_impsysa_line(target, msg);
5228 if (sai->gpt_head_crc_should != sai->gpt_head_crc_found) {
5229 sprintf(msg,
5230 "GPT CRC should be : 0x%8.8x to match first 92 GPT header block bytes",
5231 sai->gpt_head_crc_should);
5232 iso_impsysa_line(target, msg);
5233 sprintf(msg,
5234 "GPT CRC found : 0x%8.8x matches all 512 bytes of GPT header block",
5235 sai->gpt_head_crc_found);
5236 iso_impsysa_line(target, msg);
5237 }
5238 if (sai->gpt_array_crc_should != sai->gpt_array_crc_found) {
5239 sprintf(msg,
5240 "GPT array CRC wrong: should be 0x%8.8x , found 0x%8.8x",
5241 sai->gpt_array_crc_should, sai->gpt_array_crc_found);
5242 iso_impsysa_line(target, msg);
5243 }
5244 if (sai->gpt_backup_comments != NULL) {
5245 if (sai->gpt_backup_comments[0]) {
5246 sprintf(msg, "GPT backup problems: ");
5247 iso_impsysa_report_text(target, msg,
5248 sai->gpt_backup_comments, 0);
5249 }
5250 }
5251 sprintf(msg, "GPT disk GUID : ");
5252 iso_util_bin_to_hex(msg + 26, sai->gpt_disk_guid, 16, 0);
5253 iso_impsysa_line(target, msg);
5254 sprintf(msg, "GPT entry array : %u %u %s",
5255 (unsigned int) sai->gpt_part_start,
5256 (unsigned int) sai->gpt_max_entries,
5257 sai->gpt_req_flags & 1 ? "overlapping" : "separated");
5258 iso_impsysa_line(target, msg);
5259 sprintf(msg, "GPT lba range : %.f %.f %.f",
5260 (double) sai->gpt_first_lba, (double) sai->gpt_last_lba,
5261 (double) sai->gpt_backup_lba);
5262 iso_impsysa_line(target, msg);
5263 ret = iso_write_opts_new(&opts, 0);
5264 if (ret < 0)
5265 goto ex;
5266 ret = iso_write_opts_set_output_charset(opts, "UTF-16LE");
5267 if (ret < 0)
5268 goto ex;
5269 }
5270 for (i = 0; i < sai->gpt_req_count; i++) {
5271 gpt_entry = sai->gpt_req[i];
5272 idx = gpt_entry->idx;
5273
5274 sprintf(msg, "GPT partition name : %3d ", idx);
5275 for (j = 72; j >= 2; j -= 2)
5276 if (gpt_entry->name[j - 2] || gpt_entry->name[j - 1])
5277 break;
5278 iso_util_bin_to_hex(msg + 26, gpt_entry->name, j, 0);
5279 iso_impsysa_line(target, msg);
5280 if (j > 0)
5281 ret = iso_conv_name_chars(opts, (char *) gpt_entry->name, j,
5282 &local_name, &local_len, 0 | 512 | (1 << 15));
5283 else
5284 ret = 0;
5285 if (ret == 1 && local_len <= 228) {
5286 sprintf(msg, "GPT partname local : %3d ", idx);
5287 memcpy(msg + 26, local_name, local_len);
5288 LIBISO_FREE_MEM(local_name); local_name = NULL;
5289 msg[26 + local_len] = 0;
5290 iso_impsysa_line(target, msg);
5291 }
5292 sprintf(msg, "GPT partition GUID : %3d ", idx);
5293 iso_util_bin_to_hex(msg + 26, gpt_entry->partition_guid, 16, 0);
5294 iso_impsysa_line(target, msg);
5295 sprintf(msg, "GPT type GUID : %3d ", idx);
5296 iso_util_bin_to_hex(msg + 26, gpt_entry->type_guid, 16, 0);
5297 iso_impsysa_line(target, msg);
5298 sprintf(msg, "GPT partition flags: %3d 0x%8.8x%8.8x", idx,
5299 (unsigned int) ((gpt_entry->flags >> 32) & 0xffffffff),
5300 (unsigned int) (gpt_entry->flags & 0xffffffff));
5301 iso_impsysa_line(target, msg);
5302 sprintf(msg, "GPT start and size : %3d %.f %.f", idx,
5303 (double) gpt_entry->start_block,
5304 (double) gpt_entry->block_count);
5305 iso_impsysa_line(target, msg);
5306 if (gpt_entry->block_count == 0)
5307 continue;
5308 sprintf(msg, "GPT partition path : %3d ", idx);
5309 iso_impsysa_report_blockpath(image, target, msg,
5310 (uint32_t) (gpt_entry->start_block / 4), 0);
5311 }
5312
5313 if (sai->apm_req_count > 0) {
5314 sprintf(msg, "APM : N Info");
5315 iso_impsysa_line(target, msg);
5316 sprintf(msg, "APM block size : %u", sai->apm_block_size);
5317 iso_impsysa_line(target, msg);
5318 sprintf(msg, "APM gap fillers : %d", sai->apm_gap_count);
5319 iso_impsysa_line(target, msg);
5320 }
5321 for (i = 0; i < sai->apm_req_count; i++) {
5322 apm_entry = sai->apm_req[i];
5323 idx = i + 1;
5324 sprintf(msg, "APM partition name : %3d %s", idx, apm_entry->name);
5325 iso_impsysa_line(target, msg);
5326 sprintf(msg, "APM partition type : %3d %s", idx, apm_entry->type);
5327 iso_impsysa_line(target, msg);
5328 sprintf(msg, "APM start and size : %3d %.f %.f", idx,
5329 (double) apm_entry->start_block,
5330 (double) apm_entry->block_count);
5331 iso_impsysa_line(target, msg);
5332 if (apm_entry->block_count == 0)
5333 continue;
5334 sprintf(msg, "APM partition path : %3d ", idx);
5335 iso_impsysa_report_blockpath(image, target, msg,
5336 (uint32_t) (apm_entry->start_block /
5337 (2048 / sai->apm_block_size)),
5338 0);
5339 }
5340
5341 ret = 1;
5342 ex:
5343 LIBISO_FREE_MEM(local_name);
5344 if (opts != NULL)
5345 iso_write_opts_free(opts);
5346 LIBISO_FREE_MEM(msg);
5347 return ret;
5348 }
5349
5350 static
iso_report_result_destroy(char *** result,int flag)5351 int iso_report_result_destroy(char ***result, int flag)
5352 {
5353 if (*result == NULL)
5354 return ISO_SUCCESS;
5355 if ((*result)[0] != NULL) /* points to the whole multi-line buffer */
5356 free((*result)[0]);
5357 free(*result);
5358 *result = NULL;
5359 return ISO_SUCCESS;
5360 }
5361
5362 static
iso_report_help(char ** doc,char *** result,int * line_count,int flag)5363 int iso_report_help(char **doc, char ***result, int *line_count, int flag)
5364 {
5365 int i, count = 0;
5366 char *buf = NULL;
5367
5368 *line_count = 0;
5369 for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++)
5370 count += strlen(doc[i]) + 1;
5371 if (i == 0)
5372 return ISO_SUCCESS;
5373 *result = calloc(i, sizeof(char *));
5374 if (*result == NULL)
5375 return ISO_OUT_OF_MEM;
5376 buf = calloc(1, count);
5377 if (buf == NULL) {
5378 free(*result);
5379 *result = NULL;
5380 return ISO_OUT_OF_MEM;
5381 }
5382 *line_count = i;
5383 count = 0;
5384 for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++) {
5385 strcpy(buf + count, doc[i]);
5386 (*result)[i] = buf + count;
5387 count += strlen(doc[i]) + 1;
5388 }
5389 return ISO_SUCCESS;
5390 }
5391
5392 static
iso_impsysa_hdd_emul_size(IsoImage * image,IsoDataSource * src,uint32_t lba,int flag)5393 uint32_t iso_impsysa_hdd_emul_size(IsoImage *image, IsoDataSource *src,
5394 uint32_t lba, int flag)
5395 {
5396 uint32_t max_size = 0, start_lba, num_blocks;
5397 int i, ret;
5398 uint8_t *buffer = NULL;
5399
5400 /* Obtain first block of image */
5401 LIBISO_ALLOC_MEM(buffer, uint8_t, 2048);
5402 ret = src->read_block(src, lba, buffer);
5403 if (ret < 0)
5404 goto ex;
5405
5406 /* Check for magic number of MBR */
5407 if (buffer[510] != 0x55 || buffer[511] != 0xaa)
5408 goto ex;
5409
5410 for (i = 0; i < 4; i++) {
5411 start_lba = iso_read_lsb(buffer + 454 + 16 * i, 4);
5412 num_blocks = iso_read_lsb(buffer + 458 + 16 * i, 4);
5413 if (start_lba + num_blocks > max_size)
5414 max_size = start_lba + num_blocks;
5415 }
5416 ex:;
5417 LIBISO_FREE_MEM(buffer);
5418 return max_size;
5419 }
5420
5421 static
iso_eltorito_report(IsoImage * image,struct iso_impsysa_result * target,int flag)5422 int iso_eltorito_report(IsoImage *image, struct iso_impsysa_result *target,
5423 int flag)
5424 {
5425 char *msg = NULL, emul_code[6], pltf[5], *path;
5426 int i, j, ret, section_count;
5427 uint32_t lba, *lba_mem = NULL;
5428 struct el_torito_boot_catalog *bootcat;
5429 IsoBoot *bootnode;
5430 struct el_torito_boot_image *img;
5431 struct iso_file_section *sections = NULL;
5432 static char emul_names[5][6] = {"none", "fd1.2", "fd1.4", "fd2.8", "hd"};
5433 static char pltf_names[3][5] = {"BIOS", "PPC", "Mac"};
5434 static int num_emuls = 5, num_pltf = 3;
5435
5436 bootcat = image->bootcat;
5437
5438 LIBISO_ALLOC_MEM(msg, char, ISO_MAX_SYSAREA_LINE_LENGTH);
5439
5440 if (bootcat == NULL)
5441 {ret= 0; goto ex;}
5442 bootnode = image->bootcat->node;
5443 if (bootnode == NULL)
5444 {ret= 0; goto ex;}
5445
5446 sprintf(msg, "El Torito catalog : %u %u",
5447 (unsigned int) bootnode->lba,
5448 (unsigned int) (bootnode->size + 2047) / 2048);
5449 iso_impsysa_line(target, msg);
5450 path = iso_tree_get_node_path((IsoNode *) bootnode);
5451 if (path != NULL) {
5452 sprintf(msg, "El Torito cat path : ");
5453 iso_impsysa_report_text(target, msg, path, 0);
5454 free(path);
5455 }
5456 if (bootcat->num_bootimages > 0) {
5457 sprintf(msg,
5458 "El Torito images : N Pltf B Emul Ld_seg Hdpt Ldsiz LBA");
5459 iso_impsysa_line(target, msg);
5460 LIBISO_ALLOC_MEM(lba_mem, uint32_t, bootcat->num_bootimages);
5461 }
5462 for (i= 0; i < bootcat->num_bootimages; i++) {
5463 img = bootcat->bootimages[i];
5464 if (img->type < num_emuls)
5465 strcpy(emul_code, emul_names[img->type]);
5466 else
5467 sprintf(emul_code, "0x%2.2x", (unsigned int) img->type);
5468 if (img->platform_id < num_pltf)
5469 strcpy(pltf, pltf_names[img->platform_id]);
5470 else if(img->platform_id == 0xef)
5471 strcpy(pltf, "UEFI");
5472 else
5473 sprintf(pltf, "0x%2.2x", (unsigned int) img->platform_id);
5474 lba = 0xffffffff;
5475 ret = iso_file_get_old_image_sections(img->image, §ion_count,
5476 §ions, 0);
5477 if (ret > 0 && section_count > 0)
5478 lba = sections[0].block;
5479 lba_mem[i]= lba;
5480 if (sections != NULL) {
5481 free(sections);
5482 sections = NULL;
5483 }
5484 sprintf(msg,
5485 "El Torito boot img : %3d %4s %c %5s 0x%4.4x 0x%2.2x %5u %10u",
5486 i + 1, pltf, img->bootable ? 'y' : 'n', emul_code,
5487 (unsigned int) img->load_seg, (unsigned int) img->partition_type,
5488 (unsigned int) img->load_size,
5489 (unsigned int) lba);
5490 iso_impsysa_line(target, msg);
5491 }
5492 for (i= 0; i < bootcat->num_bootimages; i++) {
5493 img = bootcat->bootimages[i];
5494 if (lba_mem[i] != 0xffffffff) {
5495 sprintf(msg, "El Torito img path : %3d ", i + 1);
5496 iso_impsysa_report_blockpath(image, target, msg, lba_mem[i], 1);
5497 if (img->type == 4 && img->emul_hdd_size > 0) {
5498 sprintf(msg, "El Torito hdsiz/512: %3d %u",
5499 i + 1, (unsigned int) img->emul_hdd_size);
5500 iso_impsysa_line(target, msg);
5501 }
5502 }
5503 sprintf(msg, "El Torito img opts : %3d ", i + 1);
5504 if (img->seems_boot_info_table)
5505 strcat(msg, "boot-info-table ");
5506 if (img->seems_isohybrid_capable)
5507 strcat(msg, "isohybrid-suitable ");
5508 if (img->seems_grub2_boot_info)
5509 strcat(msg, "grub2-boot-info ");
5510 if (strlen(msg) > 27) {
5511 msg[strlen(msg) - 1] = 0;
5512 iso_impsysa_line(target, msg);
5513 }
5514 for (j = 0; j < (int) sizeof(img->id_string); j++)
5515 if (img->id_string[j])
5516 break;
5517 if (j < (int) sizeof(img->id_string)) {
5518 sprintf(msg, "El Torito id string: %3d ", i + 1);
5519 iso_util_bin_to_hex(msg + strlen(msg),
5520 img->id_string, 24 + 4 * (i > 0), 0);
5521 }
5522 for (j = 0; j < (int) sizeof(img->selection_crit); j++)
5523 if (img->selection_crit[j])
5524 break;
5525 if (j < (int) sizeof(img->selection_crit) && i > 0) {
5526 sprintf(msg, "El Torito sel crit : %3d ", i + 1);
5527 iso_util_bin_to_hex(msg + strlen(msg),
5528 img->selection_crit, 20, 0);
5529 }
5530 }
5531
5532 ret = ISO_SUCCESS;
5533 ex:;
5534 LIBISO_FREE_MEM(msg);
5535 LIBISO_FREE_MEM(lba_mem);
5536 return ret;
5537 }
5538
5539
5540 /* API */
5541 /* @param flag bit1= do not report system area but rather reply help text
5542 bit15= dispose result from previous call
5543 */
5544 static
iso_image_report_boot_eqp(IsoImage * image,int what,char *** result,int * line_count,int flag)5545 int iso_image_report_boot_eqp(IsoImage *image, int what,
5546 char ***result, int *line_count, int flag)
5547 {
5548 int ret;
5549 char **doc;
5550 struct iso_impsysa_result *target = NULL;
5551 static char *sysarea_doc[] = { ISO_SYSAREA_REPORT_DOC ,
5552 ISO_SYSAREA_REPORT_DOC_MBR ,
5553 ISO_SYSAREA_REPORT_DOC_GPT1 ,
5554 ISO_SYSAREA_REPORT_DOC_GPT2 ,
5555 ISO_SYSAREA_REPORT_DOC_APM ,
5556 ISO_SYSAREA_REPORT_DOC_MIPS ,
5557 ISO_SYSAREA_REPORT_DOC_SUN ,
5558 ISO_SYSAREA_REPORT_DOC_HPPA ,
5559 ISO_SYSAREA_REPORT_DOC_ALPHA ,
5560 "@END_OF_DOC@" };
5561 static char *eltorito_doc[] = { ISO_ELTORITO_REPORT_DOC ,
5562 "@END_OF_DOC@" };
5563
5564 if (flag & (1 << 15))
5565 return iso_report_result_destroy(result, 0);
5566 if (flag & 1) {
5567 if (what == 0)
5568 doc = sysarea_doc;
5569 else
5570 doc = eltorito_doc;
5571 return iso_report_help(doc, result, line_count, 0);
5572 }
5573
5574 *result = NULL;
5575 *line_count = 0;
5576 ret = iso_impsysa_result_new(&target, 0);
5577 if (ret < 0)
5578 goto ex;
5579 if (what == 0)
5580 ret = iso_impsysa_report(image, target, 0);
5581 else
5582 ret = iso_eltorito_report(image, target, 0);
5583 if (ret <= 0)
5584 goto ex;
5585 target->buf = calloc(1, target->byte_count + 1);
5586 target->lines = calloc(target->line_count + 1, sizeof(char *));
5587 if (target->buf == NULL || target->lines == NULL)
5588 {ret = ISO_OUT_OF_MEM; goto ex;}
5589 target->lines[0] = target->buf; /* even if no lines get reported */
5590 target->byte_count = 0;
5591 target->line_count = 0;
5592 if (what == 0)
5593 ret = iso_impsysa_report(image, target, 0);
5594 else
5595 ret = iso_eltorito_report(image, target, 0);
5596 if (ret <= 0)
5597 goto ex;
5598
5599 /* target to result */
5600 *result = target->lines;
5601 target->lines = NULL;
5602 target->buf = NULL;
5603 *line_count = target->line_count;
5604
5605 ret = ISO_SUCCESS;
5606 ex:
5607 iso_impsysa_result_destroy(&target, 0);
5608 return ret;
5609 }
5610
5611 /* API */
5612 /* @param flag bit1= do not report system area but rather reply help text
5613 bit15= dispose result from previous call
5614 */
iso_image_report_system_area(IsoImage * image,char *** result,int * line_count,int flag)5615 int iso_image_report_system_area(IsoImage *image,
5616 char ***result, int *line_count, int flag)
5617 {
5618 return iso_image_report_boot_eqp(image, 0, result, line_count, flag);
5619 }
5620
5621 static
iso_record_pvd_blocks(IsoImage * image,IsoDataSource * src,uint32_t block,int flag)5622 int iso_record_pvd_blocks(IsoImage *image, IsoDataSource *src, uint32_t block,
5623 int flag)
5624 {
5625 int ret;
5626 uint8_t *buffer = NULL;
5627 struct iso_imported_sys_area *sai;
5628
5629 LIBISO_ALLOC_MEM(buffer, uint8_t, 2048);
5630
5631 sai = image->imported_sa_info;
5632 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] = block;
5633
5634 ret = src->read_block(src, block, buffer);
5635 if (ret < 0)
5636 goto ex;
5637
5638 /* Verify that it is a PVD of a volume not larger than sai->image_size */
5639 if (buffer[0] != 1 || strncmp((char *) buffer + 1, "CD001", 5) != 0)
5640 {ret = 0; goto ex;}
5641 if (iso_read_lsb(buffer + 80, 4) > sai->image_size)
5642 {ret = 0; goto ex;}
5643
5644 /* L pathtable, Opt L, M pathtable , Opt M, Root directory extent*/
5645 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5646 iso_read_lsb(buffer + 140, 4);
5647 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5648 iso_read_lsb(buffer + 144, 4);
5649 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5650 iso_read_lsb(buffer + 148, 4);
5651 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5652 iso_read_lsb(buffer + 152, 4);
5653 sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5654 iso_read_lsb(buffer + 158, 4);
5655
5656 ret = ISO_SUCCESS;
5657 ex:;
5658 LIBISO_FREE_MEM(buffer);
5659 return ret;
5660 }
5661
5662 static
iso_record_meta_struct_blocks(IsoImage * image,IsoDataSource * src,int flag)5663 int iso_record_meta_struct_blocks(IsoImage *image, IsoDataSource *src,
5664 int flag)
5665 {
5666 int ret;
5667 struct iso_imported_sys_area *sai;
5668
5669 sai = image->imported_sa_info;
5670 ret = iso_record_pvd_blocks(image, src, sai->pvd_block, 0);
5671 if (ret < 0)
5672 goto ex;
5673 /* Try block 32 as first session PVD */
5674 ret = iso_record_pvd_blocks(image, src, 16, 0);
5675 if (ret < 0)
5676 goto ex;
5677 if (ret == 0 && sai->pvd_block > 16) {
5678 /* No emulated multi-session: Try block 16 as first session PVD */
5679 ret = iso_record_pvd_blocks(image, src, 16, 0);
5680 if (ret < 0)
5681 goto ex;
5682 }
5683 ret = ISO_SUCCESS;
5684 ex:
5685 return ret;
5686 }
5687
5688 static
iso_analyze_system_area(IsoImage * image,IsoDataSource * src,struct iso_read_opts * opts,uint32_t image_size,int flag)5689 int iso_analyze_system_area(IsoImage *image, IsoDataSource *src,
5690 struct iso_read_opts *opts, uint32_t image_size,
5691 int flag)
5692 {
5693 int ret, i, sao, sa_type, sa_sub;
5694
5695 iso_imported_sa_unref(&(image->imported_sa_info), 0);
5696 ret = iso_imported_sa_new(&(image->imported_sa_info), 0);
5697 if (ret < 0)
5698 goto ex;
5699
5700 for (i = 0; i < 32768; i++)
5701 if (image->system_area_data[i] != 0)
5702 break;
5703 if (i < 32768)
5704 image->imported_sa_info->is_not_zero = 1;
5705
5706 image->imported_sa_info->image_size = image_size;
5707 image->imported_sa_info->pvd_block = opts->block + 16;
5708
5709 ret = iso_analyze_mbr(image, src, 0);
5710 if (ret < 0)
5711 goto ex;
5712 ret = iso_analyze_gpt(image, src, 0);
5713 if (ret < 0)
5714 goto ex;
5715 ret = iso_analyze_apm(image, src, 0);
5716 if (ret < 0)
5717 goto ex;
5718 sao = image->imported_sa_info->system_area_options;
5719 sa_type = (sao >> 2) & 0x3f;
5720 sa_sub = (sao >> 10) & 0xf;
5721 if (sa_type == 0 && !((sao & 3) || sa_sub == 1 || sa_sub == 2)) {
5722 ret = iso_analyze_mips(image, src, 0);
5723 if (ret < 0)
5724 goto ex;
5725 if (ret == 0) {
5726 ret = iso_analyze_mipsel(image, src, 0);
5727 if (ret < 0)
5728 goto ex;
5729 }
5730 if (ret == 0) {
5731 ret = iso_analyze_sun(image, src, 0);
5732 if (ret < 0)
5733 goto ex;
5734 }
5735 }
5736 if (sa_type == 0 && !((sao & 3) || sa_sub == 1)) {
5737 /* HP-PA PALO v5 can look like generic MBR */
5738 ret = iso_analyze_hppa(image, src, 0);
5739 if (ret < 0)
5740 goto ex;
5741 /* DEC Alpha has checksum bytes where MBR has its magic number */
5742 if (ret == 0) {
5743 ret = iso_analyze_alpha_boot(image, src, 0);
5744 if (ret < 0)
5745 goto ex;
5746 }
5747 }
5748 ret = iso_record_meta_struct_blocks(image, src, 0);
5749 if (ret < 0)
5750 goto ex;
5751
5752 ret = ISO_SUCCESS;
5753 ex:;
5754 image->imported_sa_info->overall_return = ret;
5755 return ret;
5756 }
5757
5758
5759 /* API */
5760 /* @param flag bit1= do not report system area but rather reply help text
5761 bit15= dispose result from previous call
5762 */
iso_image_report_el_torito(IsoImage * image,char *** reply,int * line_count,int flag)5763 int iso_image_report_el_torito(IsoImage *image,
5764 char ***reply, int *line_count, int flag)
5765 {
5766 return iso_image_report_boot_eqp(image, 1, reply, line_count, flag);
5767 }
5768
5769
iso_image_import(IsoImage * image,IsoDataSource * src,struct iso_read_opts * opts,IsoReadImageFeatures ** features)5770 int iso_image_import(IsoImage *image, IsoDataSource *src,
5771 struct iso_read_opts *opts,
5772 IsoReadImageFeatures **features)
5773 {
5774 int ret, hflag, i, idx;
5775 IsoImageFilesystem *fs;
5776 IsoFilesystem *fsback;
5777 IsoNodeBuilder *blback;
5778 IsoDir *oldroot;
5779 IsoFileSource *newroot;
5780 _ImageFsData *data;
5781 struct el_torito_boot_catalog *oldbootcat;
5782 uint8_t *rpt;
5783 IsoFileSource *boot_src;
5784 IsoNode *node;
5785 char *old_checksum_array = NULL;
5786 char checksum_type[81];
5787 uint32_t checksum_size, truncate_mode, truncate_length;
5788 size_t size, attr_value_length;
5789 char *attr_value;
5790 unsigned char *aa_string = NULL;
5791 void *ctx = NULL;
5792 char md5[16];
5793 struct el_torito_boot_catalog *catalog = NULL;
5794 ElToritoBootImage *boot_image = NULL;
5795
5796 if (image == NULL || src == NULL || opts == NULL) {
5797 return ISO_NULL_POINTER;
5798 }
5799
5800 opts->truncate_mode = image->truncate_mode;
5801 opts->truncate_length = image->truncate_length;
5802 ret = iso_image_filesystem_new(src, opts, image->id, &fs);
5803 if (ret < 0) {
5804 return ret;
5805 }
5806 data = fs->data;
5807
5808
5809 if (opts->keep_import_src) {
5810 iso_data_source_ref(src);
5811 image->import_src = src;
5812 }
5813 if (opts->load_system_area) {
5814 if (image->system_area_data != NULL)
5815 free(image->system_area_data);
5816 image->system_area_data = calloc(32768, 1);
5817 if (image->system_area_data == NULL) {
5818 iso_filesystem_unref(fs);
5819 return ISO_OUT_OF_MEM;
5820 }
5821 image->system_area_options = 0;
5822 /* Read 32768 bytes */
5823 for (i = 0; i < 16; i++) {
5824 rpt = (uint8_t *) (image->system_area_data + i * 2048);
5825 ret = src->read_block(src, opts->block + i, rpt);
5826 if (ret < 0) {
5827 iso_filesystem_unref(fs);
5828 return ret;
5829 }
5830 }
5831 }
5832
5833 /* get root from filesystem */
5834 ret = fs->get_root(fs, &newroot);
5835 if (ret < 0) {
5836 iso_filesystem_unref(fs);
5837 return ret;
5838 }
5839 if (newroot == NULL) {
5840 iso_filesystem_unref(fs);
5841 return ISO_NO_ROOT_DIR;
5842 }
5843
5844 /* Lookup character set even if no AAIP loading is enabled */
5845 ret = iso_file_source_get_aa_string(newroot, &aa_string, 2);
5846 if (ret == 1 && aa_string != NULL) {
5847 ret = iso_aa_lookup_attr(aa_string, "isofs.cs",
5848 &attr_value_length, &attr_value, 0);
5849 free(aa_string);
5850 } else {
5851 ret = 0;
5852 }
5853 if (ret == 1) {
5854 if (data->auto_input_charset & 1) {
5855 if (data->input_charset != NULL)
5856 free(data->input_charset);
5857 data->input_charset = attr_value;
5858 iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
5859 "Learned from ISO image: input character set '%.80s'",
5860 attr_value);
5861 } else {
5862 iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
5863 "Ignored character set name recorded in ISO image: '%.80s'",
5864 attr_value);
5865 free(attr_value);
5866 }
5867 attr_value = NULL;
5868 }
5869
5870 /* backup image filesystem, builder and root */
5871 fsback = image->fs;
5872 blback = image->builder;
5873 oldroot = image->root;
5874 oldbootcat = image->bootcat; /* could be NULL */
5875 image->bootcat = NULL;
5876 old_checksum_array = image->checksum_array;
5877 image->checksum_array = NULL;
5878
5879 /* create new builder */
5880 ret = iso_image_builder_new(blback, &image->builder);
5881 if (ret < 0) {
5882 goto import_revert;
5883 }
5884
5885 image->fs = fs;
5886
5887 /* create new root, and set root attributes from source */
5888 ret = iso_node_new_root(&image->root);
5889 if (ret < 0) {
5890 goto import_revert;
5891 }
5892 {
5893 struct stat info;
5894
5895 /* I know this will not fail */
5896 iso_file_source_lstat(newroot, &info);
5897 image->root->node.mode = info.st_mode;
5898 image->root->node.uid = info.st_uid;
5899 image->root->node.gid = info.st_gid;
5900 image->root->node.atime = info.st_atime;
5901 image->root->node.mtime = info.st_mtime;
5902 image->root->node.ctime = info.st_ctime;
5903
5904 /* This might fail in iso_node_add_xinfo() */
5905 ret = src_aa_to_node(newroot, &(image->root->node), 0);
5906 if (ret < 0)
5907 goto import_revert;
5908
5909 /* Attach ino as xinfo if valid */
5910 if (info.st_ino != 0 && !data->make_new_ino) {
5911 ret = iso_node_set_ino(&(image->root->node), info.st_ino, 0);
5912 if (ret < 0)
5913 goto import_revert;
5914 }
5915 }
5916
5917 ret = iso_root_get_isofsnt(&(image->root->node), &truncate_mode,
5918 &truncate_length, 0);
5919 if (ret == 1 && (int) truncate_mode == image->truncate_mode &&
5920 image->truncate_mode == 1 &&
5921 truncate_length >= 64 && truncate_length <= 255 &&
5922 (int) truncate_length != image->truncate_length) {
5923
5924 data->truncate_mode = opts->truncate_mode = image->truncate_mode =
5925 truncate_mode;
5926 data->truncate_length = opts->truncate_length =
5927 image->truncate_length = truncate_length;
5928 iso_msg_submit(image->id, ISO_TRUNCATE_ISOFSNT, 0,
5929 "File name truncation length changed by loaded image info: %d",
5930 (int) truncate_length);
5931 }
5932
5933 /* if old image has el-torito, add a new catalog */
5934 if (data->eltorito) {
5935
5936 catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
5937 if (catalog == NULL) {
5938 ret = ISO_OUT_OF_MEM;
5939 goto import_revert;
5940 }
5941
5942 catalog->num_bootimages = 0;
5943 for (idx = 0; idx < data->num_bootimgs; idx++) {
5944 boot_image = calloc(1, sizeof(ElToritoBootImage));
5945 if (boot_image == NULL) {
5946 ret = ISO_OUT_OF_MEM;
5947 goto import_revert;
5948 }
5949 boot_image->image = NULL;
5950 boot_image->bootable = data->boot_flags[idx] & 1;
5951 boot_image->type = data->media_types[idx];
5952 boot_image->partition_type = data->partition_types[idx];
5953 boot_image->load_seg = data->load_segs[idx];
5954 boot_image->load_size = data->load_sizes[idx];
5955 boot_image->platform_id = data->platform_ids[idx];
5956 memcpy(boot_image->id_string, data->id_strings[idx], 28);
5957 memcpy(boot_image->selection_crit, data->selection_crits, 20);
5958 boot_image->appended_idx = -1;
5959 boot_image->appended_start = data->bootblocks[idx];
5960 if (boot_image->type == 4) {
5961 boot_image->emul_hdd_size = iso_impsysa_hdd_emul_size(
5962 image, src,
5963 data->bootblocks[idx], 0);
5964 } else {
5965 boot_image->emul_hdd_size = 0;
5966 }
5967
5968 catalog->bootimages[catalog->num_bootimages] = boot_image;
5969 boot_image = NULL;
5970 catalog->num_bootimages++;
5971 }
5972 for ( ; idx < Libisofs_max_boot_imageS; idx++)
5973 catalog->bootimages[idx] = NULL;
5974 image->bootcat = catalog;
5975 catalog = NULL; /* So it does not get freed */
5976 }
5977
5978 /* recursively add image */
5979 ret = iso_add_dir_src_rec(image, image->root, newroot);
5980 if (ret < 0) {
5981 /* error during recursive image addition */
5982 iso_node_builder_unref(image->builder);
5983 goto import_revert;
5984 }
5985 issue_ucs2_warning_summary(data->joliet_ucs2_failures);
5986 issue_collision_warning_summary(image->collision_warnings);
5987
5988 /* Take over inode management from IsoImageFilesystem.
5989 data->inode_counter is supposed to hold the maximum PX inode number.
5990 */
5991 image->inode_counter = data->inode_counter;
5992
5993 if ((data->px_ino_status & (2 | 4 | 8)) || opts->make_new_ino) {
5994 /* Attach new inode numbers to any node which does not have one,
5995 resp. to all nodes in case of opts->make_new_ino
5996 */
5997 if (opts->make_new_ino)
5998 hflag = 1; /* Equip all data files with new unique inos */
5999 else
6000 hflag = 2 | 4 | 8; /* Equip any file type if it has ino == 0 */
6001 ret = img_make_inos(image, image->root, hflag);
6002 if (ret < 0) {
6003 iso_node_builder_unref(image->builder);
6004 goto import_revert;
6005 }
6006 }
6007
6008 if (data->eltorito) {
6009 /* if catalog and boot image nodes were not filled,
6010 we create them here */
6011 for (idx = 0; idx < image->bootcat->num_bootimages; idx++) {
6012 if (image->bootcat->bootimages[idx]->image != NULL)
6013 continue;
6014 ret = create_boot_img_filesrc(fs, image, idx, &boot_src);
6015 if (ret < 0) {
6016 iso_node_builder_unref(image->builder);
6017 goto import_revert;
6018 }
6019 ret = image_builder_create_node(image->builder, image, boot_src,
6020 NULL, &node);
6021 iso_file_source_unref(boot_src); /* Now owned by node */
6022 if (ret < 0) {
6023 iso_node_builder_unref(image->builder);
6024 goto import_revert;
6025 }
6026 if (image->bootcat->bootimages[idx]->image != NULL) {
6027 /* Already added to bootimages in image_builder_create_node().
6028 * Now it has one refcount for tree and one for bootimages.
6029 * But it will not go to tree. So unref.
6030 */
6031 iso_node_unref(node);
6032 } else {
6033 image->bootcat->bootimages[idx]->image = (IsoFile*)node;
6034 }
6035
6036
6037 /* warn about hidden images */
6038 if (image->bootcat->bootimages[idx]->platform_id == 0xef) {
6039 iso_msg_submit(image->id, ISO_ELTO_EFI_HIDDEN, 0,
6040 "Found hidden El-Torito image for EFI.");
6041 iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
6042 "EFI image start and size: %lu * 2048 , %lu * 512",
6043 (unsigned long int)
6044 image->bootcat->bootimages[idx]->appended_start,
6045 (unsigned long int)
6046 image->bootcat->bootimages[idx]->load_size);
6047 } else {
6048 iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0,
6049 "Found hidden El-Torito image. Its size could not "
6050 "be figured out, so image modify or boot image "
6051 "patching may lead to bad results.");
6052 }
6053 }
6054 if (image->bootcat->node == NULL) {
6055 IsoNode *node;
6056 IsoBoot *bootcat;
6057 node = calloc(1, sizeof(IsoBoot));
6058 if (node == NULL) {
6059 ret = ISO_OUT_OF_MEM;
6060 goto import_revert;
6061 }
6062 bootcat = (IsoBoot *) node;
6063 bootcat->lba = data->catblock;
6064 bootcat->size = data->catsize;
6065 bootcat->content = NULL;
6066 if (bootcat->size > 0) {
6067 bootcat->content = calloc(1, bootcat->size);
6068 if (bootcat->content == NULL) {
6069 free(node);
6070 ret = ISO_OUT_OF_MEM;
6071 goto import_revert;
6072 }
6073 memcpy(bootcat->content, data->catcontent, bootcat->size);
6074 }
6075 node->type = LIBISO_BOOT;
6076 node->mode = S_IFREG;
6077 node->refcount = 1;
6078 image->bootcat->node = (IsoBoot*)node;
6079 }
6080 }
6081
6082 iso_node_builder_unref(image->builder);
6083
6084 /* set volume attributes */
6085 iso_image_set_volset_id(image, data->volset_id);
6086 iso_image_set_volume_id(image, data->volume_id);
6087 iso_image_set_publisher_id(image, data->publisher_id);
6088 iso_image_set_data_preparer_id(image, data->data_preparer_id);
6089 iso_image_set_system_id(image, data->system_id);
6090 iso_image_set_application_id(image, data->application_id);
6091 iso_image_set_copyright_file_id(image, data->copyright_file_id);
6092 iso_image_set_abstract_file_id(image, data->abstract_file_id);
6093 iso_image_set_biblio_file_id(image, data->biblio_file_id);
6094 iso_image_set_pvd_times(image, data->creation_time,
6095 data->modification_time, data->expiration_time, data->effective_time);
6096
6097 if (features != NULL) {
6098 *features = malloc(sizeof(IsoReadImageFeatures));
6099 if (*features == NULL) {
6100 ret = ISO_OUT_OF_MEM;
6101 goto import_revert;
6102 }
6103 (*features)->hasJoliet = data->joliet;
6104 (*features)->hasRR = data->rr_version != 0;
6105 (*features)->hasIso1999 = data->iso1999;
6106 (*features)->hasElTorito = data->eltorito;
6107 (*features)->size = data->nblocks;
6108 (*features)->tree_loaded = 0;
6109 if (data->iso_root_block == data->svd_root_block)
6110 (*features)->tree_loaded = 1;
6111 else if (data->iso_root_block == data->evd_root_block &&
6112 data->iso_root_block != data->pvd_root_block)
6113 (*features)->tree_loaded = 2;
6114 (*features)->rr_loaded = (data->rr != RR_EXT_NO);
6115 }
6116
6117 if (data->md5_load) {
6118 /* Read checksum array */
6119 ret = iso_root_get_isofsca((IsoNode *) image->root,
6120 &(image->checksum_start_lba),
6121 &(image->checksum_end_lba),
6122 &(image->checksum_idx_count),
6123 &checksum_size, checksum_type, 0);
6124 if (ret > 0)
6125 if (checksum_size != 16 || strcmp(checksum_type, "MD5") != 0)
6126 ret = 0;
6127 if (ret > 0 && image->checksum_idx_count > 1) {
6128 size = image->checksum_idx_count / 128;
6129 if (size * 128 < image->checksum_idx_count)
6130 size++;
6131 image->checksum_array = calloc(size, 2048);
6132 if (image->checksum_array == NULL) {
6133 ret = ISO_OUT_OF_MEM;
6134 goto import_revert;
6135 }
6136
6137 /* Load from image->checksum_end_lba */;
6138 for (i = 0; i < (int) size; i++) {
6139 rpt = (uint8_t *) (image->checksum_array + i * 2048);
6140 ret = src->read_block(src, image->checksum_end_lba + i, rpt);
6141 if (ret <= 0)
6142 goto import_cleanup;
6143 }
6144
6145 /* Compute MD5 and compare with recorded MD5 */
6146 ret = iso_md5_start(&ctx);
6147 if (ret < 0) {
6148 ret = ISO_OUT_OF_MEM;
6149 goto import_revert;
6150 }
6151 for (i = 0; i < (int) image->checksum_idx_count - 1; i++)
6152 iso_md5_compute(ctx, image->checksum_array + i * 16, 16);
6153 iso_md5_end(&ctx, md5);
6154 for (i = 0; i < 16; i++)
6155 if (md5[i] != image->checksum_array[
6156 (image->checksum_idx_count - 1) * 16 + i]
6157 )
6158 break;
6159 if (i < 16) {
6160 iso_msg_submit(image->id, ISO_MD5_AREA_CORRUPTED, 0,
6161 "MD5 checksum array appears damaged and not trustworthy for verifications.");
6162 free(image->checksum_array);
6163 image->checksum_array = NULL;
6164 image->checksum_idx_count = 0;
6165 }
6166 }
6167 }
6168
6169 ret = iso_image_eval_boot_info_table(image, opts, src, data->nblocks, 0);
6170 if (ret < 0)
6171 goto import_revert;
6172
6173 if (opts->load_system_area && image->system_area_data != NULL) {
6174 ret = iso_analyze_system_area(image, src, opts, data->nblocks, 0);
6175 if (ret < 0) {
6176 iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0,
6177 "Problem encountered during inspection of System Area:");
6178 iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0,
6179 iso_error_to_msg(ret));
6180 }
6181 }
6182
6183 ret = ISO_SUCCESS;
6184 goto import_cleanup;
6185
6186 import_revert:;
6187
6188 iso_node_unref((IsoNode*)image->root);
6189 el_torito_boot_catalog_free(image->bootcat);
6190 image->root = oldroot;
6191 oldroot = NULL;
6192 image->bootcat = oldbootcat;
6193 oldbootcat = NULL;
6194 image->checksum_array = old_checksum_array;
6195 old_checksum_array = NULL;
6196
6197 import_cleanup:;
6198
6199 /* recover backed fs and builder */
6200 image->fs = fsback;
6201 image->builder = blback;
6202
6203 /* free old root */
6204 if (oldroot != NULL)
6205 iso_node_unref((IsoNode*)oldroot);
6206
6207 /* free old boot catalog */
6208 if (oldbootcat != NULL)
6209 el_torito_boot_catalog_free(oldbootcat);
6210
6211 if (catalog != NULL)
6212 el_torito_boot_catalog_free(catalog);
6213 if (boot_image != NULL)
6214 free((char *) boot_image);
6215 iso_file_source_unref(newroot);
6216 fs->close(fs);
6217 iso_filesystem_unref(fs);
6218 if (old_checksum_array != NULL)
6219 free(old_checksum_array);
6220 if (ctx != NULL)
6221 iso_md5_end(&ctx, md5);
6222 return ret;
6223 }
6224
iso_image_fs_get_volset_id(IsoImageFilesystem * fs)6225 const char *iso_image_fs_get_volset_id(IsoImageFilesystem *fs)
6226 {
6227 _ImageFsData *data = (_ImageFsData*) fs->data;
6228 return data->volset_id;
6229 }
6230
iso_image_fs_get_volume_id(IsoImageFilesystem * fs)6231 const char *iso_image_fs_get_volume_id(IsoImageFilesystem *fs)
6232 {
6233 _ImageFsData *data = (_ImageFsData*) fs->data;
6234 return data->volume_id;
6235 }
6236
iso_image_fs_get_publisher_id(IsoImageFilesystem * fs)6237 const char *iso_image_fs_get_publisher_id(IsoImageFilesystem *fs)
6238 {
6239 _ImageFsData *data = (_ImageFsData*) fs->data;
6240 return data->publisher_id;
6241 }
6242
iso_image_fs_get_data_preparer_id(IsoImageFilesystem * fs)6243 const char *iso_image_fs_get_data_preparer_id(IsoImageFilesystem *fs)
6244 {
6245 _ImageFsData *data = (_ImageFsData*) fs->data;
6246 return data->data_preparer_id;
6247 }
6248
iso_image_fs_get_system_id(IsoImageFilesystem * fs)6249 const char *iso_image_fs_get_system_id(IsoImageFilesystem *fs)
6250 {
6251 _ImageFsData *data = (_ImageFsData*) fs->data;
6252 return data->system_id;
6253 }
6254
iso_image_fs_get_application_id(IsoImageFilesystem * fs)6255 const char *iso_image_fs_get_application_id(IsoImageFilesystem *fs)
6256 {
6257 _ImageFsData *data = (_ImageFsData*) fs->data;
6258 return data->application_id;
6259 }
6260
iso_image_fs_get_copyright_file_id(IsoImageFilesystem * fs)6261 const char *iso_image_fs_get_copyright_file_id(IsoImageFilesystem *fs)
6262 {
6263 _ImageFsData *data = (_ImageFsData*) fs->data;
6264 return data->copyright_file_id;
6265 }
6266
iso_image_fs_get_abstract_file_id(IsoImageFilesystem * fs)6267 const char *iso_image_fs_get_abstract_file_id(IsoImageFilesystem *fs)
6268 {
6269 _ImageFsData *data;
6270 data = (_ImageFsData*) fs->data;
6271 return data->abstract_file_id;
6272 }
6273
iso_image_fs_get_biblio_file_id(IsoImageFilesystem * fs)6274 const char *iso_image_fs_get_biblio_file_id(IsoImageFilesystem *fs)
6275 {
6276 _ImageFsData *data = (_ImageFsData*) fs->data;
6277 return data->biblio_file_id;
6278 }
6279
iso_read_opts_new(IsoReadOpts ** opts,int profile)6280 int iso_read_opts_new(IsoReadOpts **opts, int profile)
6281 {
6282 IsoReadOpts *ropts;
6283
6284 if (opts == NULL) {
6285 return ISO_NULL_POINTER;
6286 }
6287 if (profile != 0) {
6288 return ISO_WRONG_ARG_VALUE;
6289 }
6290
6291 ropts = calloc(1, sizeof(IsoReadOpts));
6292 if (ropts == NULL) {
6293 return ISO_OUT_OF_MEM;
6294 }
6295
6296 ropts->file_mode = 0444;
6297 ropts->dir_mode = 0555;
6298 ropts->noaaip = 1;
6299 ropts->ecma119_map = 1;
6300 ropts->joliet_map = 1;
6301 ropts->nomd5 = 1;
6302 ropts->load_system_area = 0;
6303 ropts->keep_import_src = 0;
6304 ropts->truncate_mode = 1;
6305 ropts->truncate_length = LIBISOFS_NODE_NAME_MAX;
6306
6307 *opts = ropts;
6308 return ISO_SUCCESS;
6309 }
6310
iso_read_opts_free(IsoReadOpts * opts)6311 void iso_read_opts_free(IsoReadOpts *opts)
6312 {
6313 if (opts == NULL) {
6314 return;
6315 }
6316
6317 free(opts->input_charset);
6318 free(opts);
6319 }
6320
iso_read_opts_set_start_block(IsoReadOpts * opts,uint32_t block)6321 int iso_read_opts_set_start_block(IsoReadOpts *opts, uint32_t block)
6322 {
6323 if (opts == NULL) {
6324 return ISO_NULL_POINTER;
6325 }
6326 opts->block = block;
6327 return ISO_SUCCESS;
6328 }
6329
iso_read_opts_set_no_rockridge(IsoReadOpts * opts,int norr)6330 int iso_read_opts_set_no_rockridge(IsoReadOpts *opts, int norr)
6331 {
6332 if (opts == NULL) {
6333 return ISO_NULL_POINTER;
6334 }
6335 opts->norock = norr ? 1 :0;
6336 return ISO_SUCCESS;
6337 }
6338
iso_read_opts_set_no_joliet(IsoReadOpts * opts,int nojoliet)6339 int iso_read_opts_set_no_joliet(IsoReadOpts *opts, int nojoliet)
6340 {
6341 if (opts == NULL) {
6342 return ISO_NULL_POINTER;
6343 }
6344 opts->nojoliet = nojoliet ? 1 :0;
6345 return ISO_SUCCESS;
6346 }
6347
iso_read_opts_set_no_iso1999(IsoReadOpts * opts,int noiso1999)6348 int iso_read_opts_set_no_iso1999(IsoReadOpts *opts, int noiso1999)
6349 {
6350 if (opts == NULL) {
6351 return ISO_NULL_POINTER;
6352 }
6353 opts->noiso1999 = noiso1999 ? 1 :0;
6354 return ISO_SUCCESS;
6355 }
6356
iso_read_opts_set_no_aaip(IsoReadOpts * opts,int noaaip)6357 int iso_read_opts_set_no_aaip(IsoReadOpts *opts, int noaaip)
6358 {
6359 if (opts == NULL) {
6360 return ISO_NULL_POINTER;
6361 }
6362 opts->noaaip = noaaip ? 1 : 0;
6363 return ISO_SUCCESS;
6364 }
6365
iso_read_opts_set_no_md5(IsoReadOpts * opts,int no_md5)6366 int iso_read_opts_set_no_md5(IsoReadOpts *opts, int no_md5)
6367 {
6368 if (opts == NULL) {
6369 return ISO_NULL_POINTER;
6370 }
6371 opts->nomd5 = no_md5 == 2 ? 2 : no_md5 == 1 ? 1 : 0;
6372 return ISO_SUCCESS;
6373 }
6374
6375
iso_read_opts_set_new_inos(IsoReadOpts * opts,int new_inos)6376 int iso_read_opts_set_new_inos(IsoReadOpts *opts, int new_inos)
6377 {
6378 if (opts == NULL) {
6379 return ISO_NULL_POINTER;
6380 }
6381 opts->make_new_ino = new_inos ? 1 : 0;
6382 return ISO_SUCCESS;
6383 }
6384
iso_read_opts_set_preferjoliet(IsoReadOpts * opts,int preferjoliet)6385 int iso_read_opts_set_preferjoliet(IsoReadOpts *opts, int preferjoliet)
6386 {
6387 if (opts == NULL) {
6388 return ISO_NULL_POINTER;
6389 }
6390 opts->preferjoliet = preferjoliet ? 1 :0;
6391 return ISO_SUCCESS;
6392 }
6393
iso_read_opts_set_ecma119_map(IsoReadOpts * opts,int ecma119_map)6394 int iso_read_opts_set_ecma119_map(IsoReadOpts *opts, int ecma119_map)
6395 {
6396 if (opts == NULL) {
6397 return ISO_NULL_POINTER;
6398 }
6399 if (ecma119_map < 0 || ecma119_map > 3)
6400 return 0;
6401 opts->ecma119_map = ecma119_map;
6402 return ISO_SUCCESS;
6403 }
6404
iso_read_opts_set_joliet_map(IsoReadOpts * opts,int joliet_map)6405 int iso_read_opts_set_joliet_map(IsoReadOpts *opts, int joliet_map)
6406 {
6407 if (opts == NULL)
6408 return ISO_NULL_POINTER;
6409 if (joliet_map < 0 || joliet_map > 1)
6410 return 0;
6411 opts->joliet_map = joliet_map;
6412 return ISO_SUCCESS;
6413 }
6414
iso_read_opts_set_default_uid(IsoReadOpts * opts,uid_t uid)6415 int iso_read_opts_set_default_uid(IsoReadOpts *opts, uid_t uid)
6416 {
6417 if (opts == NULL) {
6418 return ISO_NULL_POINTER;
6419 }
6420 opts->uid = uid;
6421 return ISO_SUCCESS;
6422 }
6423
iso_read_opts_set_default_gid(IsoReadOpts * opts,gid_t gid)6424 int iso_read_opts_set_default_gid(IsoReadOpts *opts, gid_t gid)
6425 {
6426 if (opts == NULL) {
6427 return ISO_NULL_POINTER;
6428 }
6429 opts->gid = gid;
6430 return ISO_SUCCESS;
6431 }
6432
iso_read_opts_set_default_permissions(IsoReadOpts * opts,mode_t file_perm,mode_t dir_perm)6433 int iso_read_opts_set_default_permissions(IsoReadOpts *opts, mode_t file_perm,
6434 mode_t dir_perm)
6435 {
6436 if (opts == NULL) {
6437 return ISO_NULL_POINTER;
6438 }
6439 opts->file_mode = file_perm;
6440 opts->dir_mode = dir_perm;
6441 return ISO_SUCCESS;
6442 }
6443
iso_read_opts_set_input_charset(IsoReadOpts * opts,const char * charset)6444 int iso_read_opts_set_input_charset(IsoReadOpts *opts, const char *charset)
6445 {
6446 if (opts == NULL) {
6447 return ISO_NULL_POINTER;
6448 }
6449 opts->input_charset = charset ? strdup(charset) : NULL;
6450 return ISO_SUCCESS;
6451 }
6452
iso_read_opts_auto_input_charset(IsoReadOpts * opts,int mode)6453 int iso_read_opts_auto_input_charset(IsoReadOpts *opts, int mode)
6454 {
6455 if (opts == NULL) {
6456 return ISO_NULL_POINTER;
6457 }
6458 opts->auto_input_charset = mode;
6459 return ISO_SUCCESS;
6460 }
6461
iso_read_opts_load_system_area(IsoReadOpts * opts,int mode)6462 int iso_read_opts_load_system_area(IsoReadOpts *opts, int mode)
6463 {
6464 if (opts == NULL) {
6465 return ISO_NULL_POINTER;
6466 }
6467 opts->load_system_area = mode & 1;
6468 return ISO_SUCCESS;
6469 }
6470
iso_read_opts_keep_import_src(IsoReadOpts * opts,int mode)6471 int iso_read_opts_keep_import_src(IsoReadOpts *opts, int mode)
6472 {
6473 if (opts == NULL) {
6474 return ISO_NULL_POINTER;
6475 }
6476 opts->keep_import_src = mode & 1;
6477 return ISO_SUCCESS;
6478 }
6479
6480 /**
6481 * Destroy an IsoReadImageFeatures object obtained with iso_image_import.
6482 */
iso_read_image_features_destroy(IsoReadImageFeatures * f)6483 void iso_read_image_features_destroy(IsoReadImageFeatures *f)
6484 {
6485 if (f) {
6486 free(f);
6487 }
6488 }
6489
6490 /**
6491 * Get the size (in 2048 byte block) of the image, as reported in the PVM.
6492 */
iso_read_image_features_get_size(IsoReadImageFeatures * f)6493 uint32_t iso_read_image_features_get_size(IsoReadImageFeatures *f)
6494 {
6495 return f->size;
6496 }
6497
6498 /**
6499 * Whether RockRidge extensions are present in the image imported.
6500 */
iso_read_image_features_has_rockridge(IsoReadImageFeatures * f)6501 int iso_read_image_features_has_rockridge(IsoReadImageFeatures *f)
6502 {
6503 return f->hasRR;
6504 }
6505
6506 /**
6507 * Whether Joliet extensions are present in the image imported.
6508 */
iso_read_image_features_has_joliet(IsoReadImageFeatures * f)6509 int iso_read_image_features_has_joliet(IsoReadImageFeatures *f)
6510 {
6511 return f->hasJoliet;
6512 }
6513
6514 /**
6515 * Whether the image is recorded according to ISO 9660:1999, i.e. it has
6516 * a version 2 Enhanced Volume Descriptor.
6517 */
iso_read_image_features_has_iso1999(IsoReadImageFeatures * f)6518 int iso_read_image_features_has_iso1999(IsoReadImageFeatures *f)
6519 {
6520 return f->hasIso1999;
6521 }
6522
6523 /**
6524 * Whether El-Torito boot record is present present in the image imported.
6525 */
iso_read_image_features_has_eltorito(IsoReadImageFeatures * f)6526 int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f)
6527 {
6528 return f->hasElTorito;
6529 }
6530
6531 /**
6532 * Tells what directory tree was loaded:
6533 * 0= ISO 9660 , 1 = Joliet , 2 = ISO 9660:1999
6534 */
iso_read_image_features_tree_loaded(IsoReadImageFeatures * f)6535 int iso_read_image_features_tree_loaded(IsoReadImageFeatures *f)
6536 {
6537 return f->tree_loaded;
6538 }
6539
6540 /**
6541 * Tells whether Rock Ridge information was used while loading the tree.
6542 */
iso_read_image_features_rr_loaded(IsoReadImageFeatures * f)6543 int iso_read_image_features_rr_loaded(IsoReadImageFeatures *f)
6544 {
6545 return f->rr_loaded;
6546 }
6547
6548 /**
6549 * Get the start addresses and the sizes of the data extents of a file node
6550 * if it was imported from an old image.
6551 *
6552 * @param file
6553 * The file
6554 * @param section_count
6555 * Returns the number of extent entries in sections arrays
6556 * @param sections
6557 * Returns the array of file sections. Apply free() to dispose it.
6558 * @param flag
6559 * Reserved for future usage, submit 0
6560 * @return
6561 * 1 if there are valid extents (file comes from old image),
6562 * 0 if file was newly added, i.e. it does not come from an old image,
6563 * < 0 error
6564 */
iso_file_get_old_image_sections(IsoFile * file,int * section_count,struct iso_file_section ** sections,int flag)6565 int iso_file_get_old_image_sections(IsoFile *file, int *section_count,
6566 struct iso_file_section **sections,
6567 int flag)
6568 {
6569 if (file == NULL || section_count == NULL || sections == NULL) {
6570 return ISO_NULL_POINTER;
6571 }
6572 if (flag != 0) {
6573 return ISO_WRONG_ARG_VALUE;
6574 }
6575 *section_count = 0;
6576 *sections = NULL;
6577 if (file->from_old_session != 0) {
6578
6579 /*
6580 * When file is from old session, we retrieve the original IsoFileSource
6581 * to get the sections. This break encapsultation, but safes memory as
6582 * we don't need to store the sections in the IsoFile node.
6583 */
6584 IsoStream *stream = file->stream, *input_stream;
6585 FSrcStreamData *data;
6586 ImageFileSourceData *ifsdata;
6587
6588 /* Get the most original stream */
6589 while (1) {
6590 input_stream = iso_stream_get_input_stream(stream, 0);
6591 if (input_stream == NULL || input_stream == stream)
6592 break;
6593 stream = input_stream;
6594 }
6595
6596 /* From here on it must be a stream with FSrcStreamData. */
6597 /* ??? Shall one rather check :
6598 stream->class == extern IsoStreamIface fsrc_stream_class
6599 (its storage location is global in stream.c)
6600 */
6601 if (stream->class->type[0] != 'f' || stream->class->type[1] != 's' ||
6602 stream->class->type[2] != 'r' || stream->class->type[3] != 'c')
6603 return 0;
6604
6605 data = stream->data;
6606 ifsdata = data->src->data;
6607
6608 *section_count = ifsdata->nsections;
6609 if (*section_count <= 0)
6610 return 1;
6611 *sections = malloc(ifsdata->nsections *
6612 sizeof(struct iso_file_section));
6613 if (*sections == NULL) {
6614 return ISO_OUT_OF_MEM;
6615 }
6616 memcpy(*sections, ifsdata->sections,
6617 ifsdata->nsections * sizeof(struct iso_file_section));
6618 return 1;
6619 }
6620 return 0;
6621 }
6622
6623 /* Rank two IsoFileSource by their eventual old image LBAs if still non-zero.
6624 Other IsoFileSource classes and zeroized LBAs will be ranked only roughly.
6625 flag bit0 preserves transitivity of the caller by evaluating ifs_class with
6626 non-zero block address as smaller than anything else.
6627 flag bit1 could harm reproducibility of ISO image output.
6628 @param flag bit0= if s1 exor s2 is of applicable class, then enforce
6629 a valid test result by comparing classes
6630 bit1= if both are applicable but also have sections[].block == 0
6631 then enforce a valid test result by comparing object addresses.
6632 */
iso_ifs_sections_cmp(IsoFileSource * s1,IsoFileSource * s2,int * cmp_ret,int flag)6633 int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
6634 int flag)
6635 {
6636 int i;
6637 ImageFileSourceData *d1 = NULL, *d2 = NULL;
6638 IsoFileSourceIface *class1 = NULL, *class2 = NULL;
6639
6640 /* Newly created IsoFileSrc from imported IsoFile (e.g. boot image)
6641 is not an applicable source. It must be kept from causing a decision
6642 with other non-applicables.
6643 */
6644 if (s1 != NULL) {
6645 class1 = (IsoFileSourceIface *) s1->class;
6646 if (class1 == &ifs_class) {
6647 d1 = (ImageFileSourceData *) s1->data;
6648 if (d1->nsections > 0)
6649 if (d1->sections[0].block == 0)
6650 class1 = NULL;
6651 }
6652 }
6653 if (s2 != NULL) {
6654 class2 = (IsoFileSourceIface *) s2->class;
6655 if (class2 == &ifs_class) {
6656 d2 = (ImageFileSourceData *) s2->data;
6657 if (d2->nsections > 0)
6658 if (d2->sections[0].block == 0)
6659 class2 = NULL;
6660 }
6661 }
6662
6663 if (class1 != &ifs_class && class2 != &ifs_class) {
6664 *cmp_ret = 0;
6665 return 0;
6666 }
6667 if (class1 != class2) {
6668 *cmp_ret = (class1 == &ifs_class ? -1 : 1);
6669 if (flag & 1)
6670 return 1;
6671 return 0;
6672 }
6673
6674 if (d1->nsections != d2->nsections) {
6675 *cmp_ret = d1->nsections < d2->nsections ? -1 : 1;
6676 return 1;
6677 }
6678 if (d1->nsections == 0) {
6679 *cmp_ret = 0;
6680 return 1;
6681 }
6682 if (d1->sections[0].size < 1 || d2->sections[0].size < 1) {
6683 if (d1->sections[0].size > d2->sections[0].size)
6684 *cmp_ret = 1;
6685 else if (d1->sections[0].size < d2->sections[0].size)
6686 *cmp_ret = -1;
6687 else
6688 *cmp_ret = 0;
6689 return 1;
6690 }
6691
6692 for (i = 0; i < d1->nsections; i++) {
6693 if (d1->sections[i].block != d2->sections[i].block) {
6694 *cmp_ret = (d1->sections[i].block < d2->sections[i].block ? -1 : 1);
6695 return 1;
6696 }
6697 if (d1->sections[i].size != d2->sections[i].size) {
6698 *cmp_ret = (d1->sections[i].size < d2->sections[i].size ? -1 : 1);
6699 return 1;
6700 }
6701 }
6702 *cmp_ret = 0;
6703 return 1;
6704 }
6705
6706