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
susp_append(Ecma119Image * t,struct susp_info * susp,uint8_t * data)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
susp_append_ce(Ecma119Image * t,struct susp_info * susp,uint8_t * data)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
px_get_uid(Ecma119Image * t,Ecma119Node * n)137 uid_t px_get_uid(Ecma119Image *t, Ecma119Node *n)
138 {
139     if (t->replace_uid) {
140         return t->uid;
141     } else {
142         return n->node->uid;
143     }
144 }
145 
146 static
px_get_gid(Ecma119Image * t,Ecma119Node * n)147 uid_t px_get_gid(Ecma119Image *t, Ecma119Node *n)
148 {
149     if (t->replace_gid) {
150         return t->gid;
151     } else {
152         return n->node->gid;
153     }
154 }
155 
156 static
px_get_mode(Ecma119Image * t,Ecma119Node * n)157 mode_t px_get_mode(Ecma119Image *t, Ecma119Node *n)
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
rrip_add_PX(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)177 int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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
rrip_add_TF(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)208 int rrip_add_TF(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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
rrip_add_PL(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)243 int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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],
264        n->info.dir->real_parent->info.dir->block - t->eff_partition_offset, 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
rrip_add_RE(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)278 int rrip_add_RE(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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
rrip_add_PN(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)300 int rrip_add_PN(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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
rrip_add_CL(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)341 int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
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;
357     iso_bb(&CL[4], n->info.real_me->info.dir->block - t->eff_partition_offset,
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  */
iso_get_rr_name(IsoWriteOpts * opts,char * input_charset,char * output_charset,int imgid,char * str,char ** name,int flag)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))
383             iso_msg_submit(imgid, ISO_FILENAME_WRONG_CHARSET, ret,
384                    "Charset conversion error. Cannot convert %s from %s to %s",
385                    str, input_charset, output_charset);
386         *name = NULL;
387         return ISO_FILENAME_WRONG_CHARSET;
388     }
389 
390     return ISO_SUCCESS;
391 }
392 
393 static
get_rr_fname(Ecma119Image * t,char * str)394 char *get_rr_fname(Ecma119Image *t, char *str)
395 {
396     int ret;
397     char *name = NULL;
398 
399     ret = iso_get_rr_name(t->opts, t->input_charset, t->output_charset,
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
rrip_add_NM(Ecma119Image * t,struct susp_info * susp,char * name,int size,int flags,int ce)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
rrip_SL_append_comp(size_t * n,uint8_t *** comps,char * s,int size,char fl)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
rrip_add_RR(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)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
rrip_add_SL(Ecma119Image * t,struct susp_info * susp,uint8_t ** comp,size_t n,int ce)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
susp_calc_add_to_ce(size_t * ce,size_t base_ce,int add,int flag)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
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)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
rrip_add_ER(Ecma119Image * t,struct susp_info * susp)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
aaip_add_ER(Ecma119Image * t,struct susp_info * susp,int flag)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
susp_make_CE(Ecma119Image * t,uint8_t ** CE,uint32_t block_offset,uint32_t byte_offset,uint32_t size)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
susp_add_CE(Ecma119Image * t,size_t ce_len,struct susp_info * susp)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
susp_add_SP(Ecma119Image * t,struct susp_info * susp)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
susp_add_ES(Ecma119Image * t,struct susp_info * susp,int to_ce,int seqno)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
pseudo_susp_add_PAD(Ecma119Image * t,struct susp_info * susp)938 int pseudo_susp_add_PAD(Ecma119Image *t, struct susp_info *susp)
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
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)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;
978         if (iso_zisofs2_enable_susp_z2)
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
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)1005 int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
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,
1066                                 &block_size_log2, &uncompressed_size, 0);
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,
1077                                     &block_size_log2, &uncompressed_size, 0);
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 */
1083         ret = iso_node_get_xinfo((IsoNode *) file, zisofs_zf_xinfo_func,
1084                                  &xipt);
1085         if (ret == 1) {
1086             zf = xipt;
1087             header_size_div4 = zf->header_size_div4;
1088             block_size_log2 = zf->block_size_log2;
1089             uncompressed_size = zf->uncompressed_size;
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,
1111                        block_size_log2, uncompressed_size, 0);
1112     if (ret < 0)
1113         return ret;
1114     return 1;
1115 }
1116 
1117 /* API */
aaip_xinfo_func(void * data,int flag)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 */
aaip_xinfo_cloner(void * old_data,void ** new_data,int flag)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
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)1165 int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space,
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
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)1431 int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
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  */
rrip_calc_len(Ecma119Image * t,Ecma119Node * n,int type,size_t used_up,size_t * ce,size_t base_ce)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) {
1494         iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
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
susp_info_free(struct susp_info * susp)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  */
rrip_get_susp_fields(Ecma119Image * t,Ecma119Node * n,int type,size_t used_up,struct susp_info * info)1636 int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
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) {
1659         iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
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) {
1761         iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
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
susp_update_CE_sizes(Ecma119Image * t,struct susp_info * info,int flag)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) {
2199         iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
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  */
rrip_write_susp_fields(Ecma119Image * t,struct susp_info * info,uint8_t * buf)2235 void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info,
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  */
rrip_write_ce_fields(Ecma119Image * t,struct susp_info * info)2270 int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info)
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 
2328