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)  

rockridge.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2007 Mario Danic
4  * Copyright (c) 2009 - 2020 Thomas Schmitt
5  *
6  * This file is part of the libisofs project; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * or later as published by the Free Software Foundation.
9  * See COPYING file for details.
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 #include "../config.h"
14 #endif
15 
16 #include <string.h>
17 #include <stdio.h>
18 
19 #include "rockridge.h"
20 #include "node.h"
21 #include "ecma119_tree.h"
22 #include "writer.h"
23 #include "messages.h"
24 #include "image.h"
25 #include "aaip_0_2.h"
26 #include "libisofs.h"
27 
28 
29 #ifdef Libisofs_with_rrip_rR
30 #define ISO_ROCKRIDGE_IN_DIR_REC 128
31 #else
32 #define ISO_ROCKRIDGE_IN_DIR_REC 124
33 #endif
34 
35 #define ISO_CE_ENTRY_SIZE 28
36 
37 
38 static
39 int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno);
40 
41 static
42 int susp_make_CE(Ecma119Image *t, uint8_t **CE,
43  uint32_t block_offset, uint32_t byte_offset, uint32_t size);
44 
45 
46 static
47 int susp_append(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
48 {
49  susp->n_susp_fields++;
50  susp->susp_fields = realloc(susp->susp_fields, sizeof(void*)
51  * susp->n_susp_fields);
52  if (susp->susp_fields == NULL) {
53  return ISO_OUT_OF_MEM;
54  }
55  susp->susp_fields[susp->n_susp_fields - 1] = data;
56  susp->suf_len += data[2];
57  return ISO_SUCCESS;
58 }
59 
60 static
61 int susp_append_ce(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
62 {
63  int to_alloc = 1, ret;
64  unsigned char *pad;
65  uint8_t *CE;
66  size_t next_alloc;
67 
68  if (data[0] &&
69  (susp->ce_len + data[2] + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE !=
70  susp->ce_len / BLOCK_SIZE) {
71  /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE.
72  So this Continuation Area needs to end by a CE which points
73  to the start of the next block.
74  */
75  to_alloc = 2;
76  if ((susp->ce_len + ISO_CE_ENTRY_SIZE) % BLOCK_SIZE)
77  to_alloc = 3; /* need a PAD pseudo entry */
78  }
79 
80  if (susp->ce_susp_fields == NULL)
81  susp->alloc_ce_susp_fields = 0;
82  if (susp->n_ce_susp_fields + to_alloc > susp->alloc_ce_susp_fields) {
83  next_alloc = susp->alloc_ce_susp_fields;
84  while (susp->n_ce_susp_fields + to_alloc > next_alloc)
85  next_alloc += ISO_SUSP_CE_ALLOC_STEP;
86  susp->ce_susp_fields = realloc(susp->ce_susp_fields,
87  sizeof(uint8_t *) * next_alloc);
88  if (susp->ce_susp_fields == NULL)
89  return ISO_OUT_OF_MEM;
90  susp->alloc_ce_susp_fields = next_alloc;
91  }
92 
93  if (to_alloc >= 2) {
94  /* Insert CE entry (actual CE size later by susp_update_CE_sizes) */
95  ret = susp_make_CE(t, &CE, (uint32_t) (susp->ce_block +
96  susp->ce_len / BLOCK_SIZE + 1),
97  (uint32_t) 0, (uint32_t) 2048);
98  if (ret < 0)
99  return ret;
100  susp->ce_susp_fields[susp->n_ce_susp_fields] = CE;
101  susp->ce_len += ISO_CE_ENTRY_SIZE;
102  susp->n_ce_susp_fields++;
103  }
104  if (to_alloc >= 3) {
105 
106 
107 #ifdef Libisofs_ce_calc_debuG
108 
109  fprintf(stderr,
110  "\nlibburn_DEBUG: Inserting %d bytes of CE padding\n\n",
111  (int) (BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE)));
112 
113 #endif /* Libisofs_ce_calc_debuG */
114 
115  pad = malloc(1);
116  if (pad == NULL)
117  return ISO_OUT_OF_MEM;
118  pad[0] = 0;
119  susp->ce_susp_fields[susp->n_ce_susp_fields] = pad;
120  if (susp->ce_len % BLOCK_SIZE)
121  susp->ce_len += BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE);
122  susp->n_ce_susp_fields++;
123  }
124  susp->ce_susp_fields[susp->n_ce_susp_fields] = data;
125  susp->n_ce_susp_fields++;
126 
127  if (data[0] == 0) {
128  if (susp->ce_len % BLOCK_SIZE)
129  susp->ce_len += BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE);
130  } else {
131  susp->ce_len += data[2];
132  }
133  return ISO_SUCCESS;
134 }
135 
136 static
138 {
139  if (t->replace_uid) {
140  return t->uid;
141  } else {
142  return n->node->uid;
143  }
144 }
145 
146 static
148 {
149  if (t->replace_gid) {
150  return t->gid;
151  } else {
152  return n->node->gid;
153  }
154 }
155 
156 static
158 {
159  if ((n->type == ECMA119_DIR || n->type == ECMA119_PLACEHOLDER)) {
160  if (t->replace_dir_mode) {
161  return (n->node->mode & S_IFMT) | t->dir_mode;
162  }
163  } else {
164  if (t->replace_file_mode) {
165  return (n->node->mode & S_IFMT) | t->file_mode;
166  }
167  }
168  return n->node->mode;
169 }
170 
171 /**
172  * Add a PX System Use Entry. The PX System Use Entry is used to add POSIX
173  * file attributes, such as access permissions or user and group id, to a
174  * ECMA 119 directory record. (RRIP, 4.1.1)
175  */
176 static
178 {
179  uint8_t *PX = malloc(44);
180  if (PX == NULL) {
181  return ISO_OUT_OF_MEM;
182  }
183 
184  PX[0] = 'P';
185  PX[1] = 'X';
186  if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10 ) {
187  PX[2] = 44;
188  } else {
189  PX[2] = 36;
190  }
191  PX[3] = 1;
192  iso_bb(&PX[4], (uint32_t) px_get_mode(t, n), 4);
193  iso_bb(&PX[12], (uint32_t) n->nlink, 4);
194  iso_bb(&PX[20], (uint32_t) px_get_uid(t, n), 4);
195  iso_bb(&PX[28], (uint32_t) px_get_gid(t, n), 4);
196  if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10) {
197  iso_bb(&PX[36], (uint32_t) n->ino, 4);
198  }
199 
200  return susp_append(t, susp, PX);
201 }
202 
203 /**
204  * Add to the given tree node a TF System Use Entry, used to record some
205  * time stamps related to the file (RRIP, 4.1.6).
206  */
207 static
209 {
210  IsoNode *iso;
211  uint8_t *TF = malloc(5 + 3 * 7);
212  if (TF == NULL) {
213  return ISO_OUT_OF_MEM;
214  }
215 
216  TF[0] = 'T';
217  TF[1] = 'F';
218  TF[2] = 5 + 3 * 7;
219  TF[3] = 1;
220  TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
221 
222  iso = n->node;
223  iso_datetime_7(&TF[5], t->replace_timestamps ? t->timestamp : iso->mtime,
224  t->opts->always_gmt);
225  iso_datetime_7(&TF[12], t->replace_timestamps ? t->timestamp : iso->atime,
226  t->opts->always_gmt);
227  iso_datetime_7(&TF[19], t->replace_timestamps ? t->timestamp : iso->ctime,
228  t->opts->always_gmt);
229  return susp_append(t, susp, TF);
230 }
231 
232 /**
233  * Add a PL System Use Entry, used to record the location of the original
234  * parent directory of a directory which has been relocated.
235  *
236  * This is special because it doesn't modify the susp fields of the directory
237  * that gets passed to it; it modifies the susp fields of the ".." entry in
238  * that directory.
239  *
240  * See RRIP, 4.1.5.2 for more details.
241  */
242 static
244 {
245  uint8_t *PL;
246 
247  if (n->type != ECMA119_DIR || n->info.dir->real_parent == NULL) {
248  /* should never occur */
249  return ISO_ASSERT_FAILURE;
250  }
251 
252  PL = malloc(12);
253  if (PL == NULL) {
254  return ISO_OUT_OF_MEM;
255  }
256 
257  PL[0] = 'P';
258  PL[1] = 'L';
259  PL[2] = 12;
260  PL[3] = 1;
261 
262  /* write the location of the real parent, already computed */
263  iso_bb(&PL[4],
265  return susp_append(t, susp, PL);
266 }
267 
268 /**
269  * Add a RE System Use Entry to the given tree node. The purpose of the
270  * this System Use Entry is to indicate to an RRIP-compliant receiving
271  * system that the Directory Record in which an "RE" System Use Entry is
272  * recorded has been relocated from another position in the original
273  * Directory Hierarchy.
274  *
275  * See RRIP, 4.1.5.3 for more details.
276  */
277 static
279 {
280  uint8_t *RE = malloc(4);
281  if (RE == NULL) {
282  return ISO_OUT_OF_MEM;
283  }
284 
285  RE[0] = 'R';
286  RE[1] = 'E';
287  RE[2] = 4;
288  RE[3] = 1;
289  return susp_append(t, susp, RE);
290 }
291 
292 /**
293  * Add a PN System Use Entry to the given tree node.
294  * The PN System Use Entry is used to store the device number, and it's
295  * mandatory if the tree node corresponds to a character or block device.
296  *
297  * See RRIP, 4.1.2 for more details.
298  */
299 static
301 {
302  IsoSpecial *node;
303  uint8_t *PN;
304  int high_shift= 0;
305 
306  node = (IsoSpecial*)n->node;
307  if (node->node.type != LIBISO_SPECIAL) {
308  /* should never occur */
309  return ISO_ASSERT_FAILURE;
310  }
311 
312  PN = malloc(20);
313  if (PN == NULL) {
314  return ISO_OUT_OF_MEM;
315  }
316 
317  PN[0] = 'P';
318  PN[1] = 'N';
319  PN[2] = 20;
320  PN[3] = 1;
321 
322  /* (dev_t >> 32) causes compiler warnings on FreeBSD.
323  RRIP 1.10 4.1.2 prescribes PN "Dev_t High" to be 0 on 32 bit dev_t.
324  */
325  if (sizeof(node->dev) > 4) {
326  high_shift = 32;
327  iso_bb(&PN[4], (uint32_t) (node->dev >> high_shift), 4);
328  } else
329  iso_bb(&PN[4], 0, 4);
330  iso_bb(&PN[12], (uint32_t) (node->dev & 0xffffffff), 4);
331  return susp_append(t, susp, PN);
332 }
333 
334 /**
335  * Add to the given tree node a CL System Use Entry, that is used to record
336  * the new location of a directory which has been relocated.
337  *
338  * See RRIP, 4.1.5.1 for more details.
339  */
340 static
342 {
343  uint8_t *CL;
344  if (n->type != ECMA119_PLACEHOLDER) {
345  /* should never occur */
346  return ISO_ASSERT_FAILURE;
347  }
348  CL = malloc(12);
349  if (CL == NULL) {
350  return ISO_OUT_OF_MEM;
351  }
352 
353  CL[0] = 'C';
354  CL[1] = 'L';
355  CL[2] = 12;
356  CL[3] = 1;
358  4);
359  return susp_append(t, susp, CL);
360 }
361 
362 /**
363  * Convert a RR filename to the requested charset. On any conversion error,
364  * the original name will be used.
365  * @param flag bit0= do not issue error messages
366  */
367 int iso_get_rr_name(IsoWriteOpts *opts, char *input_charset,
368  char *output_charset, int imgid,
369  char *str, char **name, int flag)
370 {
371  int ret;
372 
373  if (!strcmp(input_charset, output_charset)) {
374  /* no conversion needed */
375  ret = iso_clone_mem(str, name, 0);
376  return ret;
377  }
378 
379  ret = strconv(str, input_charset, output_charset, name);
380  if (ret < 0) {
381  /* TODO we should check for possible cancellation */
382  if (!(flag & 1))
384  "Charset conversion error. Cannot convert %s from %s to %s",
385  str, input_charset, output_charset);
386  *name = NULL;
388  }
389 
390  return ISO_SUCCESS;
391 }
392 
393 static
394 char *get_rr_fname(Ecma119Image *t, char *str)
395 {
396  int ret;
397  char *name = NULL;
398 
400  t->image->id, str, &name, 0);
401  if (ret < 0)
402  return NULL;
403  return name;
404 }
405 
406 /**
407  * Add a NM System Use Entry to the given tree node. The purpose of this
408  * System Use Entry is to store the content of an Alternate Name to support
409  * POSIX-style or other names.
410  *
411  * See RRIP, 4.1.4 for more details.
412  *
413  * @param size
414  * Length of the name to be included into the NM
415  * @param flags
416  * @param ce
417  * Whether to add or not to CE
418  */
419 static
420 int rrip_add_NM(Ecma119Image *t, struct susp_info *susp, char *name, int size,
421  int flags, int ce)
422 {
423  uint8_t *NM;
424 
425  if (size > 250)
426  return ISO_ASSERT_FAILURE;
427 
428  NM = malloc(size + 5);
429  if (NM == NULL) {
430  return ISO_OUT_OF_MEM;
431  }
432 
433  NM[0] = 'N';
434  NM[1] = 'M';
435  NM[2] = size + 5;
436  NM[3] = 1;
437  NM[4] = flags;
438  if (size) {
439  memcpy(&NM[5], name, size);
440  }
441  if (ce) {
442  return susp_append_ce(t, susp, NM);
443  } else {
444  return susp_append(t, susp, NM);
445  }
446 }
447 
448 /**
449  * Add a new SL component (RRIP, 4.1.3.1) to a list of components.
450  *
451  * @param n
452  * Number of components. It will be updated.
453  * @param compos
454  * Pointer to the list of components.
455  * @param s
456  * The component content
457  * @param size
458  * Size of the component content
459  * @param fl
460  * Flags
461  * @return
462  * 1 on success, < 0 on error
463  */
464 static
465 int rrip_SL_append_comp(size_t *n, uint8_t ***comps, char *s, int size, char fl)
466 {
467  uint8_t *comp = malloc(size + 2);
468  if (comp == NULL) {
469  return ISO_OUT_OF_MEM;
470  }
471 
472  (*n)++;
473  comp[0] = fl;
474  comp[1] = size;
475  *comps = realloc(*comps, (*n) * sizeof(void*));
476  if (*comps == NULL) {
477  free(comp);
478  return ISO_OUT_OF_MEM;
479  }
480  (*comps)[(*n) - 1] = comp;
481 
482  if (size) {
483  memcpy(&comp[2], s, size);
484  }
485  return ISO_SUCCESS;
486 }
487 
488 
489 #ifdef Libisofs_with_rrip_rR
490 
491 /**
492  * Add a RR System Use Entry to the given tree node. This is an obsolete
493  * entry from before RRIP-1.10. Nevertheless mkisofs produces it. There
494  * is the suspicion that some operating systems could take it as indication
495  * for Rock Ridge.
496  *
497  * The meaning of the payload byte is documented e.g. in
498  * /usr/src/linux/fs/isofs/rock.h
499  * It announces the presence of entries PX, PN, SL, NM, CL, PL, RE, TF
500  * by payload byte bits 0 to 7.
501  */
502 static
503 int rrip_add_RR(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
504 {
505  uint8_t *RR;
506  RR = malloc(5);
507  if (RR == NULL) {
508  return ISO_OUT_OF_MEM;
509  }
510 
511  RR[0] = 'R';
512  RR[1] = 'R';
513  RR[2] = 5;
514  RR[3] = 1;
515 
516  /* <<< ts B20307 : Not all directories have NM, many files have more entries */
517  RR[4] = 0x89; /* TF, NM , PX */
518 
519  /* >>> ts B20307 : find out whether n carries
520  PX, PN, SL, NM, CL, PL, RE, TF and mark by bit0 to bit7 in RR[4]
521  */
522 
523  return susp_append(t, susp, RR);
524 }
525 
526 #endif /* Libisofs_with_rrip_rR */
527 
528 
529 /**
530  * Add a SL System Use Entry to the given tree node. This is used to store
531  * the content of a symbolic link, and is mandatory if the tree node
532  * indicates a symbolic link (RRIP, 4.1.3).
533  *
534  * @param comp
535  * Components of the SL System Use Entry. If they don't fit in a single
536  * SL, more than one SL will be added.
537  * @param n
538  * Number of components in comp
539  * @param ce
540  * Whether to add to a continuation area or system use field.
541  */
542 static
543 int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, uint8_t **comp,
544  size_t n, int ce)
545 {
546  int ret;
547  size_t i, j;
548  int total_comp_len = 0;
549  size_t pos, written = 0;
550 
551  uint8_t *SL;
552 
553  for (i = 0; i < n; i++) {
554 
555  total_comp_len += comp[i][1] + 2;
556  if (total_comp_len > 250) {
557  /* we need a new SL entry */
558  total_comp_len -= comp[i][1] + 2;
559  SL = malloc(total_comp_len + 5);
560  if (SL == NULL) {
561  return ISO_OUT_OF_MEM;
562  }
563 
564  SL[0] = 'S';
565  SL[1] = 'L';
566  SL[2] = total_comp_len + 5;
567  SL[3] = 1;
568  SL[4] = 1; /* CONTINUE */
569  pos = 5;
570  for (j = written; j < i; j++) {
571  memcpy(&SL[pos], comp[j], comp[j][1] + 2);
572  pos += comp[j][1] + 2;
573  }
574 
575  /*
576  * In this case we are sure we're writing to CE. Check for
577  * debug purposes
578  */
579  if (ce == 0) {
580  free(SL);
581  return ISO_ASSERT_FAILURE;
582  }
583  ret = susp_append_ce(t, susp, SL);
584  if (ret < 0) {
585  free(SL);
586  return ret;
587  }
588  SL = NULL; /* now owned by susp */
589  written = i;
590  total_comp_len = comp[i][1] + 2;
591  }
592  }
593 
594  SL = malloc(total_comp_len + 5);
595  if (SL == NULL) {
596  return ISO_OUT_OF_MEM;
597  }
598 
599  SL[0] = 'S';
600  SL[1] = 'L';
601  SL[2] = total_comp_len + 5;
602  SL[3] = 1;
603  SL[4] = 0;
604  pos = 5;
605 
606  for (j = written; j < n; j++) {
607  memcpy(&SL[pos], comp[j], comp[j][1] + 2);
608  pos += comp[j][1] + 2;
609  }
610  if (ce) {
611  ret = susp_append_ce(t, susp, SL);
612  } else {
613  ret = susp_append(t, susp, SL);
614  }
615  return ret;
616 }
617 
618 
619 /* @param flag bit1= care about crossing block boundaries */
620 static
621 int susp_calc_add_to_ce(size_t *ce, size_t base_ce, int add, int flag)
622 {
623  if (flag & 2) {
624  /* Account for inserted CE before size exceeds block size */
625  if ((*ce + base_ce + add + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE !=
626  (*ce + base_ce) / BLOCK_SIZE) {
627  /* Insert CE and padding */
628  *ce += ISO_CE_ENTRY_SIZE;
629  if ((*ce + base_ce) % BLOCK_SIZE)
630  *ce += BLOCK_SIZE - ((*ce + base_ce) % BLOCK_SIZE);
631  }
632  }
633  *ce += add;
634  return ISO_SUCCESS;
635 }
636 
637 
638 /*
639  @param flag bit0= only account sizes in sua_free resp. ce_len.
640  Parameter susp may be NULL in this case
641  bit1= account for crossing block boundaries
642  (implied by bit0 == 0)
643  @param ce_len counts the freshly added CA size of the current node
644  @param ce_mem tells the CA size of previous nodes in the same directory
645 */
646 static
647 int aaip_add_AL(Ecma119Image *t, struct susp_info *susp,
648  uint8_t **data, size_t num_data,
649  size_t *sua_free, size_t *ce_len, size_t ce_mem, int flag)
650 {
651  int ret, done = 0, len, es_extra = 0;
652  uint8_t *aapt, *cpt;
653  size_t count = 0;
654 
655  if (!(flag & 1))
656  flag |= 2;
657  if (!t->opts->aaip_susp_1_10)
658  es_extra = 5;
659  if (*sua_free < num_data + es_extra || *ce_len > 0) {
660  if (es_extra > 0)
661  susp_calc_add_to_ce(ce_len, ce_mem, es_extra, flag & 2);
662  done = 0;
663  for (aapt = *data; !done; aapt += aapt[2]) {
664  done = !(aapt[4] & 1);
665  len = aapt[2];
666  susp_calc_add_to_ce(ce_len, ce_mem, len, flag & 2);
667  count += len;
668  }
669  } else {
670  *sua_free -= num_data + es_extra;
671  }
672  if (flag & 1)
673  return ISO_SUCCESS;
674 
675  /* If AAIP enabled and announced by ER : Write ES field to announce AAIP */
676  if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
677  ret = susp_add_ES(t, susp, (*ce_len > 0), 1);
678  if (ret < 0)
679  return ret;
680  }
681  aapt = *data;
682  if (!(aapt[4] & 1)) {
683  /* Single field can be handed over directly */
684  if (*ce_len > 0) {
685  ret = susp_append_ce(t, susp, aapt);
686  } else {
687  ret = susp_append(t, susp, aapt);
688  }
689  *data = NULL;
690  return ISO_SUCCESS;
691  }
692 
693  /* Multiple fields have to be handed over as single field copies */
694  done = 0;
695  for (aapt = *data; !done; aapt += aapt[2]) {
696  done = !(aapt[4] & 1);
697  len = aapt[2];
698  cpt = calloc(aapt[2], 1);
699  if (cpt == NULL)
700  return ISO_OUT_OF_MEM;
701  memcpy(cpt, aapt, len);
702  if (*ce_len > 0) {
703  ret = susp_append_ce(t, susp, cpt);
704  } else {
705  ret = susp_append(t, susp, cpt);
706  }
707  if (ret == -1)
708  return ret;
709  }
710  free(*data);
711  *data = NULL;
712  return ISO_SUCCESS;
713 }
714 
715 
716 /**
717  * Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
718  *
719  * The "ER" System Use Entry is used to uniquely identify a specification
720  * compliant with SUSP. This method adds to the given tree node "." entry
721  * the "ER" corresponding to the RR protocol.
722  *
723  * See SUSP, 5.5 and RRIP, 4.3 for more details.
724  */
725 static
726 int rrip_add_ER(Ecma119Image *t, struct susp_info *susp)
727 {
728  unsigned char *ER;
729 
730  if (!t->opts->rrip_version_1_10) {
731  /*
732  According to RRIP 1.12 this is the future form:
733  4.3 "Specification of the ER System Use Entry Values for RRIP"
734  talks of "IEEE_P1282" in each of the three strings and finally states
735  "Note: Upon adoption as an IEEE standard, these lengths will each
736  decrease by 1."
737  So "IEEE_P1282" would be the new form, "RRIP_1991A" is the old form.
738  */
739 
740  ER = malloc(182);
741  if (ER == NULL) {
742  return ISO_OUT_OF_MEM;
743  }
744 
745  ER[0] = 'E';
746  ER[1] = 'R';
747  ER[2] = 182;
748  ER[3] = 1;
749  ER[4] = 9;
750  ER[5] = 72;
751  ER[6] = 93;
752  ER[7] = 1;
753  memcpy(&ER[8], "IEEE_1282", 9);
754  memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
755  "FILE SYSTEM SEMANTICS.", 72);
756  memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
757  "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
758  } else {
759  /*
760  RRIP 1.09 and 1.10:
761  4.3 Specification of the ER System Use Field Values for RRIP
762  The Extension Version number for the version of the RRIP defined herein
763  shall be 1. The content of the Extension Identifier field shall be
764  "RRIP_1991A". The Identifier Length shall be 10. The recommended
765  content of the Extension Descriptor shall be "THE ROCK RIDGE
766  INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
767  The corresponding Description Length is 84.
768  The recommended content of the Extension Source shall be "PLEASE
769  CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER
770  IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION."
771  The corresponding Source Length is 135.
772  */
773 
774  ER = malloc(237);
775  if (ER == NULL) {
776  return ISO_OUT_OF_MEM;
777  }
778 
779  ER[0] = 'E';
780  ER[1] = 'R';
781  ER[2] = 237;
782  ER[3] = 1;
783  ER[4] = 10;
784  ER[5] = 84;
785  ER[6] = 135;
786  ER[7] = 1;
787 
788  memcpy(&ER[8], "RRIP_1991A", 10);
789  memcpy(&ER[18], "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", 84);
790  memcpy(&ER[102], "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", 135);
791  }
792 
793  /** This always goes to continuation area */
794  return susp_append_ce(t, susp, ER);
795 }
796 
797 
798 static
799 int aaip_add_ER(Ecma119Image *t, struct susp_info *susp, int flag)
800 {
801  unsigned char *ER;
802 
803  ER = malloc(160);
804  if (ER == NULL) {
805  return ISO_OUT_OF_MEM;
806  }
807 
808  ER[0] = 'E';
809  ER[1] = 'R';
810  ER[2] = 160;
811  ER[3] = 1;
812  ER[4] = 9;
813  ER[5] = 81;
814  ER[6] = 62;
815  ER[7] = 1;
816  memcpy(ER + 8, "AAIP_0200", 9);
817  memcpy(ER + 17,
818  "AL PROVIDES VIA AAIP 2.0 SUPPORT FOR ARBITRARY FILE ATTRIBUTES"
819  " IN ISO 9660 IMAGES", 81);
820  memcpy(ER + 98,
821  "PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG",
822  62);
823 
824  /** This always goes to continuation area */
825  return susp_append_ce(t, susp, ER);
826 }
827 
828 
829 /**
830  * Create the byte representation of a CE entry.
831  * (SUSP, 5.1).
832  */
833 static
834 int susp_make_CE(Ecma119Image *t, uint8_t **CE,
835  uint32_t block_offset, uint32_t byte_offset, uint32_t size)
836 {
837  uint8_t *data;
838 
839  *CE = NULL;
840  data = calloc(1, 28);
841  if (data == NULL)
842  return ISO_OUT_OF_MEM;
843  *CE = data;
844 
845  data[0] = 'C';
846  data[1] = 'E';
847  data[2] = 28;
848  data[3] = 1;
849 
850  iso_bb(&data[4], block_offset - t->eff_partition_offset, 4);
851  iso_bb(&data[12], byte_offset, 4);
852  iso_bb(&data[20], size, 4);
853 
854  return ISO_SUCCESS;
855 }
856 
857 
858 /**
859  * Add a CE System Use Entry to the given tree node. A "CE" is used to add
860  * a continuation area, where additional System Use Entry can be written.
861  * (SUSP, 5.1).
862  */
863 static
864 int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp)
865 {
866  uint32_t block_offset, byte_offset;
867  uint8_t *CE;
868  int ret;
869 
870  /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE
871  * Here the byte_offset is reduced to the minimum.
872  */
873  block_offset = susp->ce_block + susp->ce_len / BLOCK_SIZE;
874  byte_offset = susp->ce_len % BLOCK_SIZE;
875  ret = susp_make_CE(t, &CE, block_offset, byte_offset, (uint32_t) ce_len);
876  if (ret < 0)
877  return ret;
878  return susp_append(t, susp, CE);
879 }
880 
881 /**
882  * Add a SP System Use Entry. The SP provide an identifier that the SUSP is
883  * used within the volume. The SP shall be recorded in the "." entry of the
884  * root directory. See SUSP, 5.3 for more details.
885  */
886 static
887 int susp_add_SP(Ecma119Image *t, struct susp_info *susp)
888 {
889  unsigned char *SP = malloc(7);
890  if (SP == NULL) {
891  return ISO_OUT_OF_MEM;
892  }
893 
894  SP[0] = 'S';
895  SP[1] = 'P';
896  SP[2] = (char)7;
897  SP[3] = (char)1;
898  SP[4] = 0xbe;
899  SP[5] = 0xef;
900  SP[6] = 0;
901  return susp_append(t, susp, SP);
902 }
903 
904 
905 /**
906  * SUSP 1.12: [...] shall specify as an 8-bit number the Extension
907  * Sequence Number of the extension specification utilized in the entries
908  * immediately following this System Use Entry. The Extension Sequence
909  * Numbers of multiple extension specifications on a volume shall correspond to
910  * the order in which their "ER" System Use Entries are recorded [...]
911  */
912 static
913 int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno)
914 {
915  unsigned char *ES = malloc(5);
916 
917  if (ES == NULL) {
918  return ISO_OUT_OF_MEM;
919  }
920  ES[0] = 'E';
921  ES[1] = 'S';
922  ES[2] = (unsigned char) 5;
923  ES[3] = (unsigned char) 1;
924  ES[4] = (unsigned char) seqno;
925  if (to_ce) {
926  return susp_append_ce(t, susp, ES);
927  } else {
928  return susp_append(t, susp, ES);
929  }
930 }
931 
932 
933 /**
934  * A field beginning by 0 causes rrip_write_ce_fields() to pad up to the
935  * next block.
936  */
937 static
939 {
940  unsigned char *pad;
941  int ret;
942 
943  pad = malloc(1);
944  if (pad == NULL)
945  return ISO_OUT_OF_MEM;
946  pad[0] = 0;
947  ret = susp_append_ce(t, susp, pad);
948  if (ret < 0)
949  return ret;
950  return ISO_SUCCESS;
951 }
952 
953 
954 /**
955  * see doc/zisofs_format.txt : "ZF System Use Entry Format"
956  * see doc/zisofs2_format.txt : "ZF System Use Entry Format", "Z2 ..."
957  */
958 static
959 int zisofs_add_ZF(Ecma119Image *t, struct susp_info *susp, int to_ce,
960  uint8_t algo[2], int header_size_div4, int block_size_log2,
961  uint64_t uncompressed_size, int flag)
962 {
963  unsigned char *ZF = malloc(16);
964 
965  /* Intimate friendship with this variable in filters/zisofs.c */
966  extern int iso_zisofs2_enable_susp_z2;
967 
968  if (ZF == NULL) {
969  return ISO_OUT_OF_MEM;
970  }
971  ZF[0] = 'Z';
972  ZF[1] = 'F';
973  ZF[2] = (unsigned char) 16;
974  if (algo[0] == 'p' && algo[1] == 'z') {
975  ZF[3] = (unsigned char) 1;
976  } else {
977  ZF[3] = (unsigned char) 2;
979  ZF[1] = '2';
980  }
981  ZF[4] = (unsigned char) algo[0];
982  ZF[5] = (unsigned char) algo[1];
983  ZF[6] = (unsigned char) header_size_div4;
984  ZF[7] = (unsigned char) block_size_log2;
985  if (algo[0] == 'p' && algo[1] == 'z') {
986  if (uncompressed_size > (uint64_t) 0xffffffff)
987  return ISO_ZISOFS_TOO_LARGE;
988  iso_bb(&ZF[8], (uint32_t) uncompressed_size, 4);
989  } else {
990  iso_lsb64(&ZF[8], uncompressed_size);
991  }
992  if (to_ce) {
993  return susp_append_ce(t, susp, ZF);
994  } else {
995  return susp_append(t, susp, ZF);
996  }
997 }
998 
999 
1000 /* @param flag bit0= Do not add data but only count sua_free and ce_len
1001  bit1= account for crossing block boundaries
1002  (implied by bit0 == 0)
1003 */
1004 static
1006  size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
1007 {
1008  int ret, will_copy = 1, stream_type = 0, do_zf = 0;
1009  int header_size_div4 = 0, block_size_log2 = 0;
1010  uint64_t uncompressed_size = 0;
1011  IsoStream *stream = NULL, *input_stream, *last_stream, *first_stream;
1012  IsoStream *first_filter = NULL;
1013  IsoFile *file;
1014  void *xipt;
1015  struct zisofs_zf_info *zf;
1016  uint8_t algo[2];
1017 
1018  /* Intimate friendship with this function in filters/zisofs.c */
1019  int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
1020  uint8_t zisofs_algo[2],
1021  int *header_size_div4, int *block_size_log2,
1022  uint64_t *uncompressed_size, int flag);
1023 
1024  if (!(flag & 1))
1025  flag |= 2;
1026 
1027  if (iso_node_get_type(n->node) != LIBISO_FILE)
1028  return 2;
1029  file = (IsoFile *) n->node;
1030 
1031  /* Inspect: last_stream < ... < first_filter < first_stream */
1032  /* The content is in zisofs format if:
1033  It gets copied and
1034  the last stream is a ziso stream,
1035  or it had a ZF entry and is unfiltered
1036  or it has a zf xinfo record (because its last stream delivered a
1037  zisofs file header when inquired)
1038  or it stays uncopied and
1039  the first filter is an osiz stream,
1040  or it had a ZF entry
1041  or it has a zf xinfo record (because its first stream delivered a
1042  zisofs file header when inquired)
1043  */
1044 
1045  if (t->opts->appendable && file->from_old_session)
1046  will_copy = 0;
1047 
1048  first_filter = first_stream = last_stream = iso_file_get_stream(file);
1049  while (1) {
1050  input_stream = iso_stream_get_input_stream(first_stream, 0);
1051  if (input_stream == NULL)
1052  break;
1053  first_filter = first_stream;
1054  first_stream = input_stream;
1055  }
1056  if (will_copy) {
1057  stream = last_stream;
1058  } else {
1059  /* (the eventual osiz filter on the image stream) */
1060  stream = first_filter;
1061  }
1062 
1063  /* Determine stream type : 1=ziso , -1=osiz , 0=other */
1064  algo[0] = algo[1] = 0;
1065  ret = ziso_is_zisofs_stream(stream, &stream_type, algo, &header_size_div4,
1067  if (ret < 0)
1068  return ret;
1069 
1070  if (stream_type == 1 && will_copy) {
1071  do_zf = 1;
1072  } else if (stream_type == -1 && !will_copy) {
1073  do_zf = 1;
1074  } else if(first_stream == last_stream || !will_copy) {
1075  /* Try whether the image side stream remembers a ZF field */
1076  ret = iso_stream_get_src_zf(first_stream, algo, &header_size_div4,
1078  if (ret == 1 && header_size_div4 > 0)
1079  do_zf = 1;
1080  }
1081  if (!do_zf) {
1082  /* Look for an xinfo mark of a zisofs header */
1084  &xipt);
1085  if (ret == 1) {
1086  zf = xipt;
1090  algo[0] = zf->zisofs_algo[0];
1091  algo[1] = zf->zisofs_algo[1];
1092  if (header_size_div4 > 0)
1093  do_zf = 1;
1094  }
1095  }
1096 
1097  if (!do_zf)
1098  return 2;
1099 
1100  /* Account for field size */
1101  if (*sua_free < 16 || *ce_len > 0) {
1102  susp_calc_add_to_ce(ce_len, base_ce, 16, flag & 2);
1103  } else {
1104  *sua_free -= 16;
1105  }
1106  if (flag & 1)
1107  return 1;
1108 
1109  /* write ZF field */
1110  ret = zisofs_add_ZF(t, info, (*ce_len > 0), algo, header_size_div4,
1112  if (ret < 0)
1113  return ret;
1114  return 1;
1115 }
1116 
1117 /* API */
1118 int aaip_xinfo_func(void *data, int flag)
1119 {
1120  if (flag & 1) {
1121  free(data);
1122  }
1123  return 1;
1124 }
1125 
1126 /* API */
1127 int aaip_xinfo_cloner(void *old_data, void **new_data, int flag)
1128 {
1129  size_t aa_size;
1130 
1131  *new_data = NULL;
1132  if (old_data == NULL)
1133  return 0;
1134  aa_size = aaip_count_bytes((unsigned char *) old_data, 0);
1135  if (aa_size <= 0)
1136  return ISO_AAIP_BAD_AASTRING;
1137  *new_data = calloc(1, aa_size);
1138  if (*new_data == NULL)
1139  return ISO_OUT_OF_MEM;
1140  memcpy(*new_data, old_data, aa_size);
1141  return (int) aa_size;
1142 }
1143 
1144 /**
1145  * Compute SUA length and eventual Continuation Area length of field NM and
1146  * eventually fields SL and AL. Because CA usage makes necessary the use of
1147  * a CE entry of 28 bytes in SUA, this computation fails if not the 28 bytes
1148  * are taken into account at start. In this case the caller should retry with
1149  * bit0 set.
1150  * If the resulting *ce added to base_ce is in a different block than base_ce,
1151  * then computation with bit0 fails and the caller should finally try bit1.
1152  *
1153  * @param flag bit0= assume CA usage (else return 0 on SUA overflow)
1154  * bit1= let CA start at block start (else return 0 if
1155  * *ce crosses a block boundary)
1156  * @return 1= ok, computation of *su_size and *ce is valid
1157  * 0= not ok, CA usage is necessary but bit0 was not set
1158  * or *ce crosses boundary and bit1 was not set
1159  * (*su_size and *ce stay unaltered in this case)
1160  * <0= error:
1161  * -1= not enough SUA space for 28 bytes of CE entry
1162  * -2= out of memory
1163  */
1164 static
1166  size_t *su_size, size_t *ce, size_t base_ce, int flag)
1167 {
1168  char *name;
1169  size_t namelen, su_mem, ce_mem, ce_prepad = 0;
1170  void *xipt;
1171  size_t num_aapt = 0, sua_free = 0;
1172  int ret;
1173  uint8_t *aapt;
1174 
1175 #ifdef Libisofs_ce_calc_debug_extrA
1176 
1177  if (n->node->name != NULL)
1178  fprintf(stderr, "libburn_DEBUG: susp_calc_nm_sl_al : %.f %s \n",
1179  (double) base_ce, n->node->name);
1180 
1181 #endif /* Libisofs_ce_calc_debug_extrA */
1182 
1183  su_mem = *su_size;
1184  ce_mem = *ce;
1185  if (*ce > 0 && !(flag & 1))
1186  goto unannounced_ca;
1187 
1188  if (flag & 2) {
1189  flag |= 1;
1190  if (base_ce % BLOCK_SIZE) {
1191 
1192 #ifdef Libisofs_ce_calc_debuG
1193 
1194  fprintf(stderr,
1195  "\nlibburn_DEBUG: Accounting for %d bytes CE padding : %s\n\n",
1196  (int) (BLOCK_SIZE - (base_ce % BLOCK_SIZE)), n->node->name);
1197 
1198 #endif /* Libisofs_ce_calc_debuG */
1199 
1200  ce_prepad = BLOCK_SIZE - (base_ce % BLOCK_SIZE);
1201  }
1202  }
1203 
1204  namelen = 0;
1205  name = get_rr_fname(t, n->node->name);
1206  if (name != NULL) {
1207  namelen = strlen(name);
1208  free(name);
1209  }
1210 
1211  if (flag & 1) {
1212  /* Account for 28 bytes of CE field */
1213  if (*su_size + 28 > space) {
1214  *ce += ce_prepad;
1215  return -1;
1216  }
1217  *su_size += 28;
1218  }
1219 
1220  /* NM entry */
1221  if (*su_size + 5 + namelen <= space) {
1222  /* ok, it fits in System Use Area */
1223  *su_size += 5 + namelen;
1224  } else {
1225  /* the NM will be divided in a CA */
1226  if (!(flag & 1))
1227  goto unannounced_ca;
1228  namelen = namelen - (space - *su_size - 5);
1229 
1230  /* >>> SUPER_LONG_RR: Need to handle CA part lengths > 250
1231  (This cannot happen with name lengths <= 256, as a part
1232  of the name will always fit into the directory entry.)
1233  */;
1234 
1235  susp_calc_add_to_ce(ce, base_ce, 5 + namelen, flag & 2);
1236  *su_size = space;
1237  }
1238  if (n->type == ECMA119_SYMLINK) {
1239  /*
1240  * for symlinks, we also need to write the SL
1241  */
1242  char *dest, *cur, *prev;
1243  size_t sl_len = 5;
1244  int cew = (*ce != 0); /* are we writing to CA ? */
1245 
1246  dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
1247  if (dest == NULL) {
1248  *ce += ce_prepad;
1249  return -2;
1250  }
1251  prev = dest;
1252  cur = strchr(prev, '/');
1253  while (1) {
1254  size_t clen;
1255  if (cur) {
1256  clen = cur - prev;
1257  } else {
1258  /* last component */
1259  clen = strlen(prev);
1260  }
1261 
1262  if (clen == 1 && prev[0] == '.') {
1263  clen = 0;
1264  } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
1265  clen = 0;
1266  }
1267 
1268  /* flags and len for each component record (RRIP, 4.1.3.1) */
1269  clen += 2;
1270 
1271  if (!cew) {
1272  /* we are still writing to the SUA */
1273  if (*su_size + sl_len + clen > space) {
1274  /*
1275  * ok, we need a Continuation Area anyway
1276  * TODO this can be handled better, but for now SL
1277  * will be completely moved into the CA
1278  */
1279  if (!(flag & 1)) {
1280  free(dest);
1281  goto unannounced_ca;
1282  }
1283  cew = 1;
1284  } else {
1285  sl_len += clen;
1286  }
1287  }
1288  if (cew) {
1289  if (sl_len + clen > 255) {
1290  /* we need an additional SL entry */
1291  if (clen > 250) {
1292  /*
1293  * case 1, component too large to fit in a
1294  * single SL entry. Thus, the component need
1295  * to be divided anyway.
1296  * Note than clen can be up to 255 + 2 = 257.
1297  *
1298  * First, we check how many bytes fit in current
1299  * SL field
1300  */
1301  ssize_t fit = 255 - sl_len - 2;
1302  if ((ssize_t) (clen - 250) <= fit) {
1303  /*
1304  * the component can be divided between this
1305  * and another SL entry
1306  */
1307  /* Will fill up old SL and write it */
1308  susp_calc_add_to_ce(ce, base_ce, 255, flag & 2);
1309  sl_len = 5 + (clen - fit); /* Start new SL */
1310  } else {
1311  /*
1312  * the component will need a 2rd SL entry in
1313  * any case, so we prefer to don't write
1314  * anything in this SL
1315  */
1316  /* Will write non-full old SL */
1317  susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1318  /* Will write another full SL */
1319  susp_calc_add_to_ce(ce, base_ce, 255, flag & 2);
1320  sl_len = 5 + (clen - 250) + 2; /* Start new SL */
1321  }
1322  } else {
1323  /* case 2, create a new SL entry */
1324  /* Will write non-full old SL */
1325  susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1326  sl_len = 5 + clen; /* Start new SL */
1327  }
1328  } else {
1329  sl_len += clen;
1330  }
1331  }
1332 
1333  if (!cur || cur[1] == '\0') {
1334  /* cur[1] can be \0 if dest ends with '/' */
1335  break;
1336  }
1337  prev = cur + 1;
1338  cur = strchr(prev, '/');
1339  }
1340 
1341  free(dest);
1342 
1343  /* and finally write the pending SL field */
1344  if (!cew) {
1345  /* the whole SL fits into the SUA */
1346  *su_size += sl_len;
1347  } else {
1348  susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1349  }
1350 
1351  }
1352 
1353  /* Find out whether ZF is to be added and account for its bytes */
1354  sua_free = space - *su_size;
1355  add_zf_field(t, n, NULL, &sua_free, ce, base_ce, 1 | (flag & 2));
1356  *su_size = space - sua_free;
1357  if (*ce > 0 && !(flag & 1))
1358  goto unannounced_ca;
1359 
1360  *ce += ce_prepad;
1361  ce_prepad = 0;
1362 
1363  /* obtain num_aapt from node */
1364  xipt = NULL;
1365  num_aapt = 0;
1366  if (t->opts->aaip) {
1367  ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt);
1368  if (ret == 1) {
1369  num_aapt = aaip_count_bytes((unsigned char *) xipt, 0);
1370  }
1371  }
1372  /* let the expert decide where to add num_aapt */
1373  if (num_aapt > 0) {
1374  sua_free = space - *su_size;
1375  aapt = (uint8_t *) xipt;
1376  aaip_add_AL(t, NULL, &aapt, num_aapt, &sua_free, ce, base_ce,
1377  1 | (flag & 2));
1378  *su_size = space - sua_free;
1379  if (*ce > 0 && !(flag & 1))
1380  goto unannounced_ca;
1381  }
1382 
1383 #ifdef Libisofs_ce_calc_debug_filetraP
1384 
1385  if (n->node->name != NULL)
1386  if (strcmp(n->node->name, "...insert.leaf.name.here...") == 0)
1387  fprintf(stderr,
1388  "libburn_DEBUG: filename breakpoint susp_calc_nm_sl_al\n");
1389 
1390 #endif /* Libisofs_ce_calc_debug_filetraP */
1391 
1392  if (*ce > 0 && !(flag & 2)) {
1393  if (base_ce / BLOCK_SIZE !=
1394  (base_ce + *ce + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE) {
1395 
1396 #ifdef Libisofs_ce_calc_debuG
1397 
1398  fprintf(stderr,
1399  "\nlibburn_DEBUG: Crossed block boundary: %.f (%lu) -> %.f (%lu) : %s\n\n",
1400  (double) base_ce, (unsigned long) (base_ce / BLOCK_SIZE),
1401  (double) (base_ce + *ce - 1),
1402  (unsigned long)
1403  ((base_ce + *ce + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE),
1404  n->node->name);
1405 
1406 #endif /* Libisofs_ce_calc_debuG */
1407 
1408  /* Crossed a block boundary */
1409  *su_size = su_mem;
1410  *ce = ce_mem;
1411  return 0;
1412  }
1413  }
1414 
1415  *ce += ce_prepad;
1416  return 1;
1417 
1418 unannounced_ca:;
1419  *su_size = su_mem;
1420  *ce = ce_mem;
1421  return 0;
1422 }
1423 
1424 
1425 /* @param flag bit0= Do not add data but only count sua_free and ce_len
1426  param info may be NULL in this case
1427  bit1= account for crossing block boundaries
1428  (implied by bit0 == 0)
1429 */
1430 static
1432  size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
1433 {
1434  int ret;
1435  uint8_t *aapt;
1436  void *xipt;
1437  size_t num_aapt= 0;
1438 
1439  if (!t->opts->aaip)
1440  return 1;
1441 
1442  ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt);
1443  if (ret == 1) {
1444  num_aapt = aaip_count_bytes((unsigned char *) xipt, 0);
1445  if (num_aapt > 0) {
1446  if (flag & 1) {
1447  aapt = (unsigned char *) xipt;
1448  ret = aaip_add_AL(t, NULL, &aapt, num_aapt, sua_free, ce_len,
1449  base_ce, flag & (1 | 2));
1450  } else {
1451  aapt = malloc(num_aapt);
1452  if (aapt == NULL)
1453  return ISO_OUT_OF_MEM;
1454  memcpy(aapt, xipt, num_aapt);
1455  ret = aaip_add_AL(t, info, &aapt, num_aapt, sua_free, ce_len,
1456  base_ce, 0);
1457  /* aapt is NULL now and the memory is owned by t */
1458  }
1459  if (ret < 0)
1460  return ret;
1461  }
1462  }
1463  return 1;
1464 }
1465 
1466 
1467 /**
1468  * Compute the length needed for write all RR and SUSP entries for a given
1469  * node.
1470  *
1471  * @param type
1472  * 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
1473  * for that node (i.e., it will refer to the parent)
1474  * @param used_up
1475  * Already occupied space in the directory record.
1476  * @param ce
1477  * Will be filled with the space needed in a CE
1478  * @param base_ce
1479  * Predicted fill of continuation area by previous nodes of same dir
1480  * @return
1481  * The size needed for the RR entries in the System Use Area
1482  */
1483 size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up,
1484  size_t *ce, size_t base_ce)
1485 {
1486  size_t su_size, space;
1487  int ret;
1488  size_t aaip_sua_free= 0, aaip_len= 0;
1489 
1490  /* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
1491  */
1492  space = 254 - used_up - (used_up % 2);
1493  if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
1495  "Unknown node type %d or short RR space %d < %d in directory record",
1496  type, (int) space, ISO_ROCKRIDGE_IN_DIR_REC);
1497  return ISO_ASSERT_FAILURE;
1498  }
1499 
1500  *ce = 0;
1501  su_size = 0;
1502 
1503  /* If AAIP enabled and announced by ER : account for 5 bytes of ES */;
1504  if (t->opts->aaip && !t->opts->aaip_susp_1_10)
1505  su_size += 5;
1506 
1507 #ifdef Libisofs_with_rrip_rR
1508  /* obsolete RR field (once in RRIP-1.09) */
1509  su_size += 5;
1510 #endif
1511 
1512  /* PX and TF, we are sure they always fit in SUA */
1513  if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10) {
1514  su_size += 44 + 26;
1515  } else {
1516  su_size += 36 + 26;
1517  }
1518 
1519  if (n->type == ECMA119_DIR) {
1520  if (n->info.dir->real_parent != NULL) {
1521  /* it is a reallocated entry */
1522  if (type == 2) {
1523  /* we need to add a PL entry */
1524  su_size += 12;
1525  } else if (type == 0) {
1526  /* we need to add a RE entry */
1527  su_size += 4;
1528  }
1529  } else if(ecma119_is_dedicated_reloc_dir(t, n) &&
1530  (t->opts->rr_reloc_flags & 1)) {
1531  /* The dedicated relocation directory shall be marked by RE */
1532  su_size += 4;
1533  }
1534  } else if (n->type == ECMA119_SPECIAL) {
1535  if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
1536  /* block or char device, we need a PN entry */
1537  su_size += 20;
1538  }
1539  } else if (n->type == ECMA119_PLACEHOLDER) {
1540  /* we need the CL entry */
1541  su_size += 12;
1542  }
1543 
1544  if (type == 0) {
1545 
1546  /* Try without CE */
1547  ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 0);
1548  if (ret == 0) /* Retry with CE but no block crossing */
1549  ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1);
1550  if (ret == 0) /* Retry with aligned CE and block hopping */
1551  ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1 | 2);
1552  if (ret == -2)
1553  return ISO_OUT_OF_MEM;
1554 
1555  } else {
1556 
1557  /* "." or ".." entry */
1558 
1559  if (!t->opts->rrip_version_1_10)
1560  su_size += 5; /* NM field */
1561 
1562  if (type == 1 && n->parent == NULL) {
1563  /*
1564  * "." for root directory
1565  * we need to write SP and ER entries. The first fits in SUA,
1566  * ER needs a Continuation Area, thus we also need a CE entry
1567  */
1568  su_size += 7 + 28; /* SP + CE */
1569  /* ER of RRIP */
1570  if (t->opts->rrip_version_1_10) {
1571  *ce = 237;
1572  } else {
1573  *ce = 182;
1574  }
1575  if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
1576  *ce += 160; /* ER of AAIP */
1577  }
1578  /* Compute length of AAIP string of root node.
1579  Will write all AIIP to CA, which already starts at
1580  block boundary. So no need for three tries.
1581  */
1582  aaip_sua_free= 0;
1583  ret = add_aa_string(t, n, NULL, &aaip_sua_free, &aaip_len, base_ce,
1584  1 | 2);
1585  if (ret < 0)
1586  return ret;
1587  *ce += aaip_len;
1588  }
1589  }
1590 
1591  /*
1592  * The System Use field inside the directory record must be padded if
1593  * it is an odd number (ECMA-119, 9.1.13)
1594  */
1595  su_size += (su_size % 2);
1596  return su_size;
1597 }
1598 
1599 /**
1600  * Free all info in a struct susp_info.
1601  */
1602 static
1603 void susp_info_free(struct susp_info* susp)
1604 {
1605  size_t i;
1606 
1607  for (i = 0; i < susp->n_susp_fields; ++i) {
1608  free(susp->susp_fields[i]);
1609  }
1610  free(susp->susp_fields);
1611 
1612  for (i = 0; i < susp->n_ce_susp_fields; ++i) {
1613  free(susp->ce_susp_fields[i]);
1614  }
1615  free(susp->ce_susp_fields);
1616 }
1617 
1618 
1619 /**
1620  * Fill a struct susp_info with the RR/SUSP entries needed for a given
1621  * node.
1622  *
1623  * @param type
1624  * 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
1625  * for that node (i.e., it will refer to the parent)
1626  * @param used_up
1627  * Already occupied space in the directory record.
1628  * @param info
1629  * Pointer to the struct susp_info where the entries will be stored.
1630  * If some entries need to go to a Continuation Area, they will be added
1631  * to the existing ce_susp_fields, and ce_len will be incremented
1632  * properly. Please ensure ce_block is initialized properly.
1633  * @return
1634  * 1 success, < 0 error
1635  */
1637  size_t used_up, struct susp_info *info)
1638 {
1639  int ret;
1640  size_t i;
1641  Ecma119Node *node;
1642  char *name = NULL;
1643  char *dest = NULL;
1644  size_t aaip_er_len= 0;
1645  size_t rrip_er_len= 182;
1646  size_t su_size_pd, ce_len_pd; /* predicted sizes of SUA and CA */
1647  int ce_is_predicted = 0;
1648  size_t aaip_sua_free= 0, aaip_len= 0, ce_mem;
1649  int space;
1650 
1651  if (t == NULL || n == NULL || info == NULL) {
1652  return ISO_NULL_POINTER;
1653  }
1654 
1655  /* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
1656  */
1657  space = 254 - used_up - (used_up % 2);
1658  if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
1660  "Unknown node type %d or short RR space %d < %d in directory record",
1661  type, space, ISO_ROCKRIDGE_IN_DIR_REC);
1662  return ISO_ASSERT_FAILURE;
1663  }
1664 
1665  /* Mark start index of node's continuation area for later update */
1666  info->current_ce_start = info->n_ce_susp_fields;
1667  ce_mem = info->ce_len;
1668 
1669 #ifdef Libisofs_ce_calc_debug_filetraP
1670 
1671  if (n->node->name != NULL)
1672  if (strcmp(n->node->name, "...put.leafname.here...") == 0)
1673  fprintf(stderr, "libburn_DEBUG: filename breakpoint\n");
1674 
1675 #endif /* Libisofs_ce_calc_debug_filetraP */
1676 
1677  if (type == 2 && n->parent != NULL) {
1678  node = n->parent;
1679  } else {
1680  node = n;
1681  }
1682 
1683  /*
1684  * SP must be the first entry for the "." record of the root directory
1685  * (SUSP, 5.3)
1686  */
1687  if (type == 1 && n->parent == NULL) {
1688  ret = susp_add_SP(t, info);
1689  if (ret < 0) {
1690  goto add_susp_cleanup;
1691  }
1692  }
1693 
1694  /* If AAIP enabled and announced by ER : Announce RRIP by ES */
1695  if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
1696  ret = susp_add_ES(t, info, 0, 0);
1697  if (ret < 0)
1698  goto add_susp_cleanup;
1699  }
1700 
1701 #ifdef Libisofs_with_rrip_rR
1702  ret = rrip_add_RR(t, node, info);
1703  if (ret < 0) {
1704  goto add_susp_cleanup;
1705  }
1706 #endif /* Libisofs_with_rrip_rR */
1707 
1708  /* PX and TF, we are sure they always fit in SUA */
1709  ret = rrip_add_PX(t, node, info);
1710  if (ret < 0) {
1711  goto add_susp_cleanup;
1712  }
1713  ret = rrip_add_TF(t, node, info);
1714  if (ret < 0) {
1715  goto add_susp_cleanup;
1716  }
1717 
1718  if (n->type == ECMA119_DIR) {
1719  if (n->info.dir->real_parent != NULL) {
1720  /* it is a reallocated entry */
1721  if (type == 2) {
1722  /*
1723  * we need to add a PL entry
1724  * Note that we pass "n" as parameter, not "node"
1725  */
1726  ret = rrip_add_PL(t, n, info);
1727  if (ret < 0) {
1728  goto add_susp_cleanup;
1729  }
1730  } else if (type == 0) {
1731  /* we need to add a RE entry */
1732  ret = rrip_add_RE(t, node, info);
1733  if (ret < 0) {
1734  goto add_susp_cleanup;
1735  }
1736  }
1737  } else if(ecma119_is_dedicated_reloc_dir(t, n) &&
1738  (t->opts->rr_reloc_flags & 1)) {
1739  /* The dedicated relocation directory shall be marked by RE */
1740  ret = rrip_add_RE(t, node, info);
1741  if (ret < 0)
1742  goto add_susp_cleanup;
1743  }
1744  } else if (n->type == ECMA119_SPECIAL) {
1745  if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
1746  /* block or char device, we need a PN entry */
1747  ret = rrip_add_PN(t, node, info);
1748  if (ret < 0) {
1749  goto add_susp_cleanup;
1750  }
1751  }
1752  } else if (n->type == ECMA119_PLACEHOLDER) {
1753  /* we need the CL entry */
1754  ret = rrip_add_CL(t, node, info);
1755  if (ret < 0) {
1756  goto add_susp_cleanup;
1757  }
1758  }
1759 
1760  if (info->suf_len + 28 > space) {
1762  "Directory Record overflow. name='%s' , suf_len=%d > space=%d - 28\n",
1763  node->iso_name, (int) info->suf_len, space);
1764  return ISO_ASSERT_FAILURE;
1765  }
1766 
1767  if (type == 0) {
1768  size_t sua_free; /* free space in the SUA */
1769  int nm_type = 0; /* 0 whole entry in SUA, 1 part in CE */
1770  size_t ce_len = 0; /* len of the CE */
1771  size_t namelen;
1772 
1773  /* this two are only defined for symlinks */
1774  uint8_t **comps= NULL; /* components of the SL field */
1775  size_t n_comp = 0; /* number of components */
1776 
1777  namelen = 0;
1778  name = get_rr_fname(t, n->node->name);
1779  if (name == NULL)
1780  name = strdup("");
1781  if (name == NULL) {
1782  ret = ISO_OUT_OF_MEM;
1783  goto add_susp_cleanup;
1784  }
1785  namelen = strlen(name);
1786  sua_free = space - info->suf_len;
1787 
1788  /* Try whether NM, SL, AL will fit into SUA */
1789  su_size_pd = info->suf_len;
1790  ce_len_pd = ce_len;
1791  ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1792  &su_size_pd, &ce_len_pd, info->ce_len, 0);
1793  if (ret == 0) { /* Have to use CA. 28 bytes of CE are necessary */
1794  ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1795  &su_size_pd, &ce_len_pd, info->ce_len, 1);
1796  if (ret == 0) /* Retry with aligned CE and block hopping */
1797  ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1798  &su_size_pd, &ce_len_pd, info->ce_len,
1799  1 | 2);
1800  sua_free -= 28;
1801  ce_is_predicted = 1;
1802  }
1803  if (ret == -2) {
1804  ret = ISO_OUT_OF_MEM;
1805  goto add_susp_cleanup;
1806  }
1807 
1808  /* NM entry */
1809  if (5 + namelen <= sua_free) {
1810  /* ok, it fits in System Use Area */
1811  sua_free -= (5 + namelen);
1812  nm_type = 0;
1813  } else {
1814  /* the NM will be divided in a CE */
1815  nm_type = 1;
1816  namelen = namelen - (sua_free - 5);
1817  ce_len = 5 + namelen;
1818  sua_free = 0;
1819  }
1820  if (n->type == ECMA119_SYMLINK) {
1821  /*
1822  * for symlinks, we also need to write the SL
1823  */
1824  char *cur, *prev;
1825  size_t sl_len = 5;
1826  int cew = (nm_type == 1); /* are we writing to CE? */
1827 
1828  dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
1829  if (dest == NULL)
1830  dest = strdup("");
1831  if (dest == NULL) {
1832  ret = ISO_OUT_OF_MEM;
1833  goto add_susp_cleanup;
1834  }
1835 
1836  prev = dest;
1837  cur = strchr(prev, '/');
1838  while (1) {
1839  size_t clen;
1840  char cflag = 0; /* component flag (RRIP, 4.1.3.1) */
1841  if (cur) {
1842  clen = cur - prev;
1843  } else {
1844  /* last component */
1845  clen = strlen(prev);
1846  }
1847 
1848  if (clen == 0) {
1849  /* this refers to the roor directory, '/' */
1850  cflag = 1 << 3;
1851  }
1852  if (clen == 1 && prev[0] == '.') {
1853  clen = 0;
1854  cflag = 1 << 1;
1855  } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
1856  clen = 0;
1857  cflag = 1 << 2;
1858  }
1859 
1860  /* flags and len for each component record (RRIP, 4.1.3.1) */
1861  clen += 2;
1862 
1863  if (!cew) {
1864  /* we are still writing to the SUA */
1865  if (sl_len + clen > sua_free) {
1866  /*
1867  * ok, we need a Continuation Area anyway
1868  * TODO this can be handled better, but for now SL
1869  * will be completely moved into the CA
1870  */
1871 
1872  /* sua_free, ce_len, nm_type already account for CE */
1873  cew = 1;
1874 
1875  } else {
1876  /* add the component */
1877  ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1878  clen - 2, cflag);
1879  if (ret < 0) {
1880  goto add_susp_cleanup;
1881  }
1882  sl_len += clen;
1883  }
1884  }
1885  if (cew) {
1886  if (sl_len + clen > 255) {
1887  /* we need an addition SL entry */
1888  if (clen > 250) {
1889  /*
1890  * case 1, component too large to fit in a
1891  * single SL entry. Thus, the component need
1892  * to be divided anyway.
1893  * Note than clen can be up to 255 + 2 = 257.
1894  *
1895  * First, we check how many bytes fit in current
1896  * SL field
1897  */
1898  ssize_t fit = 255 - sl_len - 2;
1899  if ((ssize_t) (clen - 250) <= fit) {
1900  /*
1901  * the component can be divided between this
1902  * and another SL entry
1903  */
1904  ret = rrip_SL_append_comp(&n_comp, &comps,
1905  prev, fit, 0x01);
1906  if (ret < 0) {
1907  goto add_susp_cleanup;
1908  }
1909  /*
1910  * and another component, that will go in
1911  * other SL entry
1912  */
1913  ret = rrip_SL_append_comp(&n_comp, &comps, prev
1914  + fit, clen - fit - 2, 0);
1915  if (ret < 0) {
1916  goto add_susp_cleanup;
1917  }
1918  ce_len += 255; /* this SL, full */
1919  sl_len = 5 + (clen - fit);
1920  } else {
1921  /*
1922  * the component will need a 2rd SL entry in
1923  * any case, so we prefer to don't write
1924  * anything in this SL
1925  */
1926  ret = rrip_SL_append_comp(&n_comp, &comps,
1927  prev, 248, 0x01);
1928  if (ret < 0) {
1929  goto add_susp_cleanup;
1930  }
1931  ret = rrip_SL_append_comp(&n_comp, &comps, prev
1932  + 248, strlen(prev + 248), 0x00);
1933  if (ret < 0) {
1934  goto add_susp_cleanup;
1935  }
1936  ce_len += sl_len + 255;
1937  sl_len = 5 + (clen - 250) + 2;
1938  }
1939  } else {
1940  /* case 2, create a new SL entry */
1941  ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1942  clen - 2, cflag);
1943  if (ret < 0) {
1944  goto add_susp_cleanup;
1945  }
1946  ce_len += sl_len;
1947  sl_len = 5 + clen;
1948  }
1949  } else {
1950  /* the component fit in the SL entry */
1951  ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1952  clen - 2, cflag);
1953  if (ret < 0) {
1954  goto add_susp_cleanup;
1955  }
1956  sl_len += clen;
1957  }
1958  }
1959 
1960  if (!cur || cur[1] == '\0') {
1961  /* cur[1] can be \0 if dest ends with '/' */
1962  break;
1963  }
1964  prev = cur + 1;
1965  cur = strchr(prev, '/');
1966  }
1967 
1968  if (cew) {
1969  ce_len += sl_len;
1970  }
1971  }
1972 
1973  /*
1974  * We we reach here:
1975  * - We know if NM fill in the SUA (nm_type == 0)
1976  * - If SL needs an to be written in CE (ce_len > 0)
1977  * - The components for SL entry (or entries)
1978  */
1979 
1980  if (nm_type == 0) {
1981  /* the full NM fills in SUA */
1982  ret = rrip_add_NM(t, info, name, strlen(name), 0, 0);
1983  if (ret < 0) {
1984  goto add_susp_cleanup;
1985  }
1986  } else {
1987  /*
1988  * Write the NM part that fits in SUA... Note that CE
1989  * entry and NM in the continuation area is added below
1990  */
1991 
1992  namelen = space - info->suf_len - 28 * (!!ce_is_predicted) - 5;
1993  ret = rrip_add_NM(t, info, name, namelen, 1, 0);
1994  if (ret < 0) {
1995  goto add_susp_cleanup;
1996  }
1997  }
1998 
1999  if (ce_is_predicted) {
2000  if ((info->ce_len % BLOCK_SIZE) &&
2001  (info->ce_len + ce_len_pd - 1 ) / BLOCK_SIZE !=
2002  info->ce_len / BLOCK_SIZE) {
2003  /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE
2004  * Insert padding to shift CE offset to next block start
2005  */
2006 
2007 #ifdef Libisofs_ce_calc_debuG
2008 
2009  fprintf(stderr,
2010  "\nlibburn_DEBUG: Inserting %d bytes of CE padding : %s\n\n",
2011  (int) (BLOCK_SIZE - (info->ce_len % BLOCK_SIZE)),
2012  n->node->name);
2013 
2014 #endif /* Libisofs_ce_calc_debuG */
2015 
2016  ret = pseudo_susp_add_PAD(t, info);
2017  if (ret < 0)
2018  goto add_susp_cleanup;
2019  }
2020  /* Add the CE entry */
2021  ret = susp_add_CE(t, ce_len_pd, info);
2022  if (ret < 0) {
2023  goto add_susp_cleanup;
2024  }
2025  }
2026 
2027  if (nm_type == 1) {
2028  /*
2029  * ..and the part that goes to continuation area.
2030  */
2031 
2032  /* >>> SUPER_LONG_RR : Need a loop to handle CA lengths > 250
2033  (This cannot happen with name lengths <= 256, as a part
2034  of the name will always fit into the directory entry.)
2035  */;
2036 
2037  ret = rrip_add_NM(t, info, name + namelen, strlen(name + namelen),
2038  0, 1);
2039  if (ret < 0) {
2040  goto add_susp_cleanup;
2041  }
2042  }
2043 
2044  if (n->type == ECMA119_SYMLINK) {
2045 
2046  /* add the SL entry (or entries) */
2047  ret = rrip_add_SL(t, info, comps, n_comp, (ce_len > 0));
2048 
2049  /* free the components */
2050  for (i = 0; i < n_comp; i++) {
2051  free(comps[i]);
2052  }
2053  free(comps);
2054 
2055  if (ret < 0) {
2056  goto add_susp_cleanup;
2057  }
2058  }
2059 
2060  /* Eventually write zisofs ZF field */
2061  ret = add_zf_field(t, n, info, &sua_free, &ce_len, ce_mem, 0);
2062  if (ret < 0)
2063  goto add_susp_cleanup;
2064 
2065  /* Eventually obtain AAIP field string from node
2066  and write it to directory entry or CE area.
2067  */
2068  ret = add_aa_string(t, n, info, &sua_free, &ce_len, ce_mem, 0);
2069  if (ret < 0)
2070  goto add_susp_cleanup;
2071 
2072 
2073  } else {
2074 
2075  /* "." or ".." entry */
2076 
2077  /* write the NM entry */
2078  if (t->opts->rrip_version_1_10) {
2079  /* RRIP-1.10:
2080  "NM" System Use Fields recorded for the ISO 9660 directory
2081  records with names (00) and (01), used to designate the
2082  current and parent directories, respectively, should be
2083  ignored. Instead, the receiving system should convert these
2084  names to the appropriate receiving system-dependent
2085  designations for the current and parent directories.
2086  */
2087  /* mkisofs obviously writes no NM for '.' and '..' .
2088  Program isoinfo shows empty names with records as of RRIP-1.12
2089  */
2090  /* no op */;
2091  } else {
2092  /* RRIP-1.12:
2093  If the ISO 9660 Directory Record File Identifier is (00), then
2094  the CURRENT bit of the "NM" Flags field [...], if present, shall
2095  be set to ONE. If the ISO 9660 Directory Record File Identifier
2096  is (01), then the PARENT bit of the "NM" Flags field [...],
2097  if present, shall be set to ONE.
2098  [...]
2099  "BP 3 - Length (LEN_NM)" shall specify as an 8-bit number the
2100  length in bytes [...]. If bit position 1, 2, or 5 of the "NM"
2101  Flags is set to ONE, the value of this field shall be 5 and no
2102  Name Content shall be recorded.
2103  [The CURRENT bit has position 1. The PARENT bit has position 2.]
2104  */
2105  ret = rrip_add_NM(t, info, NULL, 0, 1 << type, 0);
2106  if (ret < 0)
2107  goto add_susp_cleanup;
2108  }
2109 
2110  if (type == 1 && n->parent == NULL) {
2111  /*
2112  * "." for root directory
2113  * we need to write SP and ER entries. The first fits in SUA,
2114  * ER needs a Continuation Area, thus we also need a CE entry.
2115  * Note that SP entry was already added above
2116  */
2117 
2118  if (t->opts->rrip_version_1_10) {
2119  rrip_er_len = 237;
2120  } else {
2121  rrip_er_len = 182;
2122  }
2123  if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
2124  aaip_er_len = 160;
2125  }
2126 
2127  /* Compute length of AAIP string of root node */
2128  aaip_sua_free= 0;
2129  ret = add_aa_string(t, n, NULL, &aaip_sua_free, &aaip_len, ce_mem,
2130  1 | 2);
2131  if (ret < 0)
2132  goto add_susp_cleanup;
2133 
2134  /* Allocate the necessary CE space */
2135  ret = susp_add_CE(t, rrip_er_len + aaip_er_len + aaip_len, info);
2136  if (ret < 0) {
2137  goto add_susp_cleanup;
2138  }
2139  ret = rrip_add_ER(t, info);
2140  if (ret < 0) {
2141  goto add_susp_cleanup;
2142  }
2143  if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
2144  ret = aaip_add_ER(t, info, 0);
2145  if (ret < 0) {
2146  goto add_susp_cleanup;
2147  }
2148  }
2149  /* Write AAIP string of root node */
2150  aaip_sua_free= aaip_len= 0;
2151  ret = add_aa_string(t, n, info, &aaip_sua_free, &aaip_len, ce_mem,
2152  0);
2153  if (ret < 0)
2154  goto add_susp_cleanup;
2155 
2156  }
2157  }
2158 
2159 
2160  /*
2161  * The System Use field inside the directory record must be padded if
2162  * it is an odd number (ECMA-119, 9.1.13)
2163  */
2164  info->suf_len += (info->suf_len % 2);
2165 
2166  free(name);
2167  free(dest);
2168  return ISO_SUCCESS;
2169 
2170  add_susp_cleanup: ;
2171  if (name != NULL)
2172  free(name);
2173  if (dest != NULL)
2174  free(dest);
2175  susp_info_free(info);
2176  return ret;
2177 }
2178 
2179 
2180 /* Update the sizes of CE fields at end of info->susp_fields and in
2181  single node range of info->ce_susp_fields.
2182 */
2183 static
2184 int susp_update_CE_sizes(Ecma119Image *t, struct susp_info *info, int flag)
2185 {
2186  size_t i, curr_pos;
2187  uint8_t *curr_ce;
2188  uint32_t size;
2189 
2190  if (info->n_susp_fields == 0 ||
2191  info->n_ce_susp_fields - info->current_ce_start == 0)
2192  return ISO_SUCCESS;
2193 
2194  for (i = 0; i < info->n_susp_fields; i++)
2195  if (info->susp_fields[i][0] == 'C')
2196  if(info->susp_fields[i][1] == 'E')
2197  break;
2198  if (i >= info->n_susp_fields) {
2200  "System Use Area field contains no CE, but there are fields in Continuation Area");
2201  return ISO_ASSERT_FAILURE;
2202  }
2203  curr_ce = info->susp_fields[i];
2204  curr_pos = 0;
2205  for (i = info->current_ce_start; i < info->n_ce_susp_fields; i++) {
2206  if (info->ce_susp_fields[i][0] == 0) {
2207  curr_pos = 0; /* pseudo SUSP PAD */
2208  continue;
2209  }
2210  if (info->ce_susp_fields[i][0] == 'C' &&
2211  info->ce_susp_fields[i][1] == 'E') {
2212  size = (curr_pos + info->ce_susp_fields[i][2]) % BLOCK_SIZE;
2213  if (size == 0)
2214  size = BLOCK_SIZE;
2215  iso_bb(curr_ce + 20, size, 4);
2216  curr_ce = info->ce_susp_fields[i];
2217  }
2218  curr_pos = (curr_pos + info->ce_susp_fields[i][2]) % 2048;
2219  }
2220  if (curr_pos > 0) {
2221  size = curr_pos % BLOCK_SIZE;
2222  iso_bb(curr_ce + 20, size, 4);
2223  }
2224  return ISO_SUCCESS;
2225 }
2226 
2227 
2228 /**
2229  * Write the given SUSP fields into buf. Note that Continuation Area
2230  * fields are not written.
2231  * If info does not contain any SUSP entry this function just return.
2232  * After written, the info susp_fields array will be freed, and the counters
2233  * updated properly.
2234  */
2236  uint8_t *buf)
2237 {
2238  size_t i;
2239  size_t pos = 0;
2240  int ret;
2241 
2242  if (info->n_susp_fields == 0) {
2243  return;
2244  }
2245 
2246  ret = susp_update_CE_sizes(t, info, 0);
2247  if (ret < 0)
2248  return;
2249 
2250  for (i = 0; i < info->n_susp_fields; i++) {
2251  memcpy(buf + pos, info->susp_fields[i], info->susp_fields[i][2]);
2252  pos += info->susp_fields[i][2];
2253  }
2254 
2255  /* free susp_fields */
2256  for (i = 0; i < info->n_susp_fields; ++i) {
2257  free(info->susp_fields[i]);
2258  }
2259  free(info->susp_fields);
2260  info->susp_fields = NULL;
2261  info->n_susp_fields = 0;
2262  info->suf_len = 0;
2263 }
2264 
2265 /**
2266  * Write the Continuation Area entries for the given struct susp_info, using
2267  * the iso_write() function.
2268  * After written, the ce_susp_fields array will be freed.
2269  */
2271 {
2272  size_t i;
2273  uint8_t *padding = NULL;
2274  int ret= ISO_SUCCESS;
2275  uint64_t written = 0, pad_size;
2276 
2277  if (info->n_ce_susp_fields == 0) {
2278  goto ex;
2279  }
2280  LIBISO_ALLOC_MEM(padding, uint8_t, BLOCK_SIZE);
2281 
2282  for (i = 0; i < info->n_ce_susp_fields; i++) {
2283  if (info->ce_susp_fields[i][0] == 0) {
2284  /* Pseudo field: pad up to next block boundary */
2285  pad_size = BLOCK_SIZE - (written % BLOCK_SIZE);
2286  if (pad_size == BLOCK_SIZE)
2287  continue;
2288  memset(padding, 0, pad_size);
2289  ret = iso_write(t, padding, pad_size);
2290  if (ret < 0)
2291  goto write_ce_field_cleanup;
2292  written += pad_size;
2293  continue;
2294  }
2295  ret = iso_write(t, info->ce_susp_fields[i],
2296  info->ce_susp_fields[i][2]);
2297  if (ret < 0) {
2298  goto write_ce_field_cleanup;
2299  }
2300  written += info->ce_susp_fields[i][2];
2301  }
2302 
2303  /* pad continuation area until block size */
2304  i = BLOCK_SIZE - (info->ce_len % BLOCK_SIZE);
2305  if (i > 0 && i < BLOCK_SIZE) {
2306  memset(padding, 0, i);
2307  ret = iso_write(t, padding, i);
2308  if (ret < 0)
2309  goto write_ce_field_cleanup;
2310  written += i;
2311  }
2312 
2313  write_ce_field_cleanup: ;
2314  /* free ce_susp_fields */
2315  for (i = 0; i < info->n_ce_susp_fields; ++i) {
2316  free(info->ce_susp_fields[i]);
2317  }
2318  free(info->ce_susp_fields);
2319  info->ce_susp_fields = NULL;
2320  info->n_ce_susp_fields = 0;
2321  info->alloc_ce_susp_fields = 0;
2322  info->ce_len = 0;
2323 ex:;
2324  LIBISO_FREE_MEM(padding);
2325  return ret;
2326 }
2327 
size_t aaip_count_bytes(unsigned char *data, int flag)
Definition: aaip_0_2.c:966
#define BLOCK_SIZE
Definition: buffer.h:23
int iso_write(Ecma119Image *target, void *buf, size_t count)
Definition: ecma119.c:3471
int ecma119_is_dedicated_reloc_dir(Ecma119Image *img, Ecma119Node *node)
Definition: ecma119_tree.c:170
@ ECMA119_PLACEHOLDER
Definition: ecma119_tree.h:22
@ ECMA119_DIR
Definition: ecma119_tree.h:19
@ ECMA119_SPECIAL
Definition: ecma119_tree.h:21
@ ECMA119_SYMLINK
Definition: ecma119_tree.h:20
static uint32_t block_offset(int nsections, struct iso_file_section *sections, off_t offset)
Definition: fs_image.c:862
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
int iso_clone_mem(char *in, char **out, size_t size)
Definition: util.c:2336
void iso_lsb64(uint8_t *buf, uint64_t num)
Definition: util.c:1486
int strconv(const char *str, const char *icharset, const char *ocharset, char **output)
Definition: util.c:192
#define LIBISO_FREE_MEM(pt)
Definition: util.h:627
#define LIBISO_ALLOC_MEM(pt, typ, count)
Definition: util.h:615
IsoStream * iso_file_get_stream(IsoFile *file)
Definition: node.c:1161
#define ISO_SUCCESS
Definition: libisofs.h:8719
@ LIBISO_FILE
Definition: libisofs.h:230
@ LIBISO_SPECIAL
Definition: libisofs.h:232
IsoStream * iso_stream_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:867
#define ISO_OUT_OF_MEM
Definition: libisofs.h:8745
int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data)
Definition: node.c:213
#define ISO_ZISOFS_TOO_LARGE
Definition: libisofs.h:8959
#define ISO_AAIP_BAD_AASTRING
Definition: libisofs.h:8939
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
enum IsoNodeType iso_node_get_type(IsoNode *node)
Definition: node.c:321
#define ISO_FILENAME_WRONG_CHARSET
Definition: libisofs.h:8841
#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
int zisofs_zf_xinfo_func(void *data, int flag)
Definition: node.c:2411
static int rrip_SL_append_comp(size_t *n, uint8_t ***comps, char *s, int size, char fl)
Definition: rockridge.c:465
static int rrip_add_NM(Ecma119Image *t, struct susp_info *susp, char *name, int size, int flags, int ce)
Definition: rockridge.c:420
static int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
Definition: rockridge.c:1431
static int pseudo_susp_add_PAD(Ecma119Image *t, struct susp_info *susp)
Definition: rockridge.c:938
int aaip_xinfo_cloner(void *old_data, void **new_data, int flag)
Definition: rockridge.c:1127
static int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:243
static int rrip_add_TF(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:208
static int rrip_add_RE(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:278
static int aaip_add_AL(Ecma119Image *t, struct susp_info *susp, uint8_t **data, size_t num_data, size_t *sua_free, size_t *ce_len, size_t ce_mem, int flag)
Definition: rockridge.c:647
static int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, uint8_t **comp, size_t n, int ce)
Definition: rockridge.c:543
static int susp_append_ce(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
Definition: rockridge.c:61
static mode_t px_get_mode(Ecma119Image *t, Ecma119Node *n)
Definition: rockridge.c:157
static int susp_calc_add_to_ce(size_t *ce, size_t base_ce, int add, int flag)
Definition: rockridge.c:621
size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, size_t *ce, size_t base_ce)
Definition: rockridge.c:1483
int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, struct susp_info *info)
Definition: rockridge.c:1636
static int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp)
Definition: rockridge.c:864
static int susp_update_CE_sizes(Ecma119Image *t, struct susp_info *info, int flag)
Definition: rockridge.c:2184
static void susp_info_free(struct susp_info *susp)
Definition: rockridge.c:1603
static int susp_append(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
Definition: rockridge.c:47
static int zisofs_add_ZF(Ecma119Image *t, struct susp_info *susp, int to_ce, uint8_t algo[2], int header_size_div4, int block_size_log2, uint64_t uncompressed_size, int flag)
Definition: rockridge.c:959
static uid_t px_get_uid(Ecma119Image *t, Ecma119Node *n)
Definition: rockridge.c:137
static int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:177
static int susp_add_SP(Ecma119Image *t, struct susp_info *susp)
Definition: rockridge.c:887
static int rrip_add_ER(Ecma119Image *t, struct susp_info *susp)
Definition: rockridge.c:726
static int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, size_t *su_size, size_t *ce, size_t base_ce, int flag)
Definition: rockridge.c:1165
int aaip_xinfo_func(void *data, int flag)
Definition: rockridge.c:1118
int iso_get_rr_name(IsoWriteOpts *opts, char *input_charset, char *output_charset, int imgid, char *str, char **name, int flag)
Definition: rockridge.c:367
int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info)
Definition: rockridge.c:2270
static int aaip_add_ER(Ecma119Image *t, struct susp_info *susp, int flag)
Definition: rockridge.c:799
#define ISO_ROCKRIDGE_IN_DIR_REC
Definition: rockridge.c:32
static int rrip_add_PN(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:300
#define ISO_CE_ENTRY_SIZE
Definition: rockridge.c:35
static int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
Definition: rockridge.c:341
void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info, uint8_t *buf)
Definition: rockridge.c:2235
static int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno)
Definition: rockridge.c:913
static uid_t px_get_gid(Ecma119Image *t, Ecma119Node *n)
Definition: rockridge.c:147
static int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
Definition: rockridge.c:1005
static int susp_make_CE(Ecma119Image *t, uint8_t **CE, uint32_t block_offset, uint32_t byte_offset, uint32_t size)
Definition: rockridge.c:834
static char * get_rr_fname(Ecma119Image *t, char *str)
Definition: rockridge.c:394
#define ISO_SUSP_CE_ALLOC_STEP
Definition: rockridge.h:79
int iso_stream_get_src_zf(IsoStream *stream, uint8_t zisofs_algo[2], int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: stream.c:293
Definition: node.h:149
unsigned int from_old_session
Definition: node.h:155
int id
Definition: image.h:97
Definition: node.h:100
gid_t gid
Definition: node.h:117
time_t ctime
Definition: node.h:122
uid_t uid
Definition: node.h:116
char * name
Definition: node.h:113
time_t atime
Definition: node.h:120
enum IsoNodeType type
Definition: node.h:111
mode_t mode
Definition: node.h:115
time_t mtime
Definition: node.h:121
dev_t dev
Definition: node.h:187
IsoNode node
Definition: node.h:186
Ecma119Node * real_parent
Definition: ecma119_tree.h:48
IsoImage * image
Definition: ecma119.h:560
mode_t file_mode
Definition: ecma119.h:586
IsoWriteOpts * opts
Definition: ecma119.h:563
mode_t dir_mode
Definition: ecma119.h:587
gid_t gid
Definition: ecma119.h:585
unsigned int replace_timestamps
Definition: ecma119.h:581
char * output_charset
Definition: ecma119.h:592
char * input_charset
Definition: ecma119.h:591
uid_t uid
Definition: ecma119.h:584
unsigned int replace_dir_mode
Definition: ecma119.h:580
unsigned int replace_gid
Definition: ecma119.h:578
time_t timestamp
Definition: ecma119.h:588
unsigned int replace_uid
Definition: ecma119.h:577
uint32_t eff_partition_offset
Definition: ecma119.h:794
unsigned int replace_file_mode
Definition: ecma119.h:579
union ecma119_node::@0 info
uint32_t ino
Definition: ecma119_tree.h:67
nlink_t nlink
Definition: ecma119_tree.h:69
char * iso_name
Definition: ecma119_tree.h:61
IsoNode * node
Definition: ecma119_tree.h:65
Ecma119Node * real_me
Definition: ecma119_tree.h:78
Ecma119Node * parent
Definition: ecma119_tree.h:63
struct ecma119_dir_info * dir
Definition: ecma119_tree.h:76
enum ecma119_node_type type
Definition: ecma119_tree.h:72
unsigned int aaip_susp_1_10
Definition: ecma119.h:234
unsigned int rrip_version_1_10
Definition: ecma119.h:211
unsigned int rrip_1_10_px_ino
Definition: ecma119.h:216
int rr_reloc_flags
Definition: ecma119.h:259
unsigned int always_gmt
Definition: ecma119.h:115
unsigned int appendable
Definition: ecma119.h:364
unsigned int aaip
Definition: ecma119.h:112
uint8_t ** ce_susp_fields
Definition: rockridge.h:68
size_t n_ce_susp_fields
Definition: rockridge.h:67
size_t n_susp_fields
Definition: rockridge.h:56
uint32_t ce_block
Definition: rockridge.h:63
uint32_t ce_len
Definition: rockridge.h:64
size_t alloc_ce_susp_fields
Definition: rockridge.h:71
size_t current_ce_start
Definition: rockridge.h:74
uint8_t ** susp_fields
Definition: rockridge.h:57
int suf_len
Definition: rockridge.h:60
uint8_t header_size_div4
Definition: node.h:441
uint8_t block_size_log2
Definition: node.h:442
uint8_t zisofs_algo[2]
Definition: node.h:443
uint64_t uncompressed_size
Definition: node.h:440
int iso_zisofs2_enable_susp_z2
Definition: zisofs.c:118
int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type, uint8_t zisofs_algo[2], int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: zisofs.c:1601