"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/joliet.c" (30 Jan 2021, 37918 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.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 "joliet.c" see the Fossies "Dox" file reference documentation and the last 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) 2011-2018 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 "joliet.h"
   17 #include "messages.h"
   18 #include "writer.h"
   19 #include "image.h"
   20 #include "filesrc.h"
   21 #include "eltorito.h"
   22 #include "libisofs.h"
   23 #include "util.h"
   24 #include "ecma119.h"
   25 
   26 
   27 #include <stdlib.h>
   28 #include <stdio.h>
   29 #include <string.h>
   30 
   31 /* @param flag   bit0=  Do not issue error messages
   32 */
   33 int iso_get_joliet_name(IsoWriteOpts *opts, char *input_charset, int imgid,
   34                         char *node_name, enum IsoNodeType node_type,
   35                         size_t *joliet_ucs2_failures,
   36                         uint16_t **name, int flag)
   37 {
   38     int ret = ISO_SUCCESS;
   39     uint16_t *ucs_name = NULL, *utf16_name = NULL;
   40     uint16_t *jname = NULL;
   41 
   42     if (node_name == NULL) {
   43         /* it is not necessarily an error, it can be the root */
   44         *name = NULL;
   45         return ISO_SUCCESS;
   46     }
   47 
   48     if (opts->joliet_utf16) {
   49         ret = str2utf16be(input_charset, node_name, &ucs_name);
   50         if (ret < 0) {
   51             if (!(flag & 512))
   52                 iso_msg_debug(imgid, "Cannot convert to UTF-16 : \"%s\"",
   53                               node_name);
   54             goto ex;
   55         }
   56     } else {
   57         ret = str2ucs(input_charset, node_name, &ucs_name);
   58         if (ret < 0) {
   59             if (!(flag & 512))
   60                 iso_msg_debug(imgid, "Cannot convert to UCS-2 : \"%s\"",
   61                               node_name);
   62             goto ex;
   63         }
   64         ret = str2utf16be(input_charset, node_name, &utf16_name);
   65         if (ret == ISO_SUCCESS) {
   66             if (ucscmp(ucs_name, utf16_name) != 0) {
   67                 (*joliet_ucs2_failures)++;
   68                 if (*joliet_ucs2_failures <= ISO_JOLIET_UCS2_WARN_MAX &&
   69                     !(flag & 512)) {
   70                     iso_msg_submit(imgid, ISO_NAME_NOT_UCS2, 0,
   71                "Filename not suitable for Joliet character set UCS-2 : \"%s\"",
   72                                    node_name);
   73                 }
   74             }
   75         }
   76     }
   77     if (node_type == LIBISO_DIR) {
   78         jname = iso_j_dir_id(ucs_name, opts->joliet_long_names << 1);
   79     } else {
   80         jname = iso_j_file_id(ucs_name,
   81                  (opts->joliet_long_names << 1) | !!(opts->no_force_dots & 2));
   82     }
   83     ret = ISO_SUCCESS;
   84 ex:;
   85     if (ucs_name != NULL)
   86         free(ucs_name);
   87     if (utf16_name != NULL)
   88         free(utf16_name);
   89     if (ret != ISO_SUCCESS) {
   90         if (jname != NULL)
   91             free(jname);
   92         return ret;
   93     } else if (jname != NULL) {
   94         *name = jname;
   95         return ISO_SUCCESS;
   96     } else {
   97         /*
   98          * only possible if mem error, as check for empty names is done
   99          * in public tree
  100          */
  101         return ISO_OUT_OF_MEM;
  102     }
  103 }
  104 
  105 static
  106 int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
  107 {
  108     int ret;
  109 
  110     ret = iso_get_joliet_name(t->opts, t->input_charset, t->image->id,
  111                               iso->name, iso->type, &(t->joliet_ucs2_failures),
  112                               name, 0);
  113 
  114     return ret;
  115 }
  116 
  117 
  118 static
  119 void joliet_node_free(JolietNode *node)
  120 {
  121     if (node == NULL) {
  122         return;
  123     }
  124     if (node->type == JOLIET_DIR) {
  125         size_t i;
  126         for (i = 0; i < node->info.dir->nchildren; i++) {
  127             joliet_node_free(node->info.dir->children[i]);
  128         }
  129         if (node->info.dir->children != NULL)
  130             free(node->info.dir->children);
  131         free(node->info.dir);
  132     }
  133     iso_node_unref(node->node);
  134     free(node->name);
  135     free(node);
  136 }
  137 
  138 /**
  139  * Create a low level Joliet node
  140  * @return
  141  *      1 success, 0 ignored, < 0 error
  142  */
  143 static
  144 int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
  145 {
  146     int ret;
  147     JolietNode *joliet;
  148 
  149     joliet = calloc(1, sizeof(JolietNode));
  150     if (joliet == NULL) {
  151         return ISO_OUT_OF_MEM;
  152     }
  153 
  154     if (iso->type == LIBISO_DIR) {
  155         IsoDir *dir = (IsoDir*) iso;
  156         joliet->info.dir = calloc(1, sizeof(struct joliet_dir_info));
  157         if (joliet->info.dir == NULL) {
  158             free(joliet);
  159             return ISO_OUT_OF_MEM;
  160         }
  161         joliet->info.dir->children = NULL;
  162         if (dir->nchildren > 0) {
  163             joliet->info.dir->children = calloc(sizeof(void*), dir->nchildren);
  164             if (joliet->info.dir->children == NULL) {
  165                 free(joliet->info.dir);
  166                 free(joliet);
  167                 return ISO_OUT_OF_MEM;
  168             }
  169         }
  170         joliet->type = JOLIET_DIR;
  171     } else if (iso->type == LIBISO_FILE) {
  172         /* it's a file */
  173         off_t size;
  174         IsoFileSrc *src;
  175         IsoFile *file = (IsoFile*) iso;
  176 
  177         size = iso_stream_get_size(file->stream);
  178         if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE &&
  179             t->opts->iso_level != 3) {
  180             char *ipath = iso_tree_get_node_path(iso);
  181             free(joliet);
  182             ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
  183                          "File \"%s\" can't be added to image because is "
  184                          "greater than 4GB", ipath);
  185             free(ipath);
  186             return ret;
  187         }
  188 
  189         ret = iso_file_src_create(t, file, &src);
  190         if (ret < 0) {
  191             free(joliet);
  192             return ret;
  193         }
  194         joliet->info.file = src;
  195         joliet->type = JOLIET_FILE;
  196     } else if (iso->type == LIBISO_BOOT) {
  197         /* it's a el-torito boot catalog, that we write as a file */
  198         IsoFileSrc *src;
  199 
  200         ret = el_torito_catalog_file_src_create(t, &src);
  201         if (ret < 0) {
  202             free(joliet);
  203             return ret;
  204         }
  205         joliet->info.file = src;
  206         joliet->type = JOLIET_FILE;
  207     } else {
  208         /* should never happen */
  209         free(joliet);
  210         return ISO_ASSERT_FAILURE;
  211     }
  212 
  213     /* take a ref to the IsoNode */
  214     joliet->node = iso;
  215     iso_node_ref(iso);
  216 
  217     *node = joliet;
  218     return ISO_SUCCESS;
  219 }
  220 
  221 /**
  222  * Create the low level Joliet tree from the high level ISO tree.
  223  *
  224  * @return
  225  *      1 success, 0 file ignored, < 0 error
  226  */
  227 static
  228 int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
  229 {
  230     int ret, max_path;
  231     JolietNode *node = NULL;
  232     uint16_t *jname = NULL;
  233 
  234     if (t == NULL || iso == NULL || tree == NULL) {
  235         return ISO_NULL_POINTER;
  236     }
  237 
  238     if (iso->hidden & LIBISO_HIDE_ON_JOLIET) {
  239         /* file will be ignored */
  240         return 0;
  241     }
  242     ret = get_joliet_name(t, iso, &jname);
  243     if (ret < 0) {
  244         return ret;
  245     }
  246     max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0);
  247     if (!t->opts->joliet_longer_paths && max_path > 240) {
  248         char *ipath = iso_tree_get_node_path(iso);
  249         /*
  250          * Wow!! Joliet is even more restrictive than plain ISO-9660,
  251          * that allows up to 255 bytes!!
  252          */
  253         ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
  254                      "File \"%s\" can't be added to Joliet tree, because "
  255                      "its path length is larger than 240", ipath);
  256         free(jname);
  257         free(ipath);
  258         return ret;
  259     }
  260 
  261     switch (iso->type) {
  262     case LIBISO_FILE:
  263         ret = create_node(t, iso, &node);
  264         break;
  265     case LIBISO_DIR:
  266         {
  267             IsoNode *pos;
  268             IsoDir *dir = (IsoDir*)iso;
  269             ret = create_node(t, iso, &node);
  270             if (ret < 0) {
  271                 free(jname);
  272                 return ret;
  273             }
  274             pos = dir->children;
  275             while (pos) {
  276                 int cret;
  277                 JolietNode *child;
  278                 cret = create_tree(t, pos, &child, max_path);
  279                 if (cret < 0) {
  280                     /* error */
  281                     joliet_node_free(node);
  282                     ret = cret;
  283                     break;
  284                 } else if (cret == ISO_SUCCESS) {
  285                     /* add child to this node */
  286                     int nchildren = node->info.dir->nchildren++;
  287                     node->info.dir->children[nchildren] = child;
  288                     child->parent = node;
  289                 }
  290                 pos = pos->next;
  291             }
  292         }
  293         break;
  294     case LIBISO_BOOT:
  295         if (t->eltorito) {
  296             ret = create_node(t, iso, &node);
  297         } else {
  298             /* log and ignore */
  299             ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
  300                 "El-Torito catalog found on a image without El-Torito.");
  301         }
  302         break;
  303     case LIBISO_SYMLINK:
  304     case LIBISO_SPECIAL:
  305         {
  306             char *ipath = iso_tree_get_node_path(iso);
  307             ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
  308                  "Cannot add %s to Joliet tree. %s can only be added to a "
  309                  "Rock Ridge tree.", ipath, (iso->type == LIBISO_SYMLINK ?
  310                                              "Symlinks" : "Special files"));
  311             free(ipath);
  312         }
  313         break;
  314     default:
  315         /* should never happen */
  316         return ISO_ASSERT_FAILURE;
  317     }
  318     if (ret <= 0) {
  319         free(jname);
  320         return ret;
  321     }
  322     node->name = jname;
  323     *tree = node;
  324     return ISO_SUCCESS;
  325 }
  326 
  327 static int
  328 cmp_node(const void *f1, const void *f2)
  329 {
  330     JolietNode *f = *((JolietNode**)f1);
  331     JolietNode *g = *((JolietNode**)f2);
  332     return ucscmp(f->name, g->name);
  333 }
  334 
  335 static
  336 void sort_tree(JolietNode *root)
  337 {
  338     size_t i;
  339 
  340     if (root->info.dir->children == NULL)
  341         return;
  342     qsort(root->info.dir->children, root->info.dir->nchildren,
  343           sizeof(void*), cmp_node);
  344     for (i = 0; i < root->info.dir->nchildren; i++) {
  345         JolietNode *child = root->info.dir->children[i];
  346         if (child->type == JOLIET_DIR)
  347             sort_tree(child);
  348     }
  349 }
  350 
  351 static
  352 int cmp_node_name(const void *f1, const void *f2)
  353 {
  354     JolietNode *f = *((JolietNode**)f1);
  355     JolietNode *g = *((JolietNode**)f2);
  356     return ucscmp(f->name, g->name);
  357 }
  358 
  359 static
  360 int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits,
  361                                 int number, uint16_t *ext)
  362 {
  363     int ret, pos;
  364     uint16_t *ucsnumber;
  365     char fmt[16];
  366     char nstr[72];
  367               /* was: The only caller of this function allocates dest
  368                       with 66 elements and limits digits to < 8
  369                  But this does not match the usage of nstr which has to take
  370                  the decimal representation of an int.
  371               */
  372 
  373     if (digits >= 8)
  374         return ISO_ASSERT_FAILURE;
  375 
  376     sprintf(fmt, "%%0%dd", digits);
  377     sprintf(nstr, fmt, number);
  378 
  379     ret = str2ucs("ASCII", nstr, &ucsnumber);
  380     if (ret < 0) {
  381         return ret;
  382     }
  383 
  384     /* copy name */
  385     pos = ucslen(src);
  386     ucsncpy(dest, src, pos);
  387 
  388     /* copy number */
  389     ucsncpy(dest + pos, ucsnumber, digits);
  390     pos += digits;
  391 
  392     if (ext[0] != (uint16_t)0) {
  393         size_t extlen = ucslen(ext);
  394         iso_msb((uint8_t *) (dest + pos), 0x002E, 2); /* '.' in UCS */ 
  395         pos++;
  396         ucsncpy(dest + pos, ext, extlen);
  397         pos += extlen;
  398     }
  399     iso_msb((uint8_t *) (dest + pos), 0, 2);
  400     free(ucsnumber);
  401     return ISO_SUCCESS;
  402 }
  403 
  404 /*
  405  * From Joliet specs:
  406  * "ISO 9660 (Section 7.5.1) states that the sum of the following shall not
  407  *  exceed 30:
  408  *  - If there is a file name, the length of the file name.
  409  *  - If there is a file name extension, the length of the file name extension.
  410  *  On Joliet compliant media, however, the sum as calculated above shall not
  411  *  exceed 128 [bytes], to allow for longer file identifiers."
  412  *
  413  * I.e. the dot does not count.
  414  *
  415  * (We have an option to lift the limit from 64*2 to 103*2, which is the
  416  *  maximum to fit into an ISO 9660 directory record.)
  417  */
  418 static
  419 int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
  420 {
  421     int ret;
  422     int i, nchildren, maxchar = 64;
  423     JolietNode **children;
  424     IsoHTable *table = NULL;
  425     int need_sort = 0;
  426     uint16_t *full_name = NULL;
  427     uint16_t *tmp = NULL;
  428 
  429     nchildren = dir->info.dir->nchildren;
  430     if (nchildren <= 0) {
  431         ret = ISO_SUCCESS;
  432         goto ex;
  433     }
  434     children = dir->info.dir->children;
  435     LIBISO_ALLOC_MEM(full_name, uint16_t, LIBISO_JOLIET_NAME_MAX);
  436     LIBISO_ALLOC_MEM(tmp, uint16_t, LIBISO_JOLIET_NAME_MAX);
  437 
  438     if (t->opts->joliet_long_names)
  439         maxchar = 103;
  440 
  441     /* a hash table will temporary hold the names, for fast searching */
  442     ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
  443                             (compare_function_t)ucscmp, &table);
  444     if (ret < 0) {
  445         goto ex;
  446     }
  447     for (i = 0; i < nchildren; ++i) {
  448         uint16_t *name = children[i]->name;
  449         ret = iso_htable_add(table, name, name);
  450         if (ret < 0) {
  451             goto mangle_cleanup;
  452         }
  453     }
  454 
  455     for (i = 0; i < nchildren; ++i) {
  456         uint16_t *name, *ext;
  457         int max; /* computed max len for name, without extension */
  458         int j = i;
  459         int digits = 1; /* characters to change per name */
  460 
  461         /* first, find all child with same name */
  462         while (j + 1 < nchildren &&
  463                 !cmp_node_name(children + i, children + j + 1)) {
  464             ++j;
  465         }
  466         if (j == i) {
  467             /* name is unique */
  468             continue;
  469         }
  470 
  471         /*
  472          * A max of 7 characters is good enough, it allows handling up to
  473          * 9,999,999 files with same name.
  474          */
  475          /* Important: joliet_create_mangled_name() relies on digits < 8 */
  476 
  477         while (digits < 8) {
  478             int ok, k;
  479             uint16_t *dot;
  480             int change = 0; /* number to be written */
  481 
  482             /* copy name to buffer */
  483             ucscpy(full_name, children[i]->name);
  484 
  485             /* compute name and extension */
  486             dot = ucsrchr(full_name, '.');
  487             if (dot != NULL && children[i]->type != JOLIET_DIR) {
  488 
  489                 /*
  490                  * File (not dir) with extension
  491                  */
  492                 int extlen;
  493                 full_name[dot - full_name] = 0;
  494                 name = full_name;
  495                 ext = dot + 1;
  496 
  497                 extlen = ucslen(ext);
  498                 max = maxchar - extlen - digits;
  499                 if (max <= 0) {
  500                     /*
  501                      * This can happen if the extension is too long.
  502                      * Reduce its length, to give name at least one
  503                      * original character, if it has any.
  504                      */
  505                     max = (dot > full_name);
  506                     extlen = maxchar - max - digits;
  507                     if (extlen < 3) {
  508                         /*
  509                          * error, we do not reduce extensions to length < 3
  510                          *
  511                          * This cannot happen with current limit of digits
  512                          * because maxchar is at least 64 and digits at most 7.
  513                          */
  514                         ret = ISO_ERROR;
  515                         goto mangle_cleanup;
  516                     }
  517                     ext[extlen] = 0;
  518                 }
  519                 /* ok, reduce name by digits */
  520                 if (name + max < dot) {
  521                     name[max] = 0;
  522                 }
  523             } else {
  524                 /* Directory, or file without extension */
  525                 if (children[i]->type == JOLIET_DIR) {
  526                     max = maxchar - digits;
  527                     dot = NULL; /* dots have no meaning in dirs */
  528                 } else {
  529                     max = maxchar - digits;
  530                 }
  531                 name = full_name;
  532                 if ((size_t) max < ucslen(name)) {
  533                     name[max] = 0;
  534                 }
  535                 /* let ext be an empty string */
  536                 ext = name + ucslen(name);
  537             }
  538 
  539             ok = 1;
  540             /* change name of each file */
  541             for (k = i; k <= j; ++k) {
  542                 while (1) {
  543                     ret = joliet_create_mangled_name(tmp, name, digits,
  544                                                      change, ext);
  545                     if (ret < 0) {
  546                         goto mangle_cleanup;
  547                     }
  548                     ++change;
  549                     if (change > int_pow(10, digits)) {
  550                         ok = 0;
  551                         break;
  552                     }
  553                     if (!iso_htable_get(table, tmp, NULL)) {
  554                         /* the name is unique, so it can be used */
  555                         break;
  556                     }
  557                 }
  558                 if (ok) {
  559                     uint16_t *new = ucsdup(tmp);
  560                     if (new == NULL) {
  561                         ret = ISO_OUT_OF_MEM;
  562                         goto mangle_cleanup;
  563                     }
  564 
  565                     iso_htable_remove_ptr(table, children[k]->name, NULL);
  566                     free(children[k]->name);
  567                     children[k]->name = new;
  568                     iso_htable_add(table, new, new);
  569 
  570                     /*
  571                      * if we change a name we need to sort again children
  572                      * at the end
  573                      */
  574                     need_sort = 1;
  575                 } else {
  576                     /* we need to increment digits */
  577                     break;
  578                 }
  579             }
  580             if (ok) {
  581                 break;
  582             } else {
  583                 ++digits;
  584             }
  585         }
  586         if (digits == 8) {
  587             ret = ISO_MANGLE_TOO_MUCH_FILES;
  588             goto mangle_cleanup;
  589         }
  590         i = j;
  591     }
  592 
  593     /*
  594      * If needed, sort again the files inside dir
  595      */
  596     if (need_sort) {
  597         qsort(children, nchildren, sizeof(void*), cmp_node_name);
  598     }
  599 
  600     ret = ISO_SUCCESS;
  601 
  602 mangle_cleanup : ;
  603 ex:;
  604     iso_htable_destroy(table, NULL);
  605     LIBISO_FREE_MEM(tmp);
  606     LIBISO_FREE_MEM(full_name);
  607     return ret;
  608 }
  609 
  610 static
  611 int mangle_tree(Ecma119Image *t, JolietNode *dir)
  612 {
  613     int ret;
  614     size_t i;
  615 
  616     ret = mangle_single_dir(t, dir);
  617     if (ret < 0) {
  618         return ret;
  619     }
  620 
  621     /* recurse */
  622     for (i = 0; i < dir->info.dir->nchildren; ++i) {
  623         if (dir->info.dir->children[i]->type == JOLIET_DIR) {
  624             ret = mangle_tree(t, dir->info.dir->children[i]);
  625             if (ret < 0) {
  626                 /* error */
  627                 return ret;
  628             }
  629         }
  630     }
  631     return ISO_SUCCESS;
  632 }
  633 
  634 static
  635 int joliet_tree_create(Ecma119Image *t)
  636 {
  637     int ret;
  638     JolietNode *root;
  639 
  640     if (t == NULL) {
  641         return ISO_NULL_POINTER;
  642     }
  643 
  644     ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
  645     if (ret <= 0) {
  646         if (ret == 0) {
  647             /* unexpected error, root ignored!! This can't happen */
  648             ret = ISO_ASSERT_FAILURE;
  649         }
  650         return ret;
  651     }
  652 
  653     /* the Joliet tree is stored in Ecma119Image target */
  654     if (t->eff_partition_offset > 0) {
  655         t->j_part_root = root;
  656     } else {
  657         t->joliet_root = root;
  658     }
  659 
  660     iso_msg_debug(t->image->id, "Sorting the Joliet tree...");
  661     sort_tree(root);
  662 
  663     iso_msg_debug(t->image->id, "Mangling Joliet names...");
  664     ret = mangle_tree(t, root);
  665     if (ret < 0)
  666         return ret;
  667     return ISO_SUCCESS;
  668 }
  669 
  670 /**
  671  * Compute the size of a directory entry for a single node
  672  */
  673 static
  674 size_t calc_dirent_len(Ecma119Image *t, JolietNode *n)
  675 {
  676     /* note than name len is always even, so we always need the pad byte */
  677     int ret = n->name ? ucslen(n->name) * 2 + 34 : 34;
  678     if (n->type == JOLIET_FILE && !(t->opts->omit_version_numbers & 3)) {
  679         /* take into account version numbers */
  680         ret += 4;
  681     }
  682     return ret;
  683 }
  684 
  685 /**
  686  * Computes the total size of all directory entries of a single joliet dir.
  687  * This is like ECMA-119 6.8.1.1, but taking care that names are stored in
  688  * UCS.
  689  */
  690 static
  691 size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
  692 {
  693     size_t i, len;
  694 
  695     /* size of "." and ".." entries */
  696     len = 34 + 34;
  697 
  698     for (i = 0; i < dir->info.dir->nchildren; ++i) {
  699         size_t remaining;
  700         int section, nsections;
  701         JolietNode *child = dir->info.dir->children[i];
  702         size_t dirent_len = calc_dirent_len(t, child);
  703 
  704         nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
  705         for (section = 0; section < nsections; ++section) {
  706             remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
  707             if (dirent_len > remaining) {
  708                 /* child directory entry doesn't fit on block */
  709                 len += remaining + dirent_len;
  710             } else {
  711                 len += dirent_len;
  712             }
  713         }
  714     }
  715 
  716     /*
  717      * The size of a dir is always a multiple of block size, as we must add
  718      * the size of the unused space after the last directory record
  719      * (ECMA-119, 6.8.1.3)
  720      */
  721     len = ROUND_UP(len, BLOCK_SIZE);
  722 
  723     /* cache the len */
  724     dir->info.dir->len = len;
  725     return len;
  726 }
  727 
  728 static
  729 void calc_dir_pos(Ecma119Image *t, JolietNode *dir)
  730 {
  731     size_t i, len;
  732 
  733     t->joliet_ndirs++;
  734     dir->info.dir->block = t->curblock;
  735     len = calc_dir_size(t, dir);
  736     t->curblock += DIV_UP(len, BLOCK_SIZE);
  737     for (i = 0; i < dir->info.dir->nchildren; i++) {
  738         JolietNode *child = dir->info.dir->children[i];
  739         if (child->type == JOLIET_DIR) {
  740             calc_dir_pos(t, child);
  741         }
  742     }
  743 }
  744 
  745 /**
  746  * Compute the length of the joliet path table, in bytes.
  747  */
  748 static
  749 uint32_t calc_path_table_size(JolietNode *dir)
  750 {
  751     uint32_t size;
  752     size_t i;
  753 
  754     /* size of path table for this entry */
  755     size = 8;
  756     size += dir->name ? ucslen(dir->name) * 2 : 2;
  757 
  758     /* and recurse */
  759     for (i = 0; i < dir->info.dir->nchildren; i++) {
  760         JolietNode *child = dir->info.dir->children[i];
  761         if (child->type == JOLIET_DIR) {
  762             size += calc_path_table_size(child);
  763         }
  764     }
  765     return size;
  766 }
  767 
  768 static
  769 int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
  770 {
  771     Ecma119Image *t;
  772     uint32_t path_table_size;
  773     size_t ndirs;
  774 
  775     if (writer == NULL) {
  776         return ISO_OUT_OF_MEM;
  777     }
  778 
  779     t = writer->target;
  780 
  781     /* compute position of directories */
  782     iso_msg_debug(t->image->id, "Computing position of Joliet dir structure");
  783     t->joliet_ndirs = 0;
  784     calc_dir_pos(t, t->joliet_root);
  785 
  786     /* compute length of pathlist */
  787     iso_msg_debug(t->image->id, "Computing length of Joliet pathlist");
  788     path_table_size = calc_path_table_size(t->joliet_root);
  789 
  790     /* compute location for path tables */
  791     t->joliet_l_path_table_pos = t->curblock;
  792     t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  793     t->joliet_m_path_table_pos = t->curblock;
  794     t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  795     t->joliet_path_table_size = path_table_size;
  796 
  797     if (t->opts->partition_offset > 0) {
  798         /* Take into respect second directory tree */
  799         ndirs = t->joliet_ndirs;
  800         t->joliet_ndirs = 0;
  801         calc_dir_pos(t, t->j_part_root);
  802         if (t->joliet_ndirs != ndirs) {
  803             iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
  804                     "Number of directories differs in Joliet partiton_tree");
  805             return ISO_ASSERT_FAILURE;
  806         }
  807         /* Take into respect second set of path tables */
  808         path_table_size = calc_path_table_size(t->j_part_root);
  809         t->j_part_l_path_table_pos = t->curblock;
  810         t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  811         t->j_part_m_path_table_pos = t->curblock;
  812         t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  813     }
  814 
  815     return ISO_SUCCESS;
  816 }
  817 
  818 /**
  819  * Write a single directory record for Joliet. It is like (ECMA-119, 9.1),
  820  * but file identifier is stored in UCS.
  821  *
  822  * @param file_id
  823  *     if >= 0, we use it instead of the filename (for "." and ".." entries).
  824  * @param len_fi
  825  *     Computed length of the file identifier. Total size of the directory
  826  *     entry will be len + 34 (ECMA-119, 9.1.12), as padding is always needed
  827  */
  828 static
  829 void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
  830                           uint8_t *buf, size_t len_fi, int extent)
  831 {
  832     uint32_t len;
  833     uint32_t block;
  834     uint8_t len_dr; /*< size of dir entry */
  835     int multi_extend = 0;
  836     uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
  837             : (uint8_t*)node->name;
  838 
  839     struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
  840     IsoNode *iso;
  841 
  842     len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
  843 
  844     memcpy(rec->file_id, name, len_fi);
  845 
  846     if (node->type == JOLIET_FILE && !(t->opts->omit_version_numbers & 3)) {
  847         len_dr += 4;
  848         rec->file_id[len_fi++] = 0;
  849         rec->file_id[len_fi++] = ';';
  850         rec->file_id[len_fi++] = 0;
  851         rec->file_id[len_fi++] = '1';
  852     }
  853 
  854     if (node->type == JOLIET_DIR) {
  855         /* use the cached length */
  856         len = node->info.dir->len;
  857         block = node->info.dir->block;
  858     } else if (node->type == JOLIET_FILE) {
  859         block = node->info.file->sections[extent].block;
  860         len = node->info.file->sections[extent].size;
  861         multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
  862     } else {
  863         /*
  864          * for nodes other than files and dirs, we set both
  865          * len and block to 0
  866          */
  867         len = 0;
  868         block = 0;
  869     }
  870 
  871     /*
  872      * For ".." entry we need to write the parent info!
  873      */
  874     if (file_id == 1 && node->parent)
  875         node = node->parent;
  876 
  877     rec->len_dr[0] = len_dr;
  878     iso_bb(rec->block, block - t->eff_partition_offset, 4);
  879     iso_bb(rec->length, len, 4);
  880 
  881     /* was: iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
  882     */
  883     iso= node->node;
  884     iso_datetime_7(rec->recording_time, 
  885                    (t->opts->dir_rec_mtime & 2) ? ( t->replace_timestamps ?
  886                                                     t->timestamp : iso->mtime )
  887                                                 : t->now, t->opts->always_gmt);
  888 
  889     rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
  890     iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
  891     rec->len_fi[0] = len_fi;
  892 }
  893 
  894 /**
  895  * Copy up to \p max characters from \p src to \p dest. If \p src has less than
  896  * \p max characters, we pad dest with " " characters.
  897  */
  898 static
  899 void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max)
  900 {
  901     char *cdest, *csrc;
  902     size_t len, i;
  903 
  904     cdest = (char*)dest;
  905     csrc = (char*)src;
  906 
  907     if (src != NULL) {
  908         len = MIN(ucslen(src) * 2, max - (max % 2));
  909     } else {
  910         len = 0;
  911     }
  912 
  913     for (i = 0; i < len; ++i)
  914         cdest[i] = csrc[i];
  915     if (len >= 2)
  916         iso_handle_split_utf16(dest + (len / 2 - 1));
  917 
  918     for (i = len; i + 1 < max; i += 2) {
  919         cdest[i] = '\0';
  920         cdest[i + 1] = ' ';
  921     }
  922     if (max % 2)
  923         cdest[max - 1] = 0;
  924 }
  925 
  926 int joliet_writer_write_vol_desc(IsoImageWriter *writer)
  927 {
  928     IsoImage *image;
  929     Ecma119Image *t;
  930     struct ecma119_sup_vol_desc vol;
  931 
  932     uint16_t *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
  933     uint16_t *volset_id = NULL, *system_id = NULL, *application_id = NULL;
  934     uint16_t *copyright_file_id = NULL, *abstract_file_id = NULL;
  935     uint16_t *biblio_file_id = NULL;
  936 
  937     if (writer == NULL) {
  938         return ISO_OUT_OF_MEM;
  939     }
  940 
  941     t = writer->target;
  942     image = t->image;
  943 
  944     iso_msg_debug(image->id, "Write SVD for Joliet");
  945 
  946     memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
  947 
  948     str2ucs(t->input_charset, image->volume_id, &vol_id);
  949     str2ucs(t->input_charset, image->publisher_id, &pub_id);
  950     str2ucs(t->input_charset, image->data_preparer_id, &data_id);
  951     str2ucs(t->input_charset, image->volset_id, &volset_id);
  952 
  953     str2ucs(t->input_charset, image->system_id, &system_id);
  954     str2ucs(t->input_charset, image->application_id, &application_id);
  955     str2ucs(t->input_charset, image->copyright_file_id, &copyright_file_id);
  956     str2ucs(t->input_charset, image->abstract_file_id, &abstract_file_id);
  957     str2ucs(t->input_charset, image->biblio_file_id, &biblio_file_id);
  958 
  959     vol.vol_desc_type[0] = 2;
  960     memcpy(vol.std_identifier, "CD001", 5);
  961     vol.vol_desc_version[0] = 1;
  962     ucsncpy_pad((uint16_t*)vol.volume_id, vol_id, 32);
  963 
  964     /* make use of UCS-2 Level 3 */
  965     memcpy(vol.esc_sequences, "%/E", 3);
  966     iso_bb(vol.vol_space_size, t->vol_space_size  - t->eff_partition_offset,
  967            4);
  968     iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
  969     iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
  970     iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
  971     iso_bb(vol.path_table_size, t->joliet_path_table_size, 4);
  972 
  973     if (t->eff_partition_offset > 0) {
  974         /* Point to second tables and second root */
  975         iso_lsb(vol.l_path_table_pos,
  976                 t->j_part_l_path_table_pos - t->eff_partition_offset, 4);
  977         iso_msb(vol.m_path_table_pos,
  978                 t->j_part_m_path_table_pos - t->eff_partition_offset, 4);
  979         write_one_dir_record(t, t->j_part_root, 0, vol.root_dir_record, 1, 0);
  980     } else {
  981         iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
  982         iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
  983         write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0);
  984     }
  985 
  986     ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
  987     ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
  988     ucsncpy_pad((uint16_t*)vol.data_prep_id, data_id, 128);
  989 
  990     ucsncpy_pad((uint16_t*)vol.system_id, system_id, 32);
  991 
  992     ucsncpy_pad((uint16_t*)vol.application_id, application_id, 128);
  993     ucsncpy_pad((uint16_t*)vol.copyright_file_id, copyright_file_id, 37);
  994     ucsncpy_pad((uint16_t*)vol.abstract_file_id, abstract_file_id, 37);
  995     ucsncpy_pad((uint16_t*)vol.bibliographic_file_id, biblio_file_id, 37);
  996 
  997     ecma119_set_voldescr_times(writer, (struct ecma119_pri_vol_desc *) &vol);
  998     vol.file_structure_version[0] = 1;
  999 
 1000     free(vol_id);
 1001     free(volset_id);
 1002     free(pub_id);
 1003     free(data_id);
 1004     free(system_id);
 1005     free(application_id);
 1006     free(copyright_file_id);
 1007     free(abstract_file_id);
 1008     free(biblio_file_id);
 1009 
 1010     /* Finally write the Volume Descriptor */
 1011     return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
 1012 }
 1013 
 1014 static
 1015 int write_one_dir(Ecma119Image *t, JolietNode *dir)
 1016 {
 1017     int ret;
 1018     uint8_t *buffer = NULL;
 1019     size_t i;
 1020     size_t fi_len, len;
 1021 
 1022     /* buf will point to current write position on buffer */
 1023     uint8_t *buf;
 1024 
 1025     /* initialize buffer with 0s */
 1026     LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
 1027     buf = buffer;
 1028 
 1029     /* write the "." and ".." entries first */
 1030     write_one_dir_record(t, dir, 0, buf, 1, 0);
 1031     buf += 34;
 1032     write_one_dir_record(t, dir, 1, buf, 1, 0);
 1033     buf += 34;
 1034 
 1035     for (i = 0; i < dir->info.dir->nchildren; i++) {
 1036         int section, nsections;
 1037         JolietNode *child = dir->info.dir->children[i];
 1038 
 1039         /* compute len of directory entry */
 1040         fi_len = ucslen(child->name) * 2;
 1041         len = fi_len + 34;
 1042         if (child->type == JOLIET_FILE &&
 1043             !(t->opts->omit_version_numbers & 3)) {
 1044             len += 4;
 1045         }
 1046 
 1047         nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
 1048 
 1049         for (section = 0; section < nsections; ++section) {
 1050 
 1051             if ( (buf + len - buffer) > BLOCK_SIZE) {
 1052                 /* dir doesn't fit in current block */
 1053                 ret = iso_write(t, buffer, BLOCK_SIZE);
 1054                 if (ret < 0) {
 1055                     goto ex;
 1056                 }
 1057                 memset(buffer, 0, BLOCK_SIZE);
 1058                 buf = buffer;
 1059             }
 1060             /* write the directory entry in any case */
 1061             write_one_dir_record(t, child, -1, buf, fi_len, section);
 1062             buf += len;
 1063         }
 1064     }
 1065 
 1066     /* write the last block */
 1067     ret = iso_write(t, buffer, BLOCK_SIZE);
 1068 ex:;
 1069     LIBISO_FREE_MEM(buffer);
 1070     return ret;
 1071 }
 1072 
 1073 static
 1074 int write_dirs(Ecma119Image *t, JolietNode *root)
 1075 {
 1076     int ret;
 1077     size_t i;
 1078 
 1079     /* write all directory entries for this dir */
 1080     ret = write_one_dir(t, root);
 1081     if (ret < 0) {
 1082         return ret;
 1083     }
 1084 
 1085     /* recurse */
 1086     for (i = 0; i < root->info.dir->nchildren; i++) {
 1087         JolietNode *child = root->info.dir->children[i];
 1088         if (child->type == JOLIET_DIR) {
 1089             ret = write_dirs(t, child);
 1090             if (ret < 0) {
 1091                 return ret;
 1092             }
 1093         }
 1094     }
 1095     return ISO_SUCCESS;
 1096 }
 1097 
 1098 static
 1099 int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
 1100 {
 1101     size_t i, len;
 1102     uint8_t *buf = NULL;
 1103     struct ecma119_path_table_record *rec;
 1104     void (*write_int)(uint8_t*, uint32_t, int);
 1105     JolietNode *dir;
 1106     uint32_t path_table_size;
 1107     int parent = 0;
 1108     int ret= ISO_SUCCESS;
 1109     uint8_t *zeros = NULL;
 1110 
 1111     /* 256 is just a convenient size large enough */
 1112     LIBISO_ALLOC_MEM(buf, uint8_t, 256);
 1113     LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
 1114     path_table_size = 0;
 1115     write_int = l_type ? iso_lsb : iso_msb;
 1116 
 1117     for (i = 0; i < t->joliet_ndirs; i++) {
 1118         dir = pathlist[i];
 1119 
 1120         /* find the index of the parent in the table */
 1121         while ((i) && pathlist[parent] != dir->parent) {
 1122             parent++;
 1123         }
 1124 
 1125         /* write the Path Table Record (ECMA-119, 9.4) */
 1126         memset(buf, 0, 256);
 1127         rec = (struct ecma119_path_table_record*) buf;
 1128         rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1;
 1129         rec->len_xa[0] = 0;
 1130         write_int(rec->block, dir->info.dir->block - t->eff_partition_offset,
 1131                   4);
 1132         write_int(rec->parent, parent + 1, 2);
 1133         if (dir->parent) {
 1134             memcpy(rec->dir_id, dir->name, rec->len_di[0]);
 1135         }
 1136         len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
 1137         ret = iso_write(t, buf, len);
 1138         if (ret < 0) {
 1139             /* error */
 1140             goto ex;
 1141         }
 1142         path_table_size += len;
 1143     }
 1144 
 1145     /* we need to fill the last block with zeros */
 1146     path_table_size %= BLOCK_SIZE;
 1147     if (path_table_size) {
 1148         len = BLOCK_SIZE - path_table_size;
 1149         memset(zeros, 0, len);
 1150         ret = iso_write(t, zeros, len);
 1151     }
 1152 ex:;
 1153     LIBISO_FREE_MEM(zeros);
 1154     LIBISO_FREE_MEM(buf);
 1155     return ret;
 1156 }
 1157 
 1158 static
 1159 int write_path_tables(Ecma119Image *t)
 1160 {
 1161     int ret;
 1162     size_t i, j, cur;
 1163     JolietNode **pathlist;
 1164 
 1165     iso_msg_debug(t->image->id, "Writing Joliet Path tables");
 1166 
 1167     /* allocate temporal pathlist */
 1168     pathlist = malloc(sizeof(void*) * t->joliet_ndirs);
 1169     if (pathlist == NULL) {
 1170         return ISO_OUT_OF_MEM;
 1171     }
 1172 
 1173     if (t->eff_partition_offset > 0) {
 1174         pathlist[0] = t->j_part_root;
 1175     } else {
 1176         pathlist[0] = t->joliet_root;
 1177     }
 1178     cur = 1;
 1179 
 1180     for (i = 0; i < t->joliet_ndirs; i++) {
 1181         JolietNode *dir = pathlist[i];
 1182         for (j = 0; j < dir->info.dir->nchildren; j++) {
 1183             JolietNode *child = dir->info.dir->children[j];
 1184             if (child->type == JOLIET_DIR) {
 1185                 pathlist[cur++] = child;
 1186             }
 1187         }
 1188     }
 1189 
 1190     /* Write L Path Table */
 1191     ret = write_path_table(t, pathlist, 1);
 1192     if (ret < 0) {
 1193         goto write_path_tables_exit;
 1194     }
 1195 
 1196     /* Write L Path Table */
 1197     ret = write_path_table(t, pathlist, 0);
 1198 
 1199     write_path_tables_exit: ;
 1200     free(pathlist);
 1201     return ret;
 1202 }
 1203 
 1204 static
 1205 int joliet_writer_write_dirs(IsoImageWriter *writer)
 1206 {
 1207     int ret;
 1208     Ecma119Image *t;
 1209     JolietNode *root;
 1210 
 1211     t = writer->target;
 1212 
 1213     /* first of all, we write the directory structure */
 1214     if (t->eff_partition_offset > 0) {
 1215         root = t->j_part_root;
 1216     } else {
 1217         root = t->joliet_root;
 1218     }
 1219     ret = write_dirs(t, root);
 1220     if (ret < 0) {
 1221         return ret;
 1222     }
 1223 
 1224     /* and write the path tables */
 1225     ret = write_path_tables(t);
 1226 
 1227     return ret;
 1228 }
 1229 
 1230 static
 1231 int joliet_writer_write_data(IsoImageWriter *writer)
 1232 {
 1233     int ret;
 1234     Ecma119Image *t;
 1235 
 1236     if (writer == NULL) {
 1237         return ISO_NULL_POINTER;
 1238     }
 1239     t = writer->target;
 1240 
 1241     ret = joliet_writer_write_dirs(writer);
 1242     if (ret < 0)
 1243         return ret;
 1244 
 1245     if (t->opts->partition_offset > 0) {
 1246         t->eff_partition_offset = t->opts->partition_offset;
 1247         ret = joliet_writer_write_dirs(writer);
 1248         t->eff_partition_offset = 0;
 1249         if (ret < 0)
 1250             return ret;
 1251     }
 1252     return ISO_SUCCESS;
 1253 }
 1254 
 1255 static
 1256 int joliet_writer_free_data(IsoImageWriter *writer)
 1257 {
 1258     /* free the Joliet tree */
 1259     Ecma119Image *t = writer->target;
 1260     joliet_node_free(t->joliet_root);
 1261     if (t->j_part_root != NULL)
 1262         joliet_node_free(t->j_part_root);
 1263     t->j_part_root = NULL;
 1264     return ISO_SUCCESS;
 1265 }
 1266 
 1267 int joliet_writer_create(Ecma119Image *target)
 1268 {
 1269     int ret;
 1270     IsoImageWriter *writer;
 1271 
 1272     writer = malloc(sizeof(IsoImageWriter));
 1273     if (writer == NULL) {
 1274         return ISO_OUT_OF_MEM;
 1275     }
 1276 
 1277     writer->compute_data_blocks = joliet_writer_compute_data_blocks;
 1278     writer->write_vol_desc = joliet_writer_write_vol_desc;
 1279     writer->write_data = joliet_writer_write_data;
 1280     writer->free_data = joliet_writer_free_data;
 1281     writer->data = NULL;
 1282     writer->target = target;
 1283 
 1284     iso_msg_debug(target->image->id, "Creating low level Joliet tree...");
 1285     ret = joliet_tree_create(target);
 1286     if (ret < 0) {
 1287         free((char *) writer);
 1288         return ret;
 1289     }
 1290 
 1291     /* add this writer to image */
 1292     target->writers[target->nwriters++] = writer;
 1293 
 1294     if(target->opts->partition_offset > 0) {
 1295         /* Create second tree */
 1296         target->eff_partition_offset = target->opts->partition_offset;
 1297         ret = joliet_tree_create(target);
 1298         if (ret < 0) {
 1299             return ret;
 1300         }
 1301         target->eff_partition_offset = 0;
 1302     }
 1303 
 1304     /* we need the volume descriptor */
 1305     target->curblock++;
 1306     return ISO_SUCCESS;
 1307 }