1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2009 - 2015 Thomas Schmitt
4  *
5  * This file is part of the libisofs project; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * or later as published by the Free Software Foundation.
8  * See COPYING file for details.
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #include "libisofs.h"
16 #include "image.h"
17 #include "node.h"
18 #include "messages.h"
19 #include "eltorito.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 
25 
iso_imported_sa_new(struct iso_imported_sys_area ** boots,int flag)26 int iso_imported_sa_new(struct iso_imported_sys_area **boots, int flag)
27 {
28     struct iso_imported_sys_area *b;
29 
30     *boots = NULL;
31     b = calloc(1, sizeof(struct iso_imported_sys_area));
32     if (b == NULL)
33         return ISO_OUT_OF_MEM;
34 
35     b->mbr_req = NULL;
36     b->apm_req = NULL;
37 
38     b->gpt_req = NULL;
39     b->gpt_backup_comments = NULL;
40 
41     b->mips_boot_file_paths = NULL;
42     b->mips_vd_entries = NULL;
43 
44     b->sparc_disc_label = NULL;
45     b->sparc_core_node = NULL;
46     b->sparc_entries = NULL;
47 
48     b->hppa_cmdline = NULL;
49     b->hppa_bootloader = NULL;
50     b->hppa_kernel_32 = NULL;
51     b->hppa_kernel_64 = NULL;
52     b->hppa_ramdisk = NULL;
53 
54     b->alpha_boot_image = NULL;
55 
56     *boots = b;
57     return 1;
58 }
59 
iso_imported_sa_unref(struct iso_imported_sys_area ** boots,int flag)60 int iso_imported_sa_unref(struct iso_imported_sys_area **boots, int flag)
61 {
62     int i;
63     struct iso_imported_sys_area *b;
64 
65     b = *boots;
66     if (b == NULL)
67         return 2;
68     if (b->refcount > 0)
69         b->refcount--;
70     if (b->refcount > 0)
71         return 2;
72 
73     if (b->mbr_req != NULL) {
74         for (i = 0; i < b->mbr_req_count; i++)
75             LIBISO_FREE_MEM(b->mbr_req[i]);
76         LIBISO_FREE_MEM(b->mbr_req);
77     }
78     if (b->apm_req != NULL) {
79         for (i = 0; i < b->apm_req_count; i++)
80             LIBISO_FREE_MEM(b->apm_req[i]);
81         LIBISO_FREE_MEM(b->apm_req);
82     }
83     if (b->gpt_req != NULL) {
84         for (i = 0; i < b->gpt_req_count; i++)
85             LIBISO_FREE_MEM(b->gpt_req[i]);
86         LIBISO_FREE_MEM(b->gpt_req);
87     }
88     LIBISO_FREE_MEM(b->gpt_backup_comments);
89 
90     if (b->mips_boot_file_paths != NULL) {
91         for (i = 0; i < b->num_mips_boot_files; i++)
92             LIBISO_FREE_MEM(b->mips_boot_file_paths[i]);
93         LIBISO_FREE_MEM(b->mips_boot_file_paths);
94     }
95     if (b->mips_vd_entries != NULL) {
96         for (i = 0; i < b->num_mips_boot_files; i++)
97             LIBISO_FREE_MEM(b->mips_vd_entries[i]);
98         LIBISO_FREE_MEM(b->mips_vd_entries);
99     }
100     LIBISO_FREE_MEM(b->mipsel_boot_file_path);
101 
102     LIBISO_FREE_MEM(b->sparc_disc_label);
103     if (b->sparc_core_node != NULL)
104         iso_node_unref((IsoNode *) b->sparc_core_node);
105     LIBISO_FREE_MEM(b->sparc_entries);
106 
107     LIBISO_FREE_MEM(b->hppa_cmdline);
108     LIBISO_FREE_MEM(b->hppa_bootloader);
109     LIBISO_FREE_MEM(b->hppa_kernel_32);
110     LIBISO_FREE_MEM(b->hppa_kernel_64);
111     LIBISO_FREE_MEM(b->hppa_ramdisk);
112     LIBISO_FREE_MEM(b->alpha_boot_image);
113     LIBISO_FREE_MEM(b);
114     *boots = NULL;
115     return 1;
116 }
117 
118 
119 /**
120  * Create a new image, empty.
121  *
122  * The image will be owned by you and should be unref() when no more needed.
123  *
124  * @param name
125  *     Name of the image. This will be used as volset_id and volume_id.
126  * @param image
127  *     Location where the image pointer will be stored.
128  * @return
129  *     1 success, < 0 error
130  */
iso_image_new(const char * name,IsoImage ** image)131 int iso_image_new(const char *name, IsoImage **image)
132 {
133     int res, i;
134     IsoImage *img;
135 
136     if (image == NULL) {
137         return ISO_NULL_POINTER;
138     }
139 
140     img = calloc(1, sizeof(IsoImage));
141     if (img == NULL) {
142         return ISO_OUT_OF_MEM;
143     }
144 
145     /* local filesystem will be used by default */
146     res = iso_local_filesystem_new(&(img->fs));
147     if (res < 0) {
148         free(img);
149         return ISO_OUT_OF_MEM;
150     }
151 
152     /* use basic builder as default */
153     res = iso_node_basic_builder_new(&(img->builder));
154     if (res < 0) {
155         iso_filesystem_unref(img->fs);
156         free(img);
157         return ISO_OUT_OF_MEM;
158     }
159 
160     /* fill image fields */
161     res = iso_node_new_root(&img->root);
162     if (res < 0) {
163         iso_node_builder_unref(img->builder);
164         iso_filesystem_unref(img->fs);
165         free(img);
166         return res;
167     }
168     img->refcount = 1;
169     img->id = iso_message_id++;
170 
171     if (name != NULL) {
172         img->volset_id = strdup(name);
173         img->volume_id = strdup(name);
174     }
175     memset(img->application_use, 0, 512);
176     img->system_area_data = NULL;
177     img->system_area_options = 0;
178     img->num_mips_boot_files = 0;
179     for (i = 0; i < 15; i++)
180          img->mips_boot_file_paths[i] = NULL;
181     img->sparc_core_node = NULL;
182     img->hppa_cmdline= NULL;
183     img->hppa_bootloader = NULL;
184     img->hppa_kernel_32 = NULL;
185     img->hppa_kernel_64 = NULL;
186     img->hppa_ramdisk = NULL;
187     img->alpha_boot_image = NULL;
188     img->import_src = NULL;
189     img->builder_ignore_acl = 1;
190     img->builder_ignore_ea = 1;
191     img->truncate_mode = 1;
192     img->truncate_length = LIBISOFS_NODE_NAME_MAX;
193     img->truncate_buffer[0] = 0;
194     img->inode_counter = 0;
195     img->used_inodes = NULL;
196     img->used_inodes_start = 0;
197     img->checksum_start_lba = 0;
198     img->checksum_end_lba = 0;
199     img->checksum_idx_count = 0;
200     img->checksum_array = NULL;
201     img->generator_is_running = 0;
202     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
203         img->hfsplus_blessed[i] = NULL;
204     img->collision_warnings = 0;
205     img->imported_sa_info = NULL;
206     img->blind_on_local_get_attrs = 0;
207 
208     *image = img;
209     return ISO_SUCCESS;
210 }
211 
212 /**
213  * Increments the reference counting of the given image.
214  */
iso_image_ref(IsoImage * image)215 void iso_image_ref(IsoImage *image)
216 {
217     ++image->refcount;
218 }
219 
220 /**
221  * Decrements the reference counting of the given image.
222  * If it reaches 0, the image is free, together with its tree nodes (whether
223  * their refcount reach 0 too, of course).
224  */
iso_image_unref(IsoImage * image)225 void iso_image_unref(IsoImage *image)
226 {
227     int nexcl, i;
228 
229     if (--image->refcount == 0) {
230         /* we need to free the image */
231 
232         if (image->user_data_free != NULL) {
233             /* free attached data */
234             image->user_data_free(image->user_data);
235         }
236         for (nexcl = 0; nexcl < image->nexcludes; ++nexcl) {
237             free(image->excludes[nexcl]);
238         }
239         free(image->excludes);
240         for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
241             if (image->hfsplus_blessed[i] != NULL)
242                 iso_node_unref(image->hfsplus_blessed[i]);
243         iso_node_unref((IsoNode*)image->root);
244         iso_node_builder_unref(image->builder);
245         iso_filesystem_unref(image->fs);
246         el_torito_boot_catalog_free(image->bootcat);
247         iso_image_give_up_mips_boot(image, 0);
248         if (image->sparc_core_node != NULL)
249             iso_node_unref((IsoNode *) image->sparc_core_node);
250         iso_image_set_hppa_palo(image, NULL, NULL, NULL, NULL, NULL, 1);
251         if (image->alpha_boot_image != NULL)
252             free(image->alpha_boot_image);
253         if (image->import_src != NULL)
254             iso_data_source_unref(image->import_src);
255         free(image->volset_id);
256         free(image->volume_id);
257         free(image->publisher_id);
258         free(image->data_preparer_id);
259         free(image->system_id);
260         free(image->application_id);
261         free(image->copyright_file_id);
262         free(image->abstract_file_id);
263         free(image->biblio_file_id);
264         free(image->creation_time);
265         free(image->modification_time);
266         free(image->expiration_time);
267         free(image->effective_time);
268         if (image->used_inodes != NULL)
269             free(image->used_inodes);
270         if (image->system_area_data != NULL)
271             free(image->system_area_data);
272         iso_image_free_checksums(image, 0);
273         iso_imported_sa_unref(&(image->imported_sa_info), 0);
274         free(image);
275     }
276 }
277 
278 
iso_image_free_checksums(IsoImage * image,int flag)279 int iso_image_free_checksums(IsoImage *image, int flag)
280 {
281     image->checksum_start_lba = 0;
282     image->checksum_end_lba = 0;
283     image->checksum_idx_count = 0;
284     if (image->checksum_array != NULL)
285         free(image->checksum_array);
286     image->checksum_array = NULL;
287     return 1;
288 }
289 
290 
291 /**
292  * Attach user defined data to the image. Use this if your application needs
293  * to store addition info together with the IsoImage. If the image already
294  * has data attached, the old data will be freed.
295  *
296  * @param data
297  *      Pointer to application defined data that will be attached to the
298  *      image. You can pass NULL to remove any already attached data.
299  * @param give_up
300  *      Function that will be called when the image does not need the data
301  *      any more. It receives the data pointer as an argumente, and eventually
302  *      causes data to be free. It can be NULL if you don't need it.
303  */
iso_image_attach_data(IsoImage * image,void * data,void (* give_up)(void *))304 int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
305 {
306     if (image == NULL) {
307         return ISO_NULL_POINTER;
308     }
309 
310     if (image->user_data != NULL) {
311         /* free previously attached data */
312         if (image->user_data_free != NULL) {
313             image->user_data_free(image->user_data);
314         }
315         image->user_data = NULL;
316         image->user_data_free = NULL;
317     }
318 
319     if (data != NULL) {
320         image->user_data = data;
321         image->user_data_free = give_up;
322     }
323     return ISO_SUCCESS;
324 }
325 
326 /**
327  * The the data previously attached with iso_image_attach_data()
328  */
iso_image_get_attached_data(IsoImage * image)329 void *iso_image_get_attached_data(IsoImage *image)
330 {
331     return image->user_data;
332 }
333 
iso_image_get_root(const IsoImage * image)334 IsoDir *iso_image_get_root(const IsoImage *image)
335 {
336     return image->root;
337 }
338 
iso_image_set_volset_id(IsoImage * image,const char * volset_id)339 void iso_image_set_volset_id(IsoImage *image, const char *volset_id)
340 {
341     free(image->volset_id);
342     image->volset_id = strdup(volset_id);
343 }
344 
iso_image_get_volset_id(const IsoImage * image)345 const char *iso_image_get_volset_id(const IsoImage *image)
346 {
347     if (image->volset_id == NULL)
348         return "";
349     return image->volset_id;
350 }
351 
iso_image_set_volume_id(IsoImage * image,const char * volume_id)352 void iso_image_set_volume_id(IsoImage *image, const char *volume_id)
353 {
354     free(image->volume_id);
355     image->volume_id = strdup(volume_id);
356 }
357 
iso_image_get_volume_id(const IsoImage * image)358 const char *iso_image_get_volume_id(const IsoImage *image)
359 {
360     if (image->volume_id == NULL)
361         return "";
362     return image->volume_id;
363 }
364 
iso_image_set_publisher_id(IsoImage * image,const char * publisher_id)365 void iso_image_set_publisher_id(IsoImage *image, const char *publisher_id)
366 {
367     free(image->publisher_id);
368     image->publisher_id = strdup(publisher_id);
369 }
370 
iso_image_get_publisher_id(const IsoImage * image)371 const char *iso_image_get_publisher_id(const IsoImage *image)
372 {
373     if (image->publisher_id == NULL)
374         return "";
375     return image->publisher_id;
376 }
377 
iso_image_set_data_preparer_id(IsoImage * image,const char * data_preparer_id)378 void iso_image_set_data_preparer_id(IsoImage *image,
379                                     const char *data_preparer_id)
380 {
381     free(image->data_preparer_id);
382     image->data_preparer_id = strdup(data_preparer_id);
383 }
384 
iso_image_get_data_preparer_id(const IsoImage * image)385 const char *iso_image_get_data_preparer_id(const IsoImage *image)
386 {
387     if (image->data_preparer_id == NULL)
388         return "";
389     return image->data_preparer_id;
390 }
391 
iso_image_set_system_id(IsoImage * image,const char * system_id)392 void iso_image_set_system_id(IsoImage *image, const char *system_id)
393 {
394     free(image->system_id);
395     image->system_id = strdup(system_id);
396 }
397 
iso_image_get_system_id(const IsoImage * image)398 const char *iso_image_get_system_id(const IsoImage *image)
399 {
400     if (image->system_id == NULL)
401         return "";
402     return image->system_id;
403 }
404 
iso_image_set_application_id(IsoImage * image,const char * application_id)405 void iso_image_set_application_id(IsoImage *image, const char *application_id)
406 {
407     free(image->application_id);
408     image->application_id = strdup(application_id);
409 }
410 
iso_image_get_application_id(const IsoImage * image)411 const char *iso_image_get_application_id(const IsoImage *image)
412 {
413     if (image->application_id == NULL)
414         return "";
415     return image->application_id;
416 }
417 
iso_image_set_copyright_file_id(IsoImage * image,const char * copyright_file_id)418 void iso_image_set_copyright_file_id(IsoImage *image,
419                                      const char *copyright_file_id)
420 {
421     free(image->copyright_file_id);
422     image->copyright_file_id = strdup(copyright_file_id);
423 }
424 
iso_image_get_copyright_file_id(const IsoImage * image)425 const char *iso_image_get_copyright_file_id(const IsoImage *image)
426 {
427     if (image->copyright_file_id == NULL)
428         return "";
429     return image->copyright_file_id;
430 }
431 
iso_image_set_abstract_file_id(IsoImage * image,const char * abstract_file_id)432 void iso_image_set_abstract_file_id(IsoImage *image,
433                                     const char *abstract_file_id)
434 {
435     free(image->abstract_file_id);
436     image->abstract_file_id = strdup(abstract_file_id);
437 }
438 
iso_image_get_abstract_file_id(const IsoImage * image)439 const char *iso_image_get_abstract_file_id(const IsoImage *image)
440 {
441     if (image->abstract_file_id == NULL)
442         return "";
443     return image->abstract_file_id;
444 }
445 
iso_image_set_biblio_file_id(IsoImage * image,const char * biblio_file_id)446 void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id)
447 {
448     free(image->biblio_file_id);
449     image->biblio_file_id = strdup(biblio_file_id);
450 }
451 
iso_image_get_biblio_file_id(const IsoImage * image)452 const char *iso_image_get_biblio_file_id(const IsoImage *image)
453 {
454     if (image->biblio_file_id == NULL)
455         return "";
456     return image->biblio_file_id;
457 }
458 
iso_image_set_pvd_times(IsoImage * image,char * creation_time,char * modification_time,char * expiration_time,char * effective_time)459 int iso_image_set_pvd_times(IsoImage *image,
460                             char *creation_time, char *modification_time,
461                             char *expiration_time, char *effective_time)
462 {
463     if (creation_time == NULL || modification_time == NULL ||
464         expiration_time == NULL || effective_time == NULL)
465         return ISO_NULL_POINTER;
466     image->creation_time = calloc(18, 1);   /* Surely including a trailing 0 */
467     image->modification_time = calloc(18, 1);
468     image->expiration_time = calloc(18, 1);
469     image->effective_time = calloc(18, 1);
470     if (image->creation_time == NULL || image->modification_time == NULL ||
471         image->expiration_time == NULL || image->effective_time == NULL)
472         return ISO_OUT_OF_MEM;
473     /* (If the string is too short, a non-zero timezone will not be stored) */
474     strncpy(image->creation_time, creation_time, 17);
475     strncpy(image->modification_time, modification_time, 17);
476     strncpy(image->expiration_time, expiration_time, 17);
477     strncpy(image->effective_time, effective_time, 17);
478     return ISO_SUCCESS;
479 }
480 
iso_image_get_pvd_times(IsoImage * image,char ** creation_time,char ** modification_time,char ** expiration_time,char ** effective_time)481 int iso_image_get_pvd_times(IsoImage *image,
482                             char **creation_time, char **modification_time,
483                             char **expiration_time, char **effective_time)
484 {
485     if (image->creation_time == NULL || image->modification_time == NULL ||
486         image->expiration_time == NULL || image->effective_time == NULL)
487         return ISO_NULL_POINTER;
488     *creation_time = image->creation_time;
489     *modification_time = image->modification_time;
490     *expiration_time = image->expiration_time;
491     *effective_time = image->effective_time;
492     return ISO_SUCCESS;
493 }
494 
iso_image_set_app_use(IsoImage * image,const char * app_use_data,int count)495 void iso_image_set_app_use(IsoImage *image, const char *app_use_data,
496                            int count)
497 {
498     if (count < 0)
499         count= 0;
500     else if(count > 512)
501         count= 512;
502     if (count > 0)
503         memcpy(image->application_use, app_use_data, count);
504     if (count < 512)
505         memset(image->application_use + count, 0, 512 - count);
506 }
507 
iso_image_get_msg_id(IsoImage * image)508 int iso_image_get_msg_id(IsoImage *image)
509 {
510     return image->id;
511 }
512 
iso_image_get_system_area(IsoImage * img,char system_area_data[32768],int * options,int flag)513 int iso_image_get_system_area(IsoImage *img, char system_area_data[32768],
514                               int *options, int flag)
515 {
516     *options = img->system_area_options;
517     if (img->system_area_data == NULL)
518         return 0;
519     memcpy(system_area_data, img->system_area_data, 32768);
520     return 1;
521 }
522 
523 static
dir_update_size(IsoImage * image,IsoDir * dir)524 int dir_update_size(IsoImage *image, IsoDir *dir)
525 {
526     IsoNode *pos;
527     int ret;
528 
529 #ifdef Libisofs_update_sizes_abortablE
530     char *path= NULL;
531     IsoStream *base_stream;
532     int cancel_ret, ret;
533     uint32_t lba;
534 #endif
535 
536     pos = dir->children;
537     while (pos) {
538         if (pos->type == LIBISO_FILE) {
539             ret = iso_stream_update_size(ISO_FILE(pos)->stream);
540         } else if (pos->type == LIBISO_DIR) {
541             /* recurse */
542             ret = dir_update_size(image, ISO_DIR(pos));
543 
544 #ifdef Libisofs_update_sizes_abortablE
545             if (ret == ISO_CANCELED)
546                 return ret; /* Message already issued by dir_update_size */
547 #endif
548 
549         } else {
550             ret = 1;
551         }
552 
553 #ifdef Libisofs_update_sizes_abortablE
554 
555         /* This would report error and abort according to severity threshold.
556            But it is desirable to let the update_size crawler continue
557            its work after e.g. a file has vanished from hard disk.
558            So normally this macro case should be disabled.
559         */
560 
561         if (ret < 0) {
562             cancel_ret = iso_msg_submit(image->id, ret, 0, NULL);
563             path = iso_tree_get_node_path(pos);
564             if (path != NULL) {
565                 iso_msg_submit(image->id, ret, 0,
566                                "ISO path  : %s", path);
567                 free(path);
568             }
569             /* Report source path with streams which do not come from
570                the loaded ISO filesystem */
571             if (pos->type == LIBISO_FILE &&
572                 iso_node_get_old_image_lba(pos, &lba, 0) == 0) {
573                 base_stream = iso_stream_get_input_stream(
574                                                      ISO_FILE(pos)->stream, 1);
575                 if (base_stream == NULL)
576                     base_stream = ISO_FILE(pos)->stream;
577                 path = iso_stream_get_source_path(base_stream, 0);
578                 if (path != NULL) {
579                     iso_msg_submit(image->id, ret, 0,
580                                    "Local path: %s", path);
581                     free(path);
582                 }
583             }
584             if (cancel_ret < 0)
585                 return cancel_ret; /* cancel due error threshold */
586         }
587 
588 #else
589 
590         if (ret < 0)
591             ret = 1; /* ignore error */
592 
593 #endif /* ! Libisofs_update_sizes_abortablE */
594 
595         pos = pos->next;
596     }
597     return ISO_SUCCESS;
598 }
599 
iso_image_update_sizes(IsoImage * image)600 int iso_image_update_sizes(IsoImage *image)
601 {
602     if (image == NULL) {
603         return ISO_NULL_POINTER;
604     }
605 
606     return dir_update_size(image, image->root);
607 }
608 
609 
iso_image_set_ignore_aclea(IsoImage * image,int what)610 void iso_image_set_ignore_aclea(IsoImage *image, int what)
611 {
612     image->builder_ignore_acl = (what & 1);
613     image->builder_ignore_ea = !!(what & 2);
614     image->builder_take_all_ea = !!(what & 8);
615 }
616 
617 
iso_image_get_ignore_aclea(IsoImage * image)618 int iso_image_get_ignore_aclea(IsoImage *image)
619 {
620     return image->builder_ignore_acl |
621            (image->builder_ignore_ea << 1) |
622            (image->builder_take_all_ea << 3);
623 }
624 
625 
626 static
img_register_ino(IsoImage * image,IsoNode * node,int flag)627 int img_register_ino(IsoImage *image, IsoNode *node, int flag)
628 {
629     int ret;
630     ino_t ino;
631     unsigned int fs_id;
632     dev_t dev_id;
633 
634     ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
635     if (ret < 0)
636        return ret;
637     if (ret > 0 && ino >= image->used_inodes_start &&
638         ino <= image->used_inodes_start + (ISO_USED_INODE_RANGE - 1)) {
639                                    /* without -1 : rollover hazard on 32 bit */
640         image->used_inodes[(ino - image->used_inodes_start) / 8]
641                                                            |= (1 << (ino % 8));
642     }
643     return 1;
644 }
645 
646 
647 /* Collect the bitmap of used inode numbers in the range of
648    _ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE
649    @param flag bit0= recursion is active
650 */
img_collect_inos(IsoImage * image,IsoDir * dir,int flag)651 int img_collect_inos(IsoImage *image, IsoDir *dir, int flag)
652 {
653     int ret, register_dir = 1;
654     IsoDirIter *iter = NULL;
655     IsoNode *node;
656     IsoDir *subdir;
657 
658     if (dir == NULL)
659         dir = image->root;
660     if (image->used_inodes == NULL) {
661         image->used_inodes = calloc(ISO_USED_INODE_RANGE / 8, 1);
662         if (image->used_inodes == NULL)
663             return ISO_OUT_OF_MEM;
664     } else if(!(flag & 1)) {
665         memset(image->used_inodes, 0, ISO_USED_INODE_RANGE / 8);
666     } else {
667         register_dir = 0;
668     }
669     if (register_dir) {
670         node = (IsoNode *) dir;
671         ret = img_register_ino(image, node, 0);
672         if (ret < 0)
673             return ret;
674     }
675 
676     ret = iso_dir_get_children(dir, &iter);
677     if (ret < 0)
678         return ret;
679     while (iso_dir_iter_next(iter, &node) == 1 ) {
680         ret = img_register_ino(image, node, 0);
681         if (ret < 0)
682             goto ex;
683         if (iso_node_get_type(node) == LIBISO_DIR) {
684             subdir = (IsoDir *) node;
685             ret = img_collect_inos(image, subdir, flag | 1);
686             if (ret < 0)
687                 goto ex;
688         }
689     }
690     ret = 1;
691 ex:;
692     if (iter != NULL)
693         iso_dir_iter_free(iter);
694     return ret;
695 }
696 
697 
698 /**
699  * A global counter for Rock Ridge inode numbers in the ISO image filesystem.
700  *
701  * On image import it gets maxed by the eventual inode numbers from PX
702  * entries. Up to the first 32 bit rollover it simply increments the counter.
703  * After the first rollover it uses a look ahead bitmap which gets filled
704  * by a full tree traversal. It covers the next inode numbers to come
705  * (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many)
706  * and advances when being exhausted.
707  * @param image The image where the number shall be used
708  * @param flag  bit0= reset count (Caution: image must get new inos then)
709  * @return
710  *     Since 0 is used as default and considered self-unique,
711  *     the value 0 should only be returned in case of error.
712  */
img_give_ino_number(IsoImage * image,int flag)713 uint32_t img_give_ino_number(IsoImage *image, int flag)
714 {
715     int ret;
716     uint64_t new_ino, ino_idx;
717     static uint64_t limit = 0xffffffff;
718 
719     if (flag & 1) {
720         image->inode_counter = 0;
721         if (image->used_inodes != NULL)
722             free(image->used_inodes);
723         image->used_inodes = NULL;
724         image->used_inodes_start = 0;
725     }
726     new_ino = ((uint64_t) image->inode_counter) + 1;
727     if (image->used_inodes == NULL) {
728         if (new_ino > 0 && new_ino <= limit) {
729             image->inode_counter = (uint32_t) new_ino;
730             return image->inode_counter;
731         }
732     }
733     /* Look for free number in used territory */
734     while (1) {
735         if (new_ino <= 0 || new_ino > limit ||
736             new_ino >= image->used_inodes_start + ISO_USED_INODE_RANGE ) {
737 
738             /* Collect a bitmap of used inode numbers ahead */
739 
740             image->used_inodes_start += ISO_USED_INODE_RANGE;
741             if (image->used_inodes_start > 0xffffffff ||
742                 image->used_inodes_start <= 0)
743                 image->used_inodes_start = 0;
744             ret = img_collect_inos(image, NULL, 0);
745             if (ret < 0)
746                 goto return_result; /* >>> need error return value */
747 
748             new_ino = image->used_inodes_start + !image->used_inodes_start;
749         }
750         ino_idx = (new_ino - image->used_inodes_start) / 8;
751         if (!(image->used_inodes[ino_idx] & (1 << (new_ino % 8)))) {
752             image->used_inodes[ino_idx] |= (1 << (new_ino % 8));
753     break;
754         }
755         new_ino++;
756     }
757 return_result:;
758     image->inode_counter = new_ino;
759     return image->inode_counter;
760 }
761 
762 
763 /* @param flag bit0= overwrite any ino, else only ino == 0
764                bit1= install inode with non-data, non-directory files
765                bit2= install inode with directories
766 */
767 static
img_update_ino(IsoImage * image,IsoNode * node,int flag)768 int img_update_ino(IsoImage *image, IsoNode *node, int flag)
769 {
770     int ret;
771     ino_t ino;
772     unsigned int fs_id;
773     dev_t dev_id;
774 
775     ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
776     if (ret < 0)
777         return ret;
778     if (ret == 0)
779        ino = 0;
780     if (((flag & 1) || ino == 0) &&
781         (iso_node_get_type(node) == LIBISO_FILE || (flag & (2 | 4))) &&
782         ((flag & 4) || iso_node_get_type(node) != LIBISO_DIR)) {
783         ret = iso_node_set_unique_id(node, image, 0);
784         if (ret < 0)
785             return ret;
786     }
787     return 1;
788 }
789 
790 
791 /* @param flag bit0= overwrite any ino, else only ino == 0
792                bit1= install inode with non-data, non-directory files
793                bit2= install inode with directories
794                bit3= with bit2: install inode on parameter dir
795 */
img_make_inos(IsoImage * image,IsoDir * dir,int flag)796 int img_make_inos(IsoImage *image, IsoDir *dir, int flag)
797 {
798     int ret;
799     IsoDirIter *iter = NULL;
800     IsoNode *node;
801     IsoDir *subdir;
802 
803     if (flag & 8) {
804         node = (IsoNode *) dir;
805         ret = img_update_ino(image, node, flag & 7);
806         if (ret < 0)
807             goto ex;
808     }
809     ret = iso_dir_get_children(dir, &iter);
810     if (ret < 0)
811         return ret;
812     while (iso_dir_iter_next(iter, &node) == 1) {
813         ret = img_update_ino(image, node, flag & 7);
814         if (ret < 0)
815             goto ex;
816         if (iso_node_get_type(node) == LIBISO_DIR) {
817             subdir = (IsoDir *) node;
818             ret = img_make_inos(image, subdir, flag & ~8);
819             if (ret < 0)
820                 goto ex;
821         }
822     }
823     ret = 1;
824 ex:;
825     if (iter != NULL)
826         iso_dir_iter_free(iter);
827     return ret;
828 }
829 
830 
831 /* API */
iso_image_get_session_md5(IsoImage * image,uint32_t * start_lba,uint32_t * end_lba,char md5[16],int flag)832 int iso_image_get_session_md5(IsoImage *image, uint32_t *start_lba,
833                               uint32_t *end_lba, char md5[16], int flag)
834 {
835     if (image->checksum_array == NULL || image->checksum_idx_count < 1)
836         return 0;
837     *start_lba = image->checksum_start_lba;
838     *end_lba = image->checksum_end_lba;
839     memcpy(md5, image->checksum_array, 16);
840     return ISO_SUCCESS;
841 }
842 
iso_image_set_checksums(IsoImage * image,char * checksum_array,uint32_t start_lba,uint32_t end_lba,uint32_t idx_count,int flag)843 int iso_image_set_checksums(IsoImage *image, char *checksum_array,
844                             uint32_t start_lba, uint32_t end_lba,
845                             uint32_t idx_count, int flag)
846 {
847     iso_image_free_checksums(image, 0);
848     image->checksum_array = checksum_array;
849     image->checksum_start_lba = start_lba;
850     image->checksum_end_lba = end_lba;
851     image->checksum_idx_count = idx_count;
852     return 1;
853 }
854 
iso_image_generator_is_running(IsoImage * image)855 int iso_image_generator_is_running(IsoImage *image)
856 {
857     return image->generator_is_running;
858 }
859 
860 
861 /* API */
iso_image_add_mips_boot_file(IsoImage * image,char * path,int flag)862 int iso_image_add_mips_boot_file(IsoImage *image, char *path, int flag)
863 {
864     if (image->num_mips_boot_files >= 15)
865         return ISO_BOOT_TOO_MANY_MIPS;
866     image->mips_boot_file_paths[image->num_mips_boot_files] = strdup(path);
867     if (image->mips_boot_file_paths[image->num_mips_boot_files] == NULL)
868         return ISO_OUT_OF_MEM;
869     image->num_mips_boot_files++;
870     return ISO_SUCCESS;
871 }
872 
873 /* API */
iso_image_get_mips_boot_files(IsoImage * image,char * paths[15],int flag)874 int iso_image_get_mips_boot_files(IsoImage *image, char *paths[15], int flag)
875 {
876     int i;
877 
878     for (i = 0; i < image->num_mips_boot_files; i++)
879          paths[i] = image->mips_boot_file_paths[i];
880     for (; i < 15; i++)
881          paths[i] = NULL;
882     return image->num_mips_boot_files;
883 }
884 
885 /* API */
iso_image_give_up_mips_boot(IsoImage * image,int flag)886 int iso_image_give_up_mips_boot(IsoImage *image, int flag)
887 {
888     int i;
889 
890     for (i = 0; i < image->num_mips_boot_files; i++)
891         if (image->mips_boot_file_paths[i] != NULL) {
892             free(image->mips_boot_file_paths[i]);
893             image->mips_boot_file_paths[i] = NULL;
894         }
895     image->num_mips_boot_files = 0;
896     return ISO_SUCCESS;
897 }
898 
unset_blessing(IsoImage * img,unsigned int idx)899 static void unset_blessing(IsoImage *img, unsigned int idx)
900 {
901     if (img->hfsplus_blessed[idx] != NULL)
902         iso_node_unref(img->hfsplus_blessed[idx]);
903     img->hfsplus_blessed[idx] = NULL;
904 }
905 
906 /* API */
iso_image_hfsplus_bless(IsoImage * img,enum IsoHfsplusBlessings blessing,IsoNode * node,int flag)907 int iso_image_hfsplus_bless(IsoImage *img, enum IsoHfsplusBlessings blessing,
908                             IsoNode *node, int flag)
909 {
910     unsigned int i, ok = 0;
911 
912     if (flag & 2) {
913         /* Delete any blessing */
914         for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++) {
915             if (img->hfsplus_blessed[i] == node || node == NULL) {
916                 unset_blessing(img, i);
917                 ok = 1;
918             }
919         }
920         return ok;
921     }
922     if (blessing == ISO_HFSPLUS_BLESS_MAX)
923         return ISO_WRONG_ARG_VALUE;
924     if (flag & 1) {
925         /* Delete a particular blessing */
926         if (img->hfsplus_blessed[blessing] == node || node == NULL) {
927             unset_blessing(img, (unsigned int) blessing);
928             return 1;
929         }
930         return 0;
931     }
932 
933     if (node == NULL) {
934         unset_blessing(img, (unsigned int) blessing);
935         return 1;
936     }
937 
938     /* No two hats on one node */
939     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX && node != NULL; i++)
940         if (i != blessing && img->hfsplus_blessed[i] == node)
941             return 0;
942     /* Enforce correct file type */
943     if (blessing == ISO_HFSPLUS_BLESS_INTEL_BOOTFILE) {
944         if (node->type != LIBISO_FILE)
945             return 0;
946     } else {
947         if (node->type != LIBISO_DIR)
948             return 0;
949     }
950 
951     unset_blessing(img, (unsigned int) blessing);
952     img->hfsplus_blessed[blessing] = node;
953     if (node != NULL)
954         iso_node_ref(node);
955     return 1;
956 }
957 
958 
959 /* API */
iso_image_hfsplus_get_blessed(IsoImage * img,IsoNode *** blessed_nodes,int * bless_max,int flag)960 int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes,
961                                   int *bless_max, int flag)
962 {
963     *blessed_nodes = img->hfsplus_blessed;
964     *bless_max = ISO_HFSPLUS_BLESS_MAX;
965     return 1;
966 }
967 
968 
969 /* API */
iso_image_set_sparc_core(IsoImage * img,IsoFile * sparc_core,int flag)970 int iso_image_set_sparc_core(IsoImage *img, IsoFile *sparc_core, int flag)
971 {
972     if (img->sparc_core_node != NULL)
973         iso_node_unref((IsoNode *) img->sparc_core_node);
974     img->sparc_core_node = sparc_core;
975     if (sparc_core != NULL)
976         iso_node_ref((IsoNode *) sparc_core);
977     return 1;
978 }
979 
980 
981 /* API */
iso_image_get_sparc_core(IsoImage * img,IsoFile ** sparc_core,int flag)982 int iso_image_get_sparc_core(IsoImage *img, IsoFile **sparc_core, int flag)
983 {
984     *sparc_core = img->sparc_core_node;
985     return 1;
986 }
987 
988 
989 /* @param flag
990            bit0= Let NULL parameters free the corresponding image properties.
991                  Else only the non-NULL parameters of this call have an effect.
992 */
hppa_palo_set_path(IsoImage * img,char * path,char ** target,char * what,int flag)993 static int hppa_palo_set_path(IsoImage *img, char *path, char **target,
994                               char *what, int flag)
995 {
996     int ret, err;
997     IsoNode *node;
998     IsoFile *file;
999 
1000     if (path == NULL && !(flag & 1))
1001         return ISO_SUCCESS;
1002     if (iso_clone_mgtd_mem(path, target, 0) < 0)
1003         return ISO_OUT_OF_MEM;
1004     if (path == NULL)
1005         return ISO_SUCCESS;
1006     ret = iso_tree_path_to_node(img, path, &node);
1007     if (ret < 0)
1008         return ret;
1009     if (ret == 0) {
1010         iso_msg_submit(img->id, ISO_BOOT_FILE_MISSING, 0,
1011                        "Cannot find in ISO image: %s file '%s'", what, path);
1012         return ISO_BOOT_FILE_MISSING;
1013     }
1014     if (iso_node_get_type(node) != LIBISO_FILE) {
1015         err = ISO_HPPA_PALO_NOTREG;
1016         if (strncmp(what, "DEC Alpha", 9) == 0)
1017             err = ISO_ALPHA_BOOT_NOTREG;
1018         iso_msg_submit(img->id, err, 0,
1019                        "%s file is not a data file: '%s'", what, path);
1020         return err;
1021     }
1022     file = (IsoFile *) node;
1023     if (!(file->explicit_weight || file->from_old_session))
1024         file->sort_weight = 2;
1025     return ISO_SUCCESS;
1026 }
1027 
1028 
1029 /* API */
1030 /* @param flag
1031           Bitfield for control purposes
1032            bit0= Let NULL parameters free the corresponding image properties.
1033                  Else only the non-NULL parameters of this call have an effect.
1034 */
iso_image_set_hppa_palo(IsoImage * img,char * cmdline,char * bootloader,char * kernel_32,char * kernel_64,char * ramdisk,int flag)1035 int iso_image_set_hppa_palo(IsoImage *img, char *cmdline, char *bootloader,
1036                             char *kernel_32, char *kernel_64, char *ramdisk,
1037                             int flag)
1038 {
1039     int ret;
1040     static char *what = "HP-PA PALO";
1041 
1042     if (cmdline != NULL || (flag & 1))
1043         if (iso_clone_mgtd_mem(cmdline, &(img->hppa_cmdline), 0) < 0)
1044             return ISO_OUT_OF_MEM;
1045     ret = hppa_palo_set_path(img, bootloader, &(img->hppa_bootloader), what,
1046                              flag & 1);
1047     if (ret < 0)
1048         return ret;
1049     ret = hppa_palo_set_path(img, kernel_32, &(img->hppa_kernel_32), what,
1050                              flag & 1);
1051     if (ret < 0)
1052         return ret;
1053     ret = hppa_palo_set_path(img, kernel_64, &(img->hppa_kernel_64), what,
1054                              flag & 1);
1055     if (ret < 0)
1056         return ret;
1057     ret = hppa_palo_set_path(img, ramdisk, &(img->hppa_ramdisk), what,
1058                              flag & 1);
1059     if (ret < 0)
1060         return ret;
1061     return ISO_SUCCESS;
1062 }
1063 
1064 
1065 /* API */
iso_image_get_hppa_palo(IsoImage * img,char ** cmdline,char ** bootloader,char ** kernel_32,char ** kernel_64,char ** ramdisk)1066 int iso_image_get_hppa_palo(IsoImage *img, char **cmdline, char **bootloader,
1067                             char **kernel_32, char **kernel_64, char **ramdisk)
1068 {
1069     *cmdline = img->hppa_cmdline;
1070     *bootloader = img->hppa_bootloader;
1071     *kernel_32 = img->hppa_kernel_32;
1072     *kernel_64 = img->hppa_kernel_64;
1073     *ramdisk  = img->hppa_ramdisk;
1074     return ISO_SUCCESS;
1075 }
1076 
1077 
1078 /* API */
iso_image_set_alpha_boot(IsoImage * img,char * boot_loader_path,int flag)1079 int iso_image_set_alpha_boot(IsoImage *img, char *boot_loader_path, int flag)
1080 {
1081     int ret;
1082 
1083     ret = hppa_palo_set_path(img, boot_loader_path, &(img->alpha_boot_image),
1084                              "DEC Alpha Bootloader", 1);
1085     if (ret < 0)
1086         return ret;
1087     return ISO_SUCCESS;
1088 }
1089 
1090 
1091 /* API */
iso_image_get_alpha_boot(IsoImage * img,char ** boot_loader_path)1092 int iso_image_get_alpha_boot(IsoImage *img, char **boot_loader_path)
1093 {
1094     *boot_loader_path = img->alpha_boot_image;
1095     return ISO_SUCCESS;
1096 }
1097 
1098 
1099 /* API */
iso_image_set_truncate_mode(IsoImage * img,int mode,int length)1100 int iso_image_set_truncate_mode(IsoImage *img, int mode, int length)
1101 {
1102     if (mode < 0 || mode > 1)
1103         return ISO_WRONG_ARG_VALUE;
1104     if (length < 64 || length > LIBISOFS_NODE_NAME_MAX)
1105         return ISO_WRONG_ARG_VALUE;
1106     img->truncate_mode = mode;
1107     img->truncate_length = length;
1108     return ISO_SUCCESS;
1109 }
1110 
1111 /* API */
iso_image_get_truncate_mode(IsoImage * img,int * mode,int * length)1112 int iso_image_get_truncate_mode(IsoImage *img, int *mode, int *length)
1113 {
1114     *mode = img->truncate_mode;
1115     *length = img->truncate_length;
1116     return ISO_SUCCESS;
1117 }
1118 
1119 /* Warning: Not thread-safe */
iso_image_truncate_name(IsoImage * image,const char * name,char ** namept,int flag)1120 int iso_image_truncate_name(IsoImage *image, const char *name, char **namept,
1121                             int flag)
1122 {
1123     int ret;
1124 
1125     if (name == NULL)
1126         return ISO_NULL_POINTER;
1127 
1128     if ((int) strlen(name) <= image->truncate_length) {
1129         *namept = (char *) name;
1130         return ISO_SUCCESS;
1131     }
1132     *namept = image->truncate_buffer;
1133     if (name != image->truncate_buffer)
1134         strncpy(image->truncate_buffer, name, 4095);
1135     image->truncate_buffer[4095] = 0;
1136     ret = iso_truncate_rr_name(image->truncate_mode, image->truncate_length,
1137                                image->truncate_buffer, 0);
1138     return ret;
1139 }
1140 
1141 
1142 /* API */
iso_image_was_blind_attrs(IsoImage * image,int flag)1143 int iso_image_was_blind_attrs(IsoImage *image, int flag)
1144 {
1145     int ret;
1146 
1147     if (image == NULL)
1148         return ISO_NULL_POINTER;
1149     ret = image->blind_on_local_get_attrs;
1150     if (flag & 1)
1151         image->blind_on_local_get_attrs = 0;
1152     return ret;
1153 }
1154 
1155 
1156 /*
1157  * @param flag bit0= recursion is active
1158  */
1159 static
iso_dir_zisofs_discard_bpt(IsoDir * dir,int flag)1160 int iso_dir_zisofs_discard_bpt(IsoDir *dir, int flag)
1161 {
1162     int ret;
1163     IsoDirIter *iter = NULL;
1164     IsoNode *node;
1165     IsoDir *subdir;
1166     IsoFile *file;
1167     IsoStream *stream;
1168 
1169     ret = iso_dir_get_children(dir, &iter);
1170     if (ret < 0)
1171         return ret;
1172     while (iso_dir_iter_next(iter, &node) == 1) {
1173         if (iso_node_get_type(node) == LIBISO_DIR) {
1174             subdir = (IsoDir *) node;
1175             ret = iso_dir_zisofs_discard_bpt(subdir, flag | 1);
1176             if (ret < 0)
1177                 goto ex;
1178     continue;
1179         }
1180         if (iso_node_get_type(node) != LIBISO_FILE)
1181     continue;
1182         file = (IsoFile *) node;
1183         stream = iso_file_get_stream(file);
1184         if (stream == NULL)
1185     continue;
1186         ret = iso_stream_zisofs_discard_bpt(stream, 0);
1187         if (ret < 0)
1188             goto ex;
1189     }
1190     ret = ISO_SUCCESS;
1191 ex:;
1192     if (iter != NULL)
1193         iso_dir_iter_free(iter);
1194     return ret;
1195 }
1196 
1197 
1198 /* API */
iso_image_zisofs_discard_bpt(IsoImage * image,int flag)1199 int iso_image_zisofs_discard_bpt(IsoImage *image, int flag)
1200 {
1201     int ret;
1202     IsoDir *dir;
1203 
1204     if (image == NULL)
1205         return ISO_NULL_POINTER;
1206     dir = image->root;
1207     if (dir == NULL)
1208         return ISO_SUCCESS;
1209     ret = iso_dir_zisofs_discard_bpt(dir, 0);
1210     return ret;
1211 }
1212 
1213