xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

iso1999.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2011-2014 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 "iso1999.h"
16 #include "messages.h"
17 #include "writer.h"
18 #include "image.h"
19 #include "filesrc.h"
20 #include "eltorito.h"
21 #include "util.h"
22 #include "ecma119.h"
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 static
29 int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
30 {
31  int ret;
32  char *name;
33 
34  if (fname == NULL) {
35  return ISO_ASSERT_FAILURE;
36  }
37 
38  if (str == NULL) {
39  /* not an error, can be root node */
40  *fname = NULL;
41  return ISO_SUCCESS;
42  }
43 
44  if (!strcmp(t->input_charset, t->output_charset)) {
45  /* no conversion needed */
46  name = strdup(str);
47  } else {
48  ret = strconv(str, t->input_charset, t->output_charset, &name);
49  if (ret < 0) {
51  "Charset conversion error. Can't convert %s from %s to %s",
52  str, t->input_charset, t->output_charset);
53  if (ret < 0) {
54  return ret; /* aborted */
55  }
56 
57  /* use the original name, it's the best we can do */
58  name = strdup(str);
59  }
60  }
61 
62  /* ISO 9660:1999 7.5.1 */
63  if (strlen(name) > 207) {
64  name[207] = '\0';
65  }
66 
67  *fname = name;
68 
69  return ISO_SUCCESS;
70 }
71 
72 static
74 {
75  if (node == NULL) {
76  return;
77  }
78  if (node->type == ISO1999_DIR) {
79  size_t i;
80  for (i = 0; i < node->info.dir->nchildren; i++) {
82  }
83  if (node->info.dir->children != NULL)
84  free(node->info.dir->children);
85  free(node->info.dir);
86  }
87  iso_node_unref(node->node);
88  free(node->name);
89  free(node);
90 }
91 
92 /**
93  * Create a low level ISO 9660:1999 node
94  * @return
95  * 1 success, 0 ignored, < 0 error
96  */
97 static
99 {
100  int ret;
101  Iso1999Node *n;
102 
103  n = calloc(1, sizeof(Iso1999Node));
104  if (n == NULL) {
105  return ISO_OUT_OF_MEM;
106  }
107 
108  if (iso->type == LIBISO_DIR) {
109  IsoDir *dir = (IsoDir*) iso;
110  n->info.dir = calloc(1, sizeof(struct iso1999_dir_info));
111  if (n->info.dir == NULL) {
112  free(n);
113  return ISO_OUT_OF_MEM;
114  }
115  n->info.dir->children = NULL;
116  if (dir->nchildren > 0) {
117  n->info.dir->children = calloc(sizeof(void*), dir->nchildren);
118  if (n->info.dir->children == NULL) {
119  free(n->info.dir);
120  free(n);
121  return ISO_OUT_OF_MEM;
122  }
123  }
124  n->type = ISO1999_DIR;
125  } else if (iso->type == LIBISO_FILE) {
126  /* it's a file */
127  off_t size;
128  IsoFileSrc *src;
129  IsoFile *file = (IsoFile*) iso;
130 
131  size = iso_stream_get_size(file->stream);
132  if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->opts->iso_level != 3) {
133  char *ipath = iso_tree_get_node_path(iso);
134  ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
135  "File \"%s\" can't be added to image because is "
136  "greater than 4GB", ipath);
137  free(n);
138  free(ipath);
139  return ret;
140  }
141 
142  ret = iso_file_src_create(t, file, &src);
143  if (ret < 0) {
144  free(n);
145  return ret;
146  }
147  n->info.file = src;
148  n->type = ISO1999_FILE;
149  } else if (iso->type == LIBISO_BOOT) {
150  /* it's a el-torito boot catalog, that we write as a file */
151  IsoFileSrc *src;
152 
153  ret = el_torito_catalog_file_src_create(t, &src);
154  if (ret < 0) {
155  free(n);
156  return ret;
157  }
158  n->info.file = src;
159  n->type = ISO1999_FILE;
160  } else {
161  /* should never happen */
162  free(n);
163  return ISO_ASSERT_FAILURE;
164  }
165 
166  /* take a ref to the IsoNode */
167  n->node = iso;
168  iso_node_ref(iso);
169 
170  *node = n;
171  return ISO_SUCCESS;
172 }
173 
174 /**
175  * Create the low level ISO 9660:1999 tree from the high level ISO tree.
176  *
177  * @return
178  * 1 success, 0 file ignored, < 0 error
179  */
180 static
181 int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
182 {
183  int ret, max_path;
184  Iso1999Node *node = NULL;
185  char *iso_name = NULL;
186 
187  if (t == NULL || iso == NULL || tree == NULL) {
188  return ISO_NULL_POINTER;
189  }
190 
191  if (iso->hidden & LIBISO_HIDE_ON_1999) {
192  /* file will be ignored */
193  return 0;
194  }
195  ret = get_iso1999_name(t, iso->name, &iso_name);
196  if (ret < 0) {
197  return ret;
198  }
199 
200  max_path = pathlen + 1 + (iso_name ? strlen(iso_name): 0);
201  if (!t->opts->allow_longer_paths && max_path > 255) {
202  char *ipath = iso_tree_get_node_path(iso);
204  "File \"%s\" can't be added to ISO 9660:1999 tree, "
205  "because its path length is larger than 255", ipath);
206  free(iso_name);
207  free(ipath);
208  return ret;
209  }
210 
211  switch (iso->type) {
212  case LIBISO_FILE:
213  ret = create_node(t, iso, &node);
214  break;
215  case LIBISO_DIR:
216  {
217  IsoNode *pos;
218  IsoDir *dir = (IsoDir*)iso;
219  ret = create_node(t, iso, &node);
220  if (ret < 0) {
221  free(iso_name);
222  return ret;
223  }
224  pos = dir->children;
225  while (pos) {
226  int cret;
227  Iso1999Node *child;
228  cret = create_tree(t, pos, &child, max_path);
229  if (cret < 0) {
230  /* error */
231  iso1999_node_free(node);
232  ret = cret;
233  break;
234  } else if (cret == ISO_SUCCESS) {
235  /* add child to this node */
236  int nchildren = node->info.dir->nchildren++;
237  node->info.dir->children[nchildren] = child;
238  child->parent = node;
239  }
240  pos = pos->next;
241  }
242  }
243  break;
244  case LIBISO_BOOT:
245  if (t->eltorito) {
246  ret = create_node(t, iso, &node);
247  } else {
248  /* log and ignore */
249  ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
250  "El-Torito catalog found on a image without El-Torito.");
251  }
252  break;
253  case LIBISO_SYMLINK:
254  case LIBISO_SPECIAL:
255  {
256  char *ipath = iso_tree_get_node_path(iso);
257  ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
258  "Can't add %s to ISO 9660:1999 tree. This kind of files "
259  "can only be added to a Rock Ridget tree. Skipping.",
260  ipath);
261  free(ipath);
262  }
263  break;
264  default:
265  /* should never happen */
266  return ISO_ASSERT_FAILURE;
267  }
268  if (ret <= 0) {
269  free(iso_name);
270  return ret;
271  }
272  node->name = iso_name;
273  *tree = node;
274  return ISO_SUCCESS;
275 }
276 
277 static int
278 cmp_node(const void *f1, const void *f2)
279 {
280  Iso1999Node *f = *((Iso1999Node**)f1);
281  Iso1999Node *g = *((Iso1999Node**)f2);
282 
283  /**
284  * TODO #00027 Follow ISO 9660:1999 specs when sorting files
285  * strcmp do not does exactly what ISO 9660:1999, 9.3, as characters
286  * < 0x20 " " are allowed, so name len must be taken into account
287  */
288  return strcmp(f->name, g->name);
289 }
290 
291 /**
292  * Sort the entries inside an ISO 9660:1999 directory, according to
293  * ISO 9660:1999, 9.3
294  */
295 static
297 {
298  size_t i;
299 
300  if (root->info.dir->children == NULL)
301  return;
302  qsort(root->info.dir->children, root->info.dir->nchildren,
303  sizeof(void*), cmp_node);
304  for (i = 0; i < root->info.dir->nchildren; i++) {
305  Iso1999Node *child = root->info.dir->children[i];
306  if (child->type == ISO1999_DIR)
307  sort_tree(child);
308  }
309 }
310 
311 static
313 {
314  int ret;
315  int i, nchildren;
316  Iso1999Node **children;
317  IsoHTable *table = NULL;
318  int need_sort = 0;
319  char *full_name = NULL, *tmp = NULL;
320 
321  nchildren = dir->info.dir->nchildren;
322  if (nchildren <= 0) {
323  ret = ISO_SUCCESS;
324  goto ex;
325  }
326  children = dir->info.dir->children;
327  LIBISO_ALLOC_MEM(full_name, char, 208);
328  LIBISO_ALLOC_MEM(tmp, char, 208);
329 
330  /* a hash table will temporary hold the names, for fast searching */
331  ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
332  (compare_function_t)strcmp, &table);
333  if (ret < 0) {
334  goto ex;
335  }
336  for (i = 0; i < nchildren; ++i) {
337  char *name = children[i]->name;
338  ret = iso_htable_add(table, name, name);
339  if (ret < 0) {
340  goto ex;
341  }
342  }
343 
344  for (i = 0; i < nchildren; ++i) {
345  char *name, *ext;
346  int max; /* computed max len for name, without extension */
347  int j = i;
348  int digits = 1; /* characters to change per name */
349 
350  /* first, find all child with same name */
351  while (j + 1 < nchildren &&
352  !cmp_node(children + i, children + j + 1)) {
353  ++j;
354  }
355  if (j == i) {
356  /* name is unique */
357  continue;
358  }
359 
360  /*
361  * A max of 7 characters is good enough, it allows handling up to
362  * 9,999,999 files with same name.
363  */
364  while (digits < 8) {
365  int ok, k;
366  char *dot;
367  int change = 0; /* number to be written */
368 
369  /* copy name to buffer */
370  strcpy(full_name, children[i]->name);
371 
372  /* compute name and extension */
373  dot = strrchr(full_name, '.');
374  if (dot != NULL && children[i]->type != ISO1999_DIR) {
375 
376  /*
377  * File (not dir) with extension.
378  */
379  int extlen;
380  full_name[dot - full_name] = '\0';
381  name = full_name;
382  ext = dot + 1;
383 
384  extlen = strlen(ext);
385  max = 207 - extlen - 1 - digits;
386  if (max <= 0) {
387  /* this can happen if extension is too long */
388  if (extlen + max > 3) {
389  /*
390  * reduce extension len, to give name an extra char
391  * note that max is negative or 0
392  */
393  extlen = extlen + max - 1;
394  ext[extlen] = '\0';
395  max = 207 - extlen - 1 - digits;
396  } else {
397  /*
398  * error, we don't support extensions < 3
399  * This can't happen with current limit of digits.
400  */
401  ret = ISO_ERROR;
402  goto ex;
403  }
404  }
405  /* ok, reduce name by digits */
406  if (name + max < dot) {
407  name[max] = '\0';
408  }
409  } else {
410  /* Directory, or file without extension */
411  if (children[i]->type == ISO1999_DIR) {
412  dot = NULL; /* dots have no meaning in dirs */
413  }
414  max = 207 - digits;
415  name = full_name;
416  if ((size_t) max < strlen(name)) {
417  name[max] = '\0';
418  }
419  /* let ext be an empty string */
420  ext = name + strlen(name);
421  }
422 
423  ok = 1;
424  /* change name of each file */
425  for (k = i; k <= j; ++k) {
426  char fmt[16];
427  if (dot != NULL) {
428  sprintf(fmt, "%%s%%0%dd.%%s", digits);
429  } else {
430  sprintf(fmt, "%%s%%0%dd%%s", digits);
431  }
432  while (1) {
433  sprintf(tmp, fmt, name, change, ext);
434  ++change;
435  if (change > int_pow(10, digits)) {
436  ok = 0;
437  break;
438  }
439  if (!iso_htable_get(table, tmp, NULL)) {
440  /* the name is unique, so it can be used */
441  break;
442  }
443  }
444  if (ok) {
445  char *new = strdup(tmp);
446  if (new == NULL) {
447  ret = ISO_OUT_OF_MEM;
448  goto ex;
449  }
450  iso_msg_debug(img->image->id, "\"%s\" renamed to \"%s\"",
451  children[k]->name, new);
452 
453  iso_htable_remove_ptr(table, children[k]->name, NULL);
454  free(children[k]->name);
455  children[k]->name = new;
456  iso_htable_add(table, new, new);
457 
458  /*
459  * if we change a name we need to sort again children
460  * at the end
461  */
462  need_sort = 1;
463  } else {
464  /* we need to increment digits */
465  break;
466  }
467  }
468  if (ok) {
469  break;
470  } else {
471  ++digits;
472  }
473  }
474  if (digits == 8) {
476  goto ex;
477  }
478  i = j;
479  }
480 
481  /*
482  * If needed, sort again the files inside dir
483  */
484  if (need_sort) {
485  qsort(children, nchildren, sizeof(void*), cmp_node);
486  }
487 
488  ret = ISO_SUCCESS;
489 
490 ex:;
491  iso_htable_destroy(table, NULL);
492  LIBISO_FREE_MEM(tmp);
493  LIBISO_FREE_MEM(full_name);
494  return ret;
495 }
496 
497 static
499 {
500  int ret;
501  size_t i;
502 
503  ret = mangle_single_dir(t, dir);
504  if (ret < 0) {
505  return ret;
506  }
507 
508  /* recurse */
509  for (i = 0; i < dir->info.dir->nchildren; ++i) {
510  if (dir->info.dir->children[i]->type == ISO1999_DIR) {
511  ret = mangle_tree(t, dir->info.dir->children[i]);
512  if (ret < 0) {
513  /* error */
514  return ret;
515  }
516  }
517  }
518  return ISO_SUCCESS;
519 }
520 
521 static
523 {
524  int ret;
525  Iso1999Node *root;
526 
527  if (t == NULL) {
528  return ISO_NULL_POINTER;
529  }
530 
531  ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
532  if (ret <= 0) {
533  if (ret == 0) {
534  /* unexpected error, root ignored!! This can't happen */
535  ret = ISO_ASSERT_FAILURE;
536  }
537  return ret;
538  }
539 
540  /* the ISO 9660:1999 tree is stored in Ecma119Image target */
541  t->iso1999_root = root;
542 
543  iso_msg_debug(t->image->id, "Sorting the ISO 9660:1999 tree...");
544  sort_tree(root);
545 
546  iso_msg_debug(t->image->id, "Mangling ISO 9660:1999 names...");
547  ret = mangle_tree(t, t->iso1999_root);
548  if (ret < 0) {
549  return ret;
550  }
551 
552  return ISO_SUCCESS;
553 }
554 
555 /**
556  * Compute the size of a directory entry for a single node
557  */
558 static
560 {
561  int ret = n->name ? strlen(n->name) + 33 : 34;
562  if (ret % 2)
563  ret++;
564  return ret;
565 }
566 
567 /**
568  * Computes the total size of all directory entries of a single dir, as
569  * stated in ISO 9660:1999, 6.8.1.3
570  */
571 static
573 {
574  size_t i, len;
575 
576  /* size of "." and ".." entries */
577  len = 34 + 34;
578 
579  for (i = 0; i < dir->info.dir->nchildren; ++i) {
580  size_t remaining;
581  int section, nsections;
582  Iso1999Node *child = dir->info.dir->children[i];
583  size_t dirent_len = calc_dirent_len(t, child);
584 
585  nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
586  for (section = 0; section < nsections; ++section) {
587  remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
588  if (dirent_len > remaining) {
589  /* child directory entry doesn't fit on block */
590  len += remaining + dirent_len;
591  } else {
592  len += dirent_len;
593  }
594  }
595  }
596 
597  /*
598  * The size of a dir is always a multiple of block size, as we must add
599  * the size of the unused space after the last directory record
600  * (ISO 9660:1999, 6.8.1.3)
601  */
602  len = ROUND_UP(len, BLOCK_SIZE);
603 
604  /* cache the len */
605  dir->info.dir->len = len;
606  return len;
607 }
608 
609 static
611 {
612  size_t i, len;
613 
614  t->iso1999_ndirs++;
615  dir->info.dir->block = t->curblock;
616  len = calc_dir_size(t, dir);
617  t->curblock += DIV_UP(len, BLOCK_SIZE);
618  for (i = 0; i < dir->info.dir->nchildren; i++) {
619  Iso1999Node *child = dir->info.dir->children[i];
620  if (child->type == ISO1999_DIR) {
621  calc_dir_pos(t, child);
622  }
623  }
624 }
625 
626 /**
627  * Compute the length of the path table (ISO 9660:1999, 6.9), in bytes.
628  */
629 static
631 {
632  uint32_t size;
633  size_t i;
634 
635  /* size of path table for this entry */
636  size = 8;
637  size += dir->name ? strlen(dir->name) : 2;
638  size += (size % 2);
639 
640  /* and recurse */
641  for (i = 0; i < dir->info.dir->nchildren; i++) {
642  Iso1999Node *child = dir->info.dir->children[i];
643  if (child->type == ISO1999_DIR) {
644  size += calc_path_table_size(child);
645  }
646  }
647  return size;
648 }
649 
650 static
652 {
653  Ecma119Image *t;
654  uint32_t path_table_size;
655 
656  if (writer == NULL) {
657  return ISO_OUT_OF_MEM;
658  }
659 
660  t = writer->target;
661 
662  /* compute position of directories */
663  iso_msg_debug(t->image->id,
664  "Computing position of ISO 9660:1999 dir structure");
665  t->iso1999_ndirs = 0;
666  calc_dir_pos(t, t->iso1999_root);
667 
668  /* compute length of pathlist */
669  iso_msg_debug(t->image->id, "Computing length of ISO 9660:1999 pathlist");
670  path_table_size = calc_path_table_size(t->iso1999_root);
671 
672  /* compute location for path tables */
674  t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
676  t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
677  t->iso1999_path_table_size = path_table_size;
678 
679  return ISO_SUCCESS;
680 }
681 
682 /**
683  * Write a single directory record (ISO 9660:1999, 9.1).
684  *
685  * @param file_id
686  * if >= 0, we use it instead of the filename (for "." and ".." entries).
687  * @param len_fi
688  * Computed length of the file identifier.
689  */
690 static
691 void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
692  uint8_t *buf, size_t len_fi, int extent)
693 {
694  uint32_t len;
695  uint32_t block;
696  uint8_t len_dr; /*< size of dir entry */
697  int multi_extend = 0;
698  uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
699  : (uint8_t*)node->name;
700 
701  struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
702  IsoNode *iso;
703 
704  len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
705 
706  memcpy(rec->file_id, name, len_fi);
707 
708  if (node->type == ISO1999_DIR) {
709  /* use the cached length */
710  len = node->info.dir->len;
711  block = node->info.dir->block;
712  } else if (node->type == ISO1999_FILE) {
713  block = node->info.file->sections[extent].block;
714  len = node->info.file->sections[extent].size;
715  multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
716  } else {
717  /*
718  * for nodes other than files and dirs, we set both
719  * len and block to 0
720  */
721  len = 0;
722  block = 0;
723  }
724 
725  /*
726  * For ".." entry we need to write the parent info!
727  */
728  if (file_id == 1 && node->parent)
729  node = node->parent;
730 
731  rec->len_dr[0] = len_dr;
732  iso_bb(rec->block, block, 4);
733  iso_bb(rec->length, len, 4);
734 
735  /* was: iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
736  */
737  iso= node->node;
738  iso_datetime_7(rec->recording_time,
739  (t->opts->dir_rec_mtime & 4) ? ( t->replace_timestamps ?
740  t->timestamp : iso->mtime )
741  : t->now, t->opts->always_gmt);
742 
743  rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
744  iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
745  rec->len_fi[0] = len_fi;
746 }
747 
748 /**
749  * Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
750  */
751 static
753 {
754  IsoImage *image;
755  Ecma119Image *t;
756 
757  /* The enhanced volume descriptor is like the sup vol desc */
758  struct ecma119_sup_vol_desc vol;
759 
760  char *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
761  char *volset_id = NULL, *system_id = NULL, *application_id = NULL;
762  char *copyright_file_id = NULL, *abstract_file_id = NULL;
763  char *biblio_file_id = NULL;
764 
765  if (writer == NULL) {
766  return ISO_OUT_OF_MEM;
767  }
768 
769  t = writer->target;
770  image = t->image;
771 
772  iso_msg_debug(image->id, "Write Enhanced Vol Desc (ISO 9660:1999)");
773 
774  memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
775 
776  get_iso1999_name(t, image->volume_id, &vol_id);
777  str2a_char(t->input_charset, image->publisher_id, &pub_id);
778  str2a_char(t->input_charset, image->data_preparer_id, &data_id);
779  get_iso1999_name(t, image->volset_id, &volset_id);
780 
785  get_iso1999_name(t, image->biblio_file_id, &biblio_file_id);
786 
787  vol.vol_desc_type[0] = 2;
788  memcpy(vol.std_identifier, "CD001", 5);
789 
790  /* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
791  vol.vol_desc_version[0] = 2;
792  strncpy_pad((char*)vol.volume_id, vol_id, 32);
793 
795  iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
796  iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
797  iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
801 
803 
804  strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
805  strncpy_pad((char*)vol.publisher_id, pub_id, 128);
806  strncpy_pad((char*)vol.data_prep_id, data_id, 128);
807 
808  strncpy_pad((char*)vol.system_id, system_id, 32);
809 
810  strncpy_pad((char*)vol.application_id, application_id, 128);
813  strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
814 
815  ecma119_set_voldescr_times(writer, (struct ecma119_pri_vol_desc *) &vol);
816  vol.file_structure_version[0] = 2;
817 
818  free(vol_id);
819  free(volset_id);
820  free(pub_id);
821  free(data_id);
822  free(system_id);
823  free(application_id);
824  free(copyright_file_id);
825  free(abstract_file_id);
826  free(biblio_file_id);
827 
828  /* Finally write the Volume Descriptor */
829  return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
830 }
831 
832 static
834 {
835  int ret;
836  uint8_t *buffer = NULL;
837  size_t i;
838  size_t fi_len, len;
839 
840  /* buf will point to current write position on buffer */
841  uint8_t *buf;
842 
844  buf = buffer;
845 
846  /* write the "." and ".." entries first */
847  write_one_dir_record(t, dir, 0, buf, 1, 0);
848  buf += 34;
849  write_one_dir_record(t, dir, 1, buf, 1, 0);
850  buf += 34;
851 
852  for (i = 0; i < dir->info.dir->nchildren; i++) {
853  int section, nsections;
854  Iso1999Node *child = dir->info.dir->children[i];
855 
856  /* compute len of directory entry */
857  fi_len = strlen(child->name);
858  len = fi_len + 33 + ((fi_len % 2) ? 0 : 1);
859 
860  nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
861  for (section = 0; section < nsections; ++section) {
862  if ( (buf + len - buffer) > BLOCK_SIZE) {
863  /* dir doesn't fit in current block */
864  ret = iso_write(t, buffer, BLOCK_SIZE);
865  if (ret < 0) {
866  goto ex;
867  }
868  memset(buffer, 0, BLOCK_SIZE);
869  buf = buffer;
870  }
871  /* write the directory entry in any case */
872  write_one_dir_record(t, child, -1, buf, fi_len, section);
873  buf += len;
874  }
875  }
876 
877  /* write the last block */
878  ret = iso_write(t, buffer, BLOCK_SIZE);
879 ex:;
881  return ret;
882 }
883 
884 static
886 {
887  int ret;
888  size_t i;
889 
890  /* write all directory entries for this dir */
891  ret = write_one_dir(t, root);
892  if (ret < 0) {
893  return ret;
894  }
895 
896  /* recurse */
897  for (i = 0; i < root->info.dir->nchildren; i++) {
898  Iso1999Node *child = root->info.dir->children[i];
899  if (child->type == ISO1999_DIR) {
900  ret = write_dirs(t, child);
901  if (ret < 0) {
902  return ret;
903  }
904  }
905  }
906  return ISO_SUCCESS;
907 }
908 
909 static
910 int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
911 {
912  size_t i, len;
913  uint8_t *buf = NULL;
914  struct ecma119_path_table_record *rec;
915  void (*write_int)(uint8_t*, uint32_t, int);
916  Iso1999Node *dir;
917  uint32_t path_table_size;
918  int parent = 0;
919  int ret= ISO_SUCCESS;
920  uint8_t *zeros = NULL;
921 
922  /* 256 is just a convenient size large enough */
923  LIBISO_ALLOC_MEM(buf, uint8_t, 256);
924 
925  path_table_size = 0;
926  write_int = l_type ? iso_lsb : iso_msb;
927 
928  for (i = 0; i < t->iso1999_ndirs; i++) {
929  dir = pathlist[i];
930 
931  /* find the index of the parent in the table */
932  while ((i) && pathlist[parent] != dir->parent) {
933  parent++;
934  }
935 
936  /* write the Path Table Record (ECMA-119, 9.4) */
937  memset(buf, 0, 256);
938  rec = (struct ecma119_path_table_record*) buf;
939  rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
940  rec->len_xa[0] = 0;
941  write_int(rec->block, dir->info.dir->block, 4);
942  write_int(rec->parent, parent + 1, 2);
943  if (dir->parent) {
944  memcpy(rec->dir_id, dir->name, rec->len_di[0]);
945  }
946  len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
947  ret = iso_write(t, buf, len);
948  if (ret < 0) {
949  /* error */
950  goto ex;
951  }
952  path_table_size += len;
953  }
954 
955  /* we need to fill the last block with zeros */
956  path_table_size %= BLOCK_SIZE;
957  if (path_table_size) {
958  LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
959  len = BLOCK_SIZE - path_table_size;
960  memset(zeros, 0, len);
961  ret = iso_write(t, zeros, len);
962  }
963 ex:;
964  LIBISO_FREE_MEM(zeros);
965  LIBISO_FREE_MEM(buf);
966  return ret;
967 }
968 
969 static
971 {
972  int ret;
973  size_t i, j, cur;
974  Iso1999Node **pathlist;
975 
976  iso_msg_debug(t->image->id, "Writing ISO 9660:1999 Path tables");
977 
978  /* allocate temporal pathlist */
979  pathlist = malloc(sizeof(void*) * t->iso1999_ndirs);
980  if (pathlist == NULL) {
981  return ISO_OUT_OF_MEM;
982  }
983  pathlist[0] = t->iso1999_root;
984  cur = 1;
985 
986  for (i = 0; i < t->iso1999_ndirs; i++) {
987  Iso1999Node *dir = pathlist[i];
988  for (j = 0; j < dir->info.dir->nchildren; j++) {
989  Iso1999Node *child = dir->info.dir->children[j];
990  if (child->type == ISO1999_DIR) {
991  pathlist[cur++] = child;
992  }
993  }
994  }
995 
996  /* Write L Path Table */
997  ret = write_path_table(t, pathlist, 1);
998  if (ret < 0) {
999  goto write_path_tables_exit;
1000  }
1001 
1002  /* Write L Path Table */
1003  ret = write_path_table(t, pathlist, 0);
1004 
1005  write_path_tables_exit: ;
1006  free(pathlist);
1007  return ret;
1008 }
1009 
1010 static
1012 {
1013  int ret;
1014  Ecma119Image *t;
1015 
1016  if (writer == NULL) {
1017  return ISO_NULL_POINTER;
1018  }
1019  t = writer->target;
1020 
1021  /* first of all, we write the directory structure */
1022  ret = write_dirs(t, t->iso1999_root);
1023  if (ret < 0) {
1024  return ret;
1025  }
1026 
1027  /* and write the path tables */
1028  ret = write_path_tables(t);
1029 
1030  return ret;
1031 }
1032 
1033 static
1035 {
1036  /* free the ISO 9660:1999 tree */
1037  Ecma119Image *t = writer->target;
1039  return ISO_SUCCESS;
1040 }
1041 
1043 {
1044  int ret;
1045  IsoImageWriter *writer;
1046 
1047  writer = malloc(sizeof(IsoImageWriter));
1048  if (writer == NULL) {
1049  return ISO_OUT_OF_MEM;
1050  }
1051 
1056  writer->data = NULL;
1057  writer->target = target;
1058 
1059  iso_msg_debug(target->image->id,
1060  "Creating low level ISO 9660:1999 tree...");
1061  ret = iso1999_tree_create(target);
1062  if (ret < 0) {
1063  free((char *) writer);
1064  return ret;
1065  }
1066 
1067  /* add this writer to image */
1068  target->writers[target->nwriters++] = writer;
1069 
1070  /* we need the volume descriptor */
1071  target->curblock++;
1072  return ISO_SUCCESS;
1073 }
#define BLOCK_SIZE
Definition: buffer.h:23
int iso_write(Ecma119Image *target, void *buf, size_t count)
Definition: ecma119.c:3471
void ecma119_set_voldescr_times(IsoImageWriter *writer, struct ecma119_pri_vol_desc *vol)
Definition: ecma119.c:475
#define MAX_ISO_FILE_SECTION_SIZE
Definition: ecma119.h:33
int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
Definition: eltorito.c:1199
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
Definition: filesrc.c:69
static int mangle_tree(Ecma119Image *t, Iso1999Node *dir)
Definition: iso1999.c:498
static int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
Definition: iso1999.c:752
int iso1999_writer_create(Ecma119Image *target)
Definition: iso1999.c:1042
static int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
Definition: iso1999.c:29
static int iso1999_writer_write_data(IsoImageWriter *writer)
Definition: iso1999.c:1011
static int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
Definition: iso1999.c:98
static int iso1999_writer_free_data(IsoImageWriter *writer)
Definition: iso1999.c:1034
static int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
Definition: iso1999.c:181
static void sort_tree(Iso1999Node *root)
Definition: iso1999.c:296
static uint32_t calc_path_table_size(Iso1999Node *dir)
Definition: iso1999.c:630
static void iso1999_node_free(Iso1999Node *node)
Definition: iso1999.c:73
static int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
Definition: iso1999.c:833
static size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
Definition: iso1999.c:572
static int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
Definition: iso1999.c:312
static void calc_dir_pos(Ecma119Image *t, Iso1999Node *dir)
Definition: iso1999.c:610
static int iso1999_tree_create(Ecma119Image *t)
Definition: iso1999.c:522
static int write_path_tables(Ecma119Image *t)
Definition: iso1999.c:970
static int write_dirs(Ecma119Image *t, Iso1999Node *root)
Definition: iso1999.c:885
static int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
Definition: iso1999.c:910
static void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id, uint8_t *buf, size_t len_fi, int extent)
Definition: iso1999.c:691
static int cmp_node(const void *f1, const void *f2)
Definition: iso1999.c:278
static size_t calc_dirent_len(Ecma119Image *t, Iso1999Node *n)
Definition: iso1999.c:559
static int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
Definition: iso1999.c:651
@ ISO1999_DIR
Definition: iso1999.h:26
@ ISO1999_FILE
Definition: iso1999.h:25
void iso_datetime_7(unsigned char *buf, time_t t, int always_gmt)
Definition: util.c:1574
void iso_bb(uint8_t *buf, uint32_t num, int bytes)
Definition: util.c:1502
void iso_msb(uint8_t *buf, uint32_t num, int bytes)
Definition: util.c:1494
void strncpy_pad(char *dest, const char *src, size_t max)
Definition: util.c:1947
int int_pow(int base, int power)
Definition: util.c:159
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
Definition: util.c:1478
int str2a_char(const char *icharset, const char *input, char **output)
Definition: util.c:1444
int strconv(const char *str, const char *icharset, const char *ocharset, char **output)
Definition: util.c:192
int iso_htable_remove_ptr(IsoHTable *table, void *key, hfree_data_t free_data)
Definition: util_htable.c:236
int iso_htable_add(IsoHTable *table, void *key, void *data)
Definition: util_htable.c:70
int(* compare_function_t)(const void *a, const void *b)
Definition: util.h:343
int iso_htable_create(size_t size, hash_funtion_t hash, compare_function_t compare, IsoHTable **table)
Definition: util_htable.c:321
#define LIBISO_FREE_MEM(pt)
Definition: util.h:627
#define ROUND_UP(n, mul)
Definition: util.h:39
void iso_htable_destroy(IsoHTable *table, hfree_data_t free_data)
Definition: util_htable.c:290
#define DIV_UP(n, div)
Definition: util.h:38
unsigned int iso_str_hash(const void *key)
Definition: util_htable.c:270
#define LIBISO_ALLOC_MEM(pt, typ, count)
Definition: util.h:615
int iso_htable_get(IsoHTable *table, void *key, void **data)
Definition: util_htable.c:144
void iso_node_unref(IsoNode *node)
Definition: node.c:56
#define ISO_SUCCESS
Definition: libisofs.h:8719
@ LIBISO_BOOT
Definition: libisofs.h:233
@ LIBISO_DIR
Definition: libisofs.h:229
@ LIBISO_FILE
Definition: libisofs.h:230
@ LIBISO_SYMLINK
Definition: libisofs.h:231
@ LIBISO_SPECIAL
Definition: libisofs.h:232
#define ISO_OUT_OF_MEM
Definition: libisofs.h:8745
char * iso_tree_get_node_path(IsoNode *node)
Definition: tree.c:1247
off_t iso_stream_get_size(IsoStream *stream)
Definition: stream.c:810
#define ISO_FILE_IMGPATH_WRONG
Definition: libisofs.h:8852
#define ISO_FILE_TOO_BIG
Definition: libisofs.h:8835
#define ISO_FILE_IGNORED
Definition: libisofs.h:8832
void iso_node_ref(IsoNode *node)
Definition: node.c:46
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
@ LIBISO_HIDE_ON_1999
Definition: libisofs.h:306
#define ISO_ERROR
Definition: libisofs.h:8734
#define ISO_FILENAME_WRONG_CHARSET
Definition: libisofs.h:8841
#define ISO_MANGLE_TOO_MUCH_FILES
Definition: libisofs.h:8868
#define ISO_ASSERT_FAILURE
Definition: libisofs.h:8737
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt,...)
Definition: messages.c:579
void iso_msg_debug(int imgid, const char *fmt,...)
Definition: messages.c:253
Definition: node.h:140
IsoNode * children
Definition: node.h:144
size_t nchildren
Definition: node.h:143
struct iso_file_section * sections
Definition: filesrc.h:56
int nsections
Definition: filesrc.h:57
Definition: node.h:149
IsoStream * stream
Definition: node.h:166
Ecma119Image * target
Definition: writer.h:28
int(* write_data)(IsoImageWriter *writer)
Definition: writer.h:23
void * data
Definition: writer.h:27
int(* compute_data_blocks)(IsoImageWriter *writer)
Definition: writer.h:19
int(* write_vol_desc)(IsoImageWriter *writer)
Definition: writer.h:21
int(* free_data)(IsoImageWriter *writer)
Definition: writer.h:25
int id
Definition: image.h:97
char * abstract_file_id
Definition: image.h:53
char * data_preparer_id
Definition: image.h:49
char * volume_id
Definition: image.h:47
char * volset_id
Definition: image.h:45
char * publisher_id
Definition: image.h:48
char * application_id
Definition: image.h:51
IsoDir * root
Definition: image.h:43
char * biblio_file_id
Definition: image.h:54
char * system_id
Definition: image.h:50
char * copyright_file_id
Definition: image.h:52
Definition: node.h:100
char * name
Definition: node.h:113
enum IsoNodeType type
Definition: node.h:111
int hidden
Definition: node.h:124
IsoNode * next
Definition: node.h:131
time_t mtime
Definition: node.h:121
size_t iso1999_ndirs
Definition: ecma119.h:677
uint32_t vol_space_size
Definition: ecma119.h:602
IsoImage * image
Definition: ecma119.h:560
time_t now
Definition: ecma119.h:594
unsigned int eltorito
Definition: ecma119.h:566
IsoWriteOpts * opts
Definition: ecma119.h:563
unsigned int replace_timestamps
Definition: ecma119.h:581
uint32_t iso1999_m_path_table_pos
Definition: ecma119.h:680
char * output_charset
Definition: ecma119.h:592
char * input_charset
Definition: ecma119.h:591
uint32_t iso1999_l_path_table_pos
Definition: ecma119.h:679
Iso1999Node * iso1999_root
Definition: ecma119.h:676
uint32_t iso1999_path_table_size
Definition: ecma119.h:678
IsoImageWriter ** writers
Definition: ecma119.h:753
size_t nwriters
Definition: ecma119.h:752
uint32_t curblock
Definition: ecma119.h:618
time_t timestamp
Definition: ecma119.h:588
uint8_t len_di[(1) -(1)+1]
Definition: ecma119.h:1029
uint8_t dir_id[(9) -(9)+1]
Definition: ecma119.h:1033
uint8_t parent[(8) -(7)+1]
Definition: ecma119.h:1032
uint8_t len_xa[(2) -(2)+1]
Definition: ecma119.h:1030
uint8_t block[(6) -(3)+1]
Definition: ecma119.h:1031
uint8_t m_path_table_pos[(152) -(149)+1]
Definition: ecma119.h:976
uint8_t vol_seq_number[(128) -(125)+1]
Definition: ecma119.h:971
uint8_t vol_space_size[(88) -(81)+1]
Definition: ecma119.h:968
uint8_t vol_set_size[(124) -(121)+1]
Definition: ecma119.h:970
uint8_t root_dir_record[(190) -(157)+1]
Definition: ecma119.h:978
uint8_t data_prep_id[(574) -(447)+1]
Definition: ecma119.h:981
uint8_t volume_id[(72) -(41)+1]
Definition: ecma119.h:966
uint8_t file_structure_version[(882) -(882)+1]
Definition: ecma119.h:990
uint8_t system_id[(40) -(9)+1]
Definition: ecma119.h:965
uint8_t std_identifier[(6) -(2)+1]
Definition: ecma119.h:962
uint8_t copyright_file_id[(739) -(703)+1]
Definition: ecma119.h:983
uint8_t vol_desc_version[(7) -(7)+1]
Definition: ecma119.h:963
uint8_t block_size[(132) -(129)+1]
Definition: ecma119.h:972
uint8_t vol_desc_type[(1) -(1)+1]
Definition: ecma119.h:961
uint8_t path_table_size[(140) -(133)+1]
Definition: ecma119.h:973
uint8_t abstract_file_id[(776) -(740)+1]
Definition: ecma119.h:984
uint8_t l_path_table_pos[(144) -(141)+1]
Definition: ecma119.h:974
uint8_t application_id[(702) -(575)+1]
Definition: ecma119.h:982
uint8_t vol_set_id[(318) -(191)+1]
Definition: ecma119.h:979
uint8_t publisher_id[(446) -(319)+1]
Definition: ecma119.h:980
uint8_t bibliographic_file_id[(813) -(777)+1]
Definition: ecma119.h:985
Iso1999Node ** children
Definition: iso1999.h:30
size_t len
Definition: iso1999.h:32
size_t block
Definition: iso1999.h:33
size_t nchildren
Definition: iso1999.h:31
char * name
Definition: iso1999.h:38
struct iso1999_dir_info * dir
Definition: iso1999.h:47
enum iso1999_node_type type
Definition: iso1999.h:44
Iso1999Node * parent
Definition: iso1999.h:40
IsoFileSrc * file
Definition: iso1999.h:46
IsoNode * node
Definition: iso1999.h:42
union iso1999_node::@4 info
uint32_t size
Definition: libisofs.h:259
uint32_t block
Definition: libisofs.h:258
unsigned int dir_rec_mtime
Definition: ecma119.h:244
unsigned int allow_longer_paths
Definition: ecma119.h:146
unsigned int always_gmt
Definition: ecma119.h:115