"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/rockridge.c" (7 Feb 2021, 72476 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rockridge.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    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
  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
  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
  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
  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
  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
  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
  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
  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
  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  */
  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
  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
  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
  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
  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
 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 */
 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
 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
 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  */
 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
 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  */
 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
 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  */
 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  */
 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