"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/hfsplus.c" (15 Nov 2020, 60147 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 "hfsplus.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) 2011-2012 Thomas Schmitt
    5  * Copyright (c) 2012 Vladimir Serbinenko
    6  *
    7  * This file is part of the libisofs project; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License version 2 
    9  * or later as published by the Free Software Foundation. 
   10  * See COPYING file for details.
   11  */
   12 
   13 
   14 /* Some extra debugging messages for Vladimir Serbinenko
   15  #define Libisofs_hfsplus_verbose_debuG yes
   16 */
   17 
   18 /* Some extra debugging messages for Thomas Schmitt
   19 */
   20 #define Libisofs_ts_debuG yes
   21 
   22 
   23 #ifdef HAVE_CONFIG_H
   24 #include "../config.h"
   25 #endif
   26 
   27 #include "hfsplus.h"
   28 #include "messages.h"
   29 #include "writer.h"
   30 #include "image.h"
   31 #include "filesrc.h"
   32 #include "eltorito.h"
   33 #include "libisofs.h"
   34 #include "util.h"
   35 #include "ecma119.h"
   36 #include "system_area.h"
   37 
   38 
   39 #include <stdlib.h>
   40 #include <stdio.h>
   41 #include <string.h>
   42 
   43 /* To be used if Ecma119.hfsplus_block_size == 0 in hfsplus_writer_create().
   44    It cannot be larger than 2048 because filesrc_writer aligns data file
   45    content start to 2048.
   46 */
   47 #define HFSPLUS_DEFAULT_BLOCK_SIZE 2048
   48 
   49 /* To be used with storage allocation.
   50 */
   51 #define HFSPLUS_MAX_BLOCK_SIZE 2048
   52 
   53 
   54 /* In libisofs/hfsplus_case.c */
   55 extern uint16_t iso_hfsplus_cichar(uint16_t x);
   56 
   57 
   58 /* ts B20623: pad up output block to full 2048 bytes */
   59 static
   60 int pad_up_block(Ecma119Image *t)
   61 {
   62     int ret;
   63     static char buffer[2048], buf_zeroed = 0;
   64 
   65     if (!buf_zeroed) {
   66         memset(buffer, 0, 2048);
   67         buf_zeroed = 1;
   68     }
   69     if (t->bytes_written % 2048) {
   70     ret = iso_write(t, buffer, 2048 - (t->bytes_written % 2048));
   71     if (ret < 0)
   72         return ret;
   73     }
   74     return 1;
   75 }
   76 
   77 
   78 static
   79 int filesrc_block_and_size(Ecma119Image *t, IsoFileSrc *src,
   80                            uint32_t *start_block, uint64_t *total_size)
   81 {
   82     int i;
   83     uint32_t pos;
   84 
   85     *start_block = 0;
   86     *total_size = 0;
   87     if (src->nsections <= 0)
   88         return 0;
   89     pos = *start_block = src->sections[0].block;
   90     for (i = 0; i < src->nsections; i++) {
   91         *total_size += src->sections[i].size;
   92         if (pos != src->sections[i].block) {
   93             iso_msg_submit(t->image->id, ISO_SECT_SCATTERED, 0,
   94                       "File sections do not form consecutive array of blocks");
   95             return ISO_SECT_SCATTERED;
   96         }
   97         /* If .size is not aligned to blocks then there is a byte gap.
   98            No need to trace the exact byte address.
   99         */
  100         pos = src->sections[i].block + src->sections[i].size / 2048;
  101     }
  102     return 1;
  103 }
  104 
  105 static
  106 uint8_t get_class (uint16_t v)
  107 {
  108   uint16_t s;
  109   uint8_t high, low;
  110   s = iso_ntohs (v);
  111   high = s >> 8;
  112   low = v & 0xff;
  113   if (!hfsplus_class_pages[high])
  114     return 0;
  115   return hfsplus_class_pages[high][low];
  116 }
  117 
  118 int iso_get_hfsplus_name(char *input_charset, int imgid, char *name,
  119                   uint16_t **result, uint32_t *result_len, uint16_t **cmp_name)
  120 {
  121     int ret;
  122     uint16_t *ucs_name, *iptr, *optr;
  123     uint32_t curlen;
  124     int done;
  125 
  126     if (name == NULL) {
  127         /* it is not necessarily an error, it can be the root */
  128         return ISO_SUCCESS;
  129     }
  130 
  131     ret = str2utf16be(input_charset, name, &ucs_name);
  132     if (ret < 0) {
  133         iso_msg_debug(imgid, "Cannot convert '%s'", name);
  134         return ret;
  135     }
  136 
  137     curlen = ucslen (ucs_name);
  138     *result = calloc ((curlen * HFSPLUS_MAX_DECOMPOSE_LEN + 1),
  139                      sizeof (uint16_t));
  140     if (*result == NULL) {
  141         free(ucs_name);
  142         return ISO_OUT_OF_MEM;
  143     }
  144 
  145     for (iptr = ucs_name, optr = *result; *iptr; iptr++)
  146       {
  147     const uint16_t *dptr;
  148     uint16_t val = iso_ntohs (*iptr);
  149     uint8_t high = val >> 8;
  150     uint8_t low = val & 0xff;
  151 
  152     if (val == ':')
  153       {
  154         *optr++ = iso_htons ('/');
  155         continue;
  156       }
  157 
  158     if (val >= 0xac00 && val <= 0xd7a3)
  159       {
  160         uint16_t s, l, v, t;
  161         s = val - 0xac00;
  162         l = s / (21 * 28);
  163         v = (s % (21 * 28)) / 28;
  164         t = s % 28;
  165         *optr++ = iso_htons (l + 0x1100);
  166         *optr++ = iso_htons (v + 0x1161);
  167         if (t)
  168           *optr++ = iso_htons (t + 0x11a7);
  169         continue;
  170       }
  171     if (!hfsplus_decompose_pages[high])
  172       {
  173         *optr++ = *iptr;
  174         continue;
  175       }
  176     dptr = hfsplus_decompose_pages[high][low];
  177     if (!dptr[0])
  178       {
  179         *optr++ = *iptr;
  180         continue;
  181       }
  182     for (; *dptr; dptr++)
  183       *optr++ = iso_htons (*dptr);
  184       }
  185     *optr = 0;
  186 
  187     do
  188       {
  189     uint8_t last_class;
  190     done = 0;
  191     if (!ucs_name[0])
  192       break;
  193     last_class = get_class (ucs_name[0]);
  194     for (optr = *result + 1; *optr; optr++)
  195       {
  196         uint8_t new_class = get_class (*optr);
  197 
  198         if (last_class == 0 || new_class == 0
  199         || last_class <= new_class)
  200           last_class = new_class;
  201         else
  202           {
  203         uint16_t t;
  204         t = *(optr - 1);
  205         *(optr - 1) = *optr;
  206         *optr = t;
  207           }
  208       }
  209       }
  210     while (done);
  211 
  212     *cmp_name = calloc ((ucslen (*result) + 1), sizeof (uint16_t));
  213     if (*cmp_name == NULL) {
  214         free(ucs_name);
  215         free(*result);
  216         *result = NULL;
  217         return ISO_OUT_OF_MEM;
  218     }
  219 
  220     for (iptr = *result, optr = *cmp_name; *iptr; iptr++)
  221       {
  222     *optr = iso_hfsplus_cichar(*iptr);
  223     if (*optr != 0)
  224         optr++;
  225       }
  226     *optr = 0;
  227 
  228     free (ucs_name);
  229 
  230     *result_len = ucslen (*result);
  231     return ISO_SUCCESS;
  232 }
  233 
  234 static
  235 int set_hfsplus_name(Ecma119Image *t, char *name, HFSPlusNode *node)
  236 {
  237     int ret;
  238 
  239     ret = iso_get_hfsplus_name(t->input_charset, t->image->id, name,
  240                             &(node->name), &(node->strlen), &(node->cmp_name));
  241     return ret;
  242 }
  243 
  244 /* >>> ts B20617
  245        This should be HFSPlusNode rather than IsoNode in order to have access
  246        to IsoFileSrc.no_write which indicates that the file content will not
  247        be in written the range of filesrc_writer.
  248 */
  249 static
  250 int hfsplus_count_tree(Ecma119Image *t, IsoNode *iso)
  251 {
  252     if (t == NULL || iso == NULL) {
  253         return ISO_NULL_POINTER;
  254     }
  255 
  256     if (iso->hidden & LIBISO_HIDE_ON_HFSPLUS) {
  257         /* file will be ignored */
  258         return 0;
  259     }
  260 
  261     switch (iso->type) {
  262     case LIBISO_SYMLINK:
  263     case LIBISO_SPECIAL:
  264     case LIBISO_FILE:
  265       t->hfsp_nfiles++;
  266       return ISO_SUCCESS;
  267     case LIBISO_DIR:
  268       t->hfsp_ndirs++;
  269       {
  270     IsoNode *pos;
  271     IsoDir *dir = (IsoDir*)iso;
  272     pos = dir->children;
  273     while (pos) {
  274       int cret;
  275       cret = hfsplus_count_tree(t, pos);
  276       if (cret < 0) {
  277         /* error */
  278         return cret;
  279       }
  280       pos = pos->next;
  281     }
  282       }
  283       return ISO_SUCCESS;
  284     case LIBISO_BOOT:
  285       return ISO_SUCCESS;
  286     default:
  287       /* should never happen */
  288       return ISO_ASSERT_FAILURE;
  289     }
  290 }
  291 
  292 /**
  293  * Create the low level Hfsplus tree from the high level ISO tree.
  294  *
  295  * @return
  296  *      1 success, 0 file ignored, < 0 error
  297  */
  298 static
  299 int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
  300 {
  301     int ret;
  302     uint32_t cat_id, cleaf;
  303     int i;
  304 
  305     if (t == NULL || iso == NULL) {
  306         return ISO_NULL_POINTER;
  307     }
  308 
  309     if (iso->hidden & LIBISO_HIDE_ON_HFSPLUS) {
  310         /* file will be ignored */
  311         return 0;
  312     }
  313 
  314     if (iso->type != LIBISO_FILE && iso->type != LIBISO_DIR
  315     && iso->type != LIBISO_SYMLINK && iso->type != LIBISO_SPECIAL)
  316       return 0;
  317 
  318     cat_id = t->hfsp_cat_id++;
  319 
  320     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
  321       if (t->hfsplus_blessed[i] == iso) {
  322 
  323 #ifdef Libisofs_ts_debuG
  324     iso_msg_debug(t->image->id, "hfsplus bless %d to cat_id %u ('%s')",
  325                                 i, cat_id, iso->name);
  326 #endif /* Libisofs_ts_debuG */
  327 
  328     t->hfsp_bless_id[i] = cat_id;
  329       }
  330 
  331     t->hfsp_leafs[t->hfsp_curleaf].node = iso;
  332     t->hfsp_leafs[t->hfsp_curleaf].parent_id = parent_id;
  333     ret = set_hfsplus_name (t, iso->name, &t->hfsp_leafs[t->hfsp_curleaf]);
  334     if (ret < 0)
  335         return ret;
  336     t->hfsp_leafs[t->hfsp_curleaf].cat_id = cat_id;
  337     t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_NONE;
  338     t->hfsp_leafs[t->hfsp_curleaf].symlink_dest = NULL;
  339 
  340     switch (iso->type)
  341       {
  342       case LIBISO_SYMLINK:
  343     {
  344       IsoSymlink *sym = (IsoSymlink*) iso;
  345       t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
  346       t->hfsp_leafs[t->hfsp_curleaf].symlink_dest = strdup(sym->dest);
  347       if (t->hfsp_leafs[t->hfsp_curleaf].symlink_dest == NULL)
  348           return ISO_OUT_OF_MEM;
  349       t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_SYMLINK;
  350       t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
  351       break;
  352     }
  353       case LIBISO_SPECIAL:
  354     t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_SPECIAL;
  355     t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
  356     t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
  357     break;
  358 
  359       case LIBISO_FILE:
  360     {
  361       IsoFile *file = (IsoFile*) iso;
  362       t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
  363       ret = iso_file_src_create(t, file, &t->hfsp_leafs[t->hfsp_curleaf].file);
  364       if (ret < 0) {
  365             return ret;
  366       }
  367       t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
  368     }
  369     break;
  370       case LIBISO_DIR:
  371     {
  372       t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_DIR;
  373       t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common);
  374       break;
  375     }
  376       default:
  377     return ISO_ASSERT_FAILURE;
  378       }
  379     cleaf = t->hfsp_curleaf;
  380     t->hfsp_leafs[t->hfsp_curleaf].nchildren = 0;
  381     t->hfsp_curleaf++;
  382 
  383     t->hfsp_leafs[t->hfsp_curleaf].name = t->hfsp_leafs[t->hfsp_curleaf - 1].name;
  384     t->hfsp_leafs[t->hfsp_curleaf].cmp_name = NULL;
  385     t->hfsp_leafs[t->hfsp_curleaf].strlen = t->hfsp_leafs[t->hfsp_curleaf - 1].strlen;
  386     t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_thread);
  387     t->hfsp_leafs[t->hfsp_curleaf].node = iso;
  388     t->hfsp_leafs[t->hfsp_curleaf].type = (iso->type == LIBISO_DIR) ? HFSPLUS_DIR_THREAD : HFSPLUS_FILE_THREAD;
  389     t->hfsp_leafs[t->hfsp_curleaf].file = 0;
  390     t->hfsp_leafs[t->hfsp_curleaf].cat_id = parent_id;
  391     t->hfsp_leafs[t->hfsp_curleaf].parent_id = cat_id;
  392     t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_NONE;
  393     t->hfsp_curleaf++;
  394 
  395     if (iso->type == LIBISO_DIR)
  396       {
  397     IsoNode *pos;
  398     IsoDir *dir = (IsoDir*)iso;
  399 
  400     pos = dir->children;
  401     while (pos)
  402       {
  403         int cret;
  404         cret = create_tree(t, pos, cat_id);
  405         if (cret < 0)
  406           return cret;
  407         pos = pos->next;
  408         if (cret > 0)
  409           t->hfsp_leafs[cleaf].nchildren++;
  410       }
  411       }
  412     return ISO_SUCCESS;
  413 }
  414 
  415 static int
  416 cmp_node(const void *f1, const void *f2)
  417 {
  418   HFSPlusNode *f = (HFSPlusNode*) f1;
  419   HFSPlusNode *g = (HFSPlusNode*) f2;
  420   const uint16_t empty[1] = {0};
  421   const uint16_t *a, *b; 
  422   if (f->parent_id > g->parent_id)
  423     return +1;
  424   if (f->parent_id < g->parent_id)
  425     return -1;
  426   a = f->cmp_name;
  427   b = g->cmp_name;
  428   if (!a)
  429     a = empty;
  430   if (!b)
  431     b = empty;
  432 
  433   return ucscmp(a, b);
  434 }
  435 
  436 
  437 static
  438 int hfsplus_tail_writer_compute_data_blocks(IsoImageWriter *writer)
  439 {
  440   Ecma119Image *t;
  441   uint32_t hfsp_size, hfsp_curblock, block_fac, block_size;
  442     
  443   if (writer == NULL) {
  444     return ISO_OUT_OF_MEM;
  445   }
  446 
  447   t = writer->target;
  448   block_size = t->opts->hfsp_block_size;
  449   block_fac = t->hfsp_iso_block_fac;
  450 
  451 #ifdef Libisofs_ts_debuG
  452   iso_msg_debug(t->image->id, "hfsplus tail writer start = %.f",
  453                 ((double) t->curblock) * 2048.0);
  454 #endif
  455 
  456   hfsp_curblock = t->curblock * block_fac;
  457   hfsp_size = hfsp_curblock - t->hfsp_part_start + 1;
  458 
  459   /* We need one bit for every block. */
  460   /* So if we allocate x blocks we have to satisfy:
  461      8 * block_size * x >= total_size + x
  462      (8 * block_size - 1) * x >= total_size
  463   */
  464   t->hfsp_allocation_blocks = hfsp_size / (8 * block_size - 1) + 1;
  465   t->hfsp_allocation_file_start = hfsp_curblock;
  466   hfsp_curblock += t->hfsp_allocation_blocks;
  467 
  468   /* write_data() will need to pad up ISO block before superblock copy */
  469   t->curblock = hfsp_curblock / block_fac;
  470   if (hfsp_curblock % block_fac)
  471       t->curblock++;
  472   hfsp_curblock = t->curblock * block_fac;
  473 
  474   /* Superblock always occupies 2K */
  475   hfsp_curblock += block_fac;
  476   t->curblock++;
  477 
  478 #ifdef Libisofs_ts_debuG
  479   iso_msg_debug(t->image->id, "hfsplus tail writer end = %.f",
  480                 ((double) hfsp_curblock) * block_size);
  481 #endif
  482 
  483   t->hfsp_total_blocks = hfsp_curblock - t->hfsp_part_start;
  484 
  485   return iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
  486                              t->hfsp_part_start / block_fac,
  487                  t->hfsp_total_blocks / block_fac +
  488                  !!(t->hfsp_total_blocks % block_fac),
  489                             "HFSPLUS_Hybrid", "Apple_HFS");
  490 }
  491 
  492 
  493 static
  494 int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer)
  495 {
  496     Ecma119Image *t;
  497     uint32_t i, hfsp_curblock;
  498     uint32_t block_fac, block_size;
  499 
  500     if (writer == NULL) {
  501         return ISO_OUT_OF_MEM;
  502     }
  503 
  504     t = writer->target;
  505     block_size = t->opts->hfsp_block_size;
  506     block_fac = t->hfsp_iso_block_fac;
  507 
  508     iso_msg_debug(t->image->id, "(b) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes);
  509     t->hfsp_part_start = t->curblock * block_fac;
  510 
  511     hfsp_curblock = t->curblock * block_fac;
  512 
  513     /* Superblock always occupies 2K */
  514     hfsp_curblock += block_fac;
  515 
  516     t->hfsp_catalog_file_start = hfsp_curblock;
  517 
  518 /* 
  519     hfsp_curblock += (t->hfsp_nnodes * t->hfsp_cat_node_size + block_size - 1) / block_size;
  520 */
  521     hfsp_curblock += 2 * t->hfsp_nnodes;
  522 
  523     t->hfsp_extent_file_start = hfsp_curblock;
  524     hfsp_curblock++;
  525 
  526     iso_msg_debug(t->image->id, "(d) hfsp_curblock=%d, nodes =%d", hfsp_curblock, t->hfsp_nnodes);
  527 
  528     for (i = 0; i < t->hfsp_nleafs; i++)
  529       if (t->hfsp_leafs[i].unix_type == UNIX_SYMLINK)
  530     {
  531           t->hfsp_leafs[i].symlink_block = hfsp_curblock;
  532           hfsp_curblock += (strlen(t->hfsp_leafs[i].symlink_dest) +
  533                             block_size - 1) / block_size;
  534     }
  535 
  536     t->curblock = hfsp_curblock / block_fac;
  537     if (hfsp_curblock % block_fac)
  538         t->curblock++;
  539 
  540     iso_msg_debug(t->image->id, "(a) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes);
  541 
  542     return ISO_SUCCESS;
  543 }
  544 
  545 
  546 static inline uint32_t mac_time_offset(uint32_t t)
  547 {
  548     uint32_t val;
  549     iso_msb ((uint8_t *) &val, t + 2082844800, sizeof(val));
  550     return val;
  551 }
  552 
  553 
  554 int nop_writer_write_vol_desc(IsoImageWriter *writer)
  555 {
  556   return ISO_SUCCESS;
  557 }
  558 
  559 static
  560 uid_t px_get_uid(Ecma119Image *t, IsoNode *n)
  561 {
  562     if (t->replace_uid) {
  563         return t->uid;
  564     } else {
  565         return n->uid;
  566     }
  567 }
  568 
  569 static
  570 uid_t px_get_gid(Ecma119Image *t, IsoNode *n)
  571 {
  572     if (t->replace_gid) {
  573         return t->gid;
  574     } else {
  575         return n->gid;
  576     }
  577 }
  578 
  579 static
  580 mode_t px_get_mode(Ecma119Image *t, IsoNode *n, int isdir)
  581 {
  582     if (isdir) {
  583         if (t->replace_dir_mode) {
  584             return (n->mode & S_IFMT) | t->dir_mode;
  585         }
  586     } else {
  587         if (t->replace_file_mode) {
  588             return (n->mode & S_IFMT) | t->file_mode;
  589         }
  590     }
  591     return n->mode;
  592 }
  593 
  594 int
  595 write_sb (Ecma119Image *t)
  596 {
  597     struct hfsplus_volheader sb;
  598     static char buffer[1024];
  599     int ret;
  600     int i;
  601     uint32_t block_size;
  602 
  603     iso_msg_debug(t->image->id, "Write HFS+ superblock");
  604 
  605     block_size = t->opts->hfsp_block_size;
  606 
  607     memset (buffer, 0, sizeof (buffer));
  608     ret = iso_write(t, buffer, 1024);
  609     if (ret < 0)
  610       return ret;
  611 
  612     memset (&sb, 0, sizeof (sb));
  613 
  614     t->hfsp_allocation_size = (t->hfsp_total_blocks + 7) >> 3;
  615 
  616     iso_msb ((uint8_t *) &sb.magic, 0x482b, 2);
  617     iso_msb ((uint8_t *) &sb.version, 4, 2);
  618     /* Cleanly unmounted, software locked.  */
  619     iso_msb ((uint8_t *) &sb.attributes, (1 << 8) | (1 << 15), 4);
  620     iso_msb ((uint8_t *) &sb.last_mounted_version, 0x6c69736f, 4);
  621     sb.ctime = mac_time_offset(t->now);
  622     sb.utime = mac_time_offset(t->now);
  623     sb.fsck_time = mac_time_offset(t->now);
  624     iso_msb ((uint8_t *) &sb.file_count, t->hfsp_nfiles, 4);
  625     iso_msb ((uint8_t *) &sb.folder_count, t->hfsp_ndirs - 1, 4);
  626     iso_msb ((uint8_t *) &sb.blksize, block_size, 4);
  627     iso_msb ((uint8_t *) &sb.catalog_node_id, t->hfsp_cat_id, 4);
  628     iso_msb ((uint8_t *) &sb.rsrc_clumpsize, block_size, 4);
  629     iso_msb ((uint8_t *) &sb.data_clumpsize, block_size, 4);
  630     iso_msb ((uint8_t *) &sb.total_blocks, t->hfsp_total_blocks, 4);
  631     iso_msb ((uint8_t *) &sb.encodings_bitmap + 4, 1, 4);
  632 
  633     iso_msb ((uint8_t *) &sb.allocations_file.size + 4, t->hfsp_allocation_size, 4);
  634     iso_msb ((uint8_t *) &sb.allocations_file.clumpsize, block_size, 4);
  635     iso_msb ((uint8_t *) &sb.allocations_file.blocks, (t->hfsp_allocation_size + block_size - 1) / block_size, 4);
  636     iso_msb ((uint8_t *) &sb.allocations_file.extents[0].start, t->hfsp_allocation_file_start - t->hfsp_part_start, 4);
  637     iso_msb ((uint8_t *) &sb.allocations_file.extents[0].count, (t->hfsp_allocation_size + block_size - 1) / block_size, 4);
  638 
  639     iso_msb ((uint8_t *) &sb.extents_file.size + 4, block_size, 4);
  640     iso_msb ((uint8_t *) &sb.extents_file.clumpsize, block_size, 4);
  641     iso_msb ((uint8_t *) &sb.extents_file.blocks, 1, 4);
  642     iso_msb ((uint8_t *) &sb.extents_file.extents[0].start, t->hfsp_extent_file_start - t->hfsp_part_start, 4);
  643     iso_msb ((uint8_t *) &sb.extents_file.extents[0].count, 1, 4);
  644     iso_msg_debug(t->image->id, "extent_file_start = %d\n", (int)t->hfsp_extent_file_start);
  645 
  646     iso_msb ((uint8_t *) &sb.catalog_file.size + 4, block_size * 2 * t->hfsp_nnodes, 4);
  647     iso_msb ((uint8_t *) &sb.catalog_file.clumpsize, block_size * 2, 4);
  648     iso_msb ((uint8_t *) &sb.catalog_file.blocks, 2 * t->hfsp_nnodes, 4);
  649     iso_msb ((uint8_t *) &sb.catalog_file.extents[0].start, t->hfsp_catalog_file_start - t->hfsp_part_start, 4);
  650     iso_msb ((uint8_t *) &sb.catalog_file.extents[0].count, 2 * t->hfsp_nnodes, 4);
  651     iso_msg_debug(t->image->id, "catalog_file_start = %d\n", (int)t->hfsp_catalog_file_start);
  652 
  653     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++) {
  654      iso_msb ((uint8_t *) (&sb.ppc_bootdir + i
  655                + (i == ISO_HFSPLUS_BLESS_OSX_FOLDER)),
  656           t->hfsp_bless_id[i], 4);
  657 
  658 #ifdef Libisofs_ts_debuG
  659      iso_msg_debug(t->image->id, "hfsplus bless %d written for cat_id %u",
  660                    i, t->hfsp_bless_id[i]);
  661 #endif /* Libisofs_ts_debuG */
  662 
  663     }
  664 
  665     memcpy (&sb.num_serial, &t->opts->hfsp_serial_number, 8);
  666     ret = iso_write(t, &sb, sizeof (sb));
  667     if (ret < 0)
  668       return ret;
  669     return iso_write(t, buffer, 512);
  670 }
  671 
  672 static
  673 int hfsplus_writer_write_data(IsoImageWriter *writer)
  674 {
  675     int ret;
  676     static char buffer[2 * HFSPLUS_MAX_BLOCK_SIZE];
  677     Ecma119Image *t;
  678     struct hfsplus_btnode *node_head;
  679     struct hfsplus_btheader *tree_head;
  680     int level;
  681     uint32_t curpos = 1, i, block_fac, cat_node_size, block_size;
  682 
  683     if (writer == NULL) {
  684         return ISO_NULL_POINTER;
  685     }
  686 
  687     t = writer->target;
  688     block_size = t->opts->hfsp_block_size;
  689     block_fac = t->hfsp_iso_block_fac;
  690     cat_node_size = t->hfsp_cat_node_size;
  691 
  692     iso_msg_debug(t->image->id, "(b) %d written", (int) t->bytes_written / 0x800);
  693 
  694     ret = write_sb (t);
  695     if (ret < 0)
  696       return ret;
  697 
  698     iso_msg_debug(t->image->id, "(c) %d written", (int) t->bytes_written / 0x800);
  699 
  700     iso_msg_debug(t->image->id, "real catalog_file_start = %d\n", (int)t->bytes_written / 2048);
  701 
  702     memset (buffer, 0, sizeof (buffer));
  703     node_head = (struct hfsplus_btnode *) buffer;
  704     node_head->type = 1;
  705     iso_msb ((uint8_t *) &node_head->count, 3, 2);
  706     tree_head = (struct hfsplus_btheader *) (node_head + 1);
  707     iso_msb ((uint8_t *) &tree_head->depth, t->hfsp_nlevels, 2);
  708     iso_msb ((uint8_t *) &tree_head->root, 1, 4);
  709     iso_msb ((uint8_t *) &tree_head->leaf_records, t->hfsp_nleafs, 4);
  710     iso_msb ((uint8_t *) &tree_head->first_leaf_node, t->hfsp_nnodes - t->hfsp_levels[0].level_size, 4);
  711     iso_msb ((uint8_t *) &tree_head->last_leaf_node, t->hfsp_nnodes - 1, 4);
  712     iso_msb ((uint8_t *) &tree_head->nodesize, cat_node_size, 2);
  713     iso_msb ((uint8_t *) &tree_head->keysize, 6 + 2 * LIBISO_HFSPLUS_NAME_MAX, 2);
  714     iso_msb ((uint8_t *) &tree_head->total_nodes, t->hfsp_nnodes, 4);
  715     iso_msb ((uint8_t *) &tree_head->free_nodes, 0, 4);
  716     iso_msb ((uint8_t *) &tree_head->clump_size, cat_node_size, 4);
  717     tree_head->key_compare = 0xcf;
  718     iso_msb ((uint8_t *) &tree_head->attributes, 2 | 4, 4);
  719     memset (buffer + 0xf8, -1, t->hfsp_nnodes / 8);
  720     buffer[0xf8 + (t->hfsp_nnodes / 8)] = 0xff00 >> (t->hfsp_nnodes % 8);
  721 
  722     buffer[cat_node_size - 1] = sizeof (*node_head);
  723     buffer[cat_node_size - 3] = sizeof (*node_head) + sizeof (*tree_head);
  724     buffer[cat_node_size - 5] = (char) 0xf8;
  725     buffer[cat_node_size - 7] = (char) ((cat_node_size - 8) & 0xff);
  726     buffer[cat_node_size - 8] = (cat_node_size - 8) >> 8;
  727 
  728 #ifdef Libisofs_hfsplus_verbose_debuG
  729     iso_msg_debug(t->image->id, "Write\n");
  730 #endif
  731 
  732     ret = iso_write(t, buffer, cat_node_size);
  733     if (ret < 0)
  734         return ret;
  735 
  736     for (level = t->hfsp_nlevels - 1; level > 0; level--)
  737       {
  738     uint32_t i;
  739     uint32_t next_lev = curpos + t->hfsp_levels[level].level_size;
  740     for (i = 0; i < t->hfsp_levels[level].level_size; i++)
  741       {
  742         uint32_t curoff;
  743         uint32_t j;
  744         uint32_t curnode = t->hfsp_levels[level].nodes[i].start;
  745         memset (buffer, 0, sizeof (buffer));
  746         node_head = (struct hfsplus_btnode *) buffer;
  747         if (i != t->hfsp_levels[level].level_size - 1)
  748           iso_msb ((uint8_t *) &node_head->next, curpos + i + 1, 4);
  749         if (i != 0)
  750           iso_msb ((uint8_t *) &node_head->prev, curpos + i - 1, 4);
  751         node_head->type = 0;
  752         node_head->height = level + 1;
  753         iso_msb ((uint8_t *) &node_head->count, t->hfsp_levels[level].nodes[i].cnt, 2);
  754         curoff = sizeof (struct hfsplus_btnode);
  755         for (j = 0; j < t->hfsp_levels[level].nodes[i].cnt; j++)
  756           {
  757         iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2);
  758 
  759         iso_msb ((uint8_t *) buffer + curoff, 2 * t->hfsp_levels[level - 1].nodes[curnode].strlen + 6, 2);
  760         iso_msb ((uint8_t *) buffer + curoff + 2, t->hfsp_levels[level - 1].nodes[curnode].parent_id, 4);
  761         iso_msb ((uint8_t *) buffer + curoff + 6, t->hfsp_levels[level - 1].nodes[curnode].strlen, 2);
  762         curoff += 8;
  763         memcpy ((uint8_t *) buffer + curoff, t->hfsp_levels[level - 1].nodes[curnode].str, 2 * t->hfsp_levels[level - 1].nodes[curnode].strlen);
  764         curoff += 2 * t->hfsp_levels[level - 1].nodes[curnode].strlen;
  765         iso_msb ((uint8_t *) buffer + curoff, next_lev + curnode, 4);
  766         curoff += 4;
  767         curnode++;
  768           }
  769         iso_msb ((uint8_t *) buffer +  cat_node_size - j * 2 - 2, curoff, 2);
  770 
  771 #ifdef Libisofs_hfsplus_verbose_debuG
  772         iso_msg_debug(t->image->id, "Write\n");
  773 #endif
  774 
  775         ret = iso_write(t, buffer, cat_node_size);
  776 
  777         if (ret < 0)
  778           return ret;
  779       }
  780     curpos = next_lev;
  781       }
  782 
  783     {
  784       uint32_t i;
  785       uint32_t next_lev = curpos + t->hfsp_levels[level].level_size;
  786       for (i = 0; i < t->hfsp_levels[level].level_size; i++)
  787     {
  788       uint32_t curoff;
  789       uint32_t j;
  790       uint32_t curnode = t->hfsp_levels[level].nodes[i].start;
  791       memset (buffer, 0, sizeof (buffer));
  792       node_head = (struct hfsplus_btnode *) buffer;
  793       if (i != t->hfsp_levels[level].level_size - 1)
  794         iso_msb ((uint8_t *) &node_head->next, curpos + i + 1, 4);
  795       if (i != 0)
  796         iso_msb ((uint8_t *) &node_head->prev, curpos + i - 1, 4);
  797       node_head->type = -1;
  798       node_head->height = level + 1;
  799       iso_msb ((uint8_t *) &node_head->count, t->hfsp_levels[level].nodes[i].cnt, 2);
  800       curoff = sizeof (struct hfsplus_btnode);
  801       for (j = 0; j < t->hfsp_levels[level].nodes[i].cnt; j++)
  802         {
  803           iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2);
  804 
  805 #ifdef Libisofs_hfsplus_verbose_debuG
  806 
  807           if (t->hfsp_leafs[curnode].node->name == NULL)
  808         {
  809           iso_msg_debug(t->image->id, "%d out of %d",
  810                 (int) curnode, t->hfsp_nleafs);
  811         }
  812           else
  813         {
  814           iso_msg_debug(t->image->id, "%d out of %d, %s",
  815                 (int) curnode, t->hfsp_nleafs,
  816                 t->hfsp_leafs[curnode].node->name);
  817         }
  818 
  819 #endif /* Libisofs_hfsplus_verbose_debuG */
  820 
  821           switch (t->hfsp_leafs[curnode].type)
  822         {
  823         case HFSPLUS_FILE_THREAD:
  824         case HFSPLUS_DIR_THREAD:
  825           {
  826             struct hfsplus_catfile_thread *thread;
  827             iso_msb ((uint8_t *) buffer + curoff, 6, 2);
  828             iso_msb ((uint8_t *) buffer + curoff + 2, t->hfsp_leafs[curnode].parent_id, 4);
  829             iso_msb ((uint8_t *) buffer + curoff + 6, 0, 2);
  830             curoff += 8;
  831             thread = (struct hfsplus_catfile_thread *) (buffer + curoff);
  832             ((uint8_t *) &thread->type)[1] = t->hfsp_leafs[curnode].type;
  833             iso_msb ((uint8_t *) &thread->parentid, t->hfsp_leafs[curnode].cat_id, 4);
  834             iso_msb ((uint8_t *) &thread->namelen, t->hfsp_leafs[curnode].strlen, 2);
  835             curoff += sizeof (*thread);
  836             memcpy (buffer + curoff, t->hfsp_leafs[curnode].name, t->hfsp_leafs[curnode].strlen * 2);
  837             curoff += t->hfsp_leafs[curnode].strlen * 2;
  838             break;
  839           }
  840         case HFSPLUS_FILE:
  841         case HFSPLUS_DIR:
  842           {
  843             struct hfsplus_catfile_common *common;
  844             struct hfsplus_forkdata *data_fork;
  845             iso_msb ((uint8_t *) buffer + curoff, 6 + 2 * t->hfsp_leafs[curnode].strlen, 2);
  846             iso_msb ((uint8_t *) buffer + curoff + 2, t->hfsp_leafs[curnode].parent_id, 4);
  847             iso_msb ((uint8_t *) buffer + curoff + 6, t->hfsp_leafs[curnode].strlen, 2);
  848             curoff += 8;
  849             memcpy (buffer + curoff, t->hfsp_leafs[curnode].name, t->hfsp_leafs[curnode].strlen * 2);
  850             curoff += t->hfsp_leafs[curnode].strlen * 2;
  851 
  852             common = (struct hfsplus_catfile_common *) (buffer + curoff);
  853             ((uint8_t *) &common->type)[1] = t->hfsp_leafs[curnode].type;
  854             iso_msb ((uint8_t *) &common->valence, t->hfsp_leafs[curnode].nchildren, 4);
  855             iso_msb ((uint8_t *) &common->fileid, t->hfsp_leafs[curnode].cat_id, 4);
  856             common->ctime = mac_time_offset(t->hfsp_leafs[curnode].node->ctime);
  857             common->mtime = mac_time_offset(t->hfsp_leafs[curnode].node->mtime);
  858             /* FIXME: distinguish attr_mtime and mtime.  */
  859             common->attr_mtime = mac_time_offset(t->hfsp_leafs[curnode].node->mtime);
  860             common->atime = mac_time_offset(t->hfsp_leafs[curnode].node->atime);
  861             iso_msb ((uint8_t *) &common->uid, px_get_uid (t, t->hfsp_leafs[curnode].node), 4);
  862             iso_msb ((uint8_t *) &common->gid, px_get_gid (t, t->hfsp_leafs[curnode].node), 4);
  863             iso_msb ((uint8_t *) &common->mode, px_get_mode (t, t->hfsp_leafs[curnode].node, (t->hfsp_leafs[curnode].type == HFSPLUS_DIR)), 2);
  864 
  865             /*
  866               FIXME:
  867               uint8_t user_flags;
  868               uint8_t group_flags;
  869 
  870               finder info
  871             */
  872             if (t->hfsp_leafs[curnode].type == HFSPLUS_FILE)
  873               {
  874             if (t->hfsp_leafs[curnode].unix_type == UNIX_SYMLINK)
  875               {
  876                 memcpy (common->file_type, "slnk", 4);
  877                 memcpy (common->file_creator, "rhap", 4);
  878               }
  879             else
  880               {
  881                 struct iso_hfsplus_xinfo_data *xinfo;
  882                 ret = iso_node_get_xinfo(t->hfsp_leafs[curnode].node,
  883                              iso_hfsplus_xinfo_func,
  884                              (void *) &xinfo);
  885                 if (ret > 0)
  886                   {
  887                 memcpy (common->file_type, xinfo->type_code,
  888                     4);
  889                 memcpy (common->file_creator,
  890                     xinfo->creator_code, 4);
  891 
  892 #ifdef Libisofs_ts_debuG
  893 {
  894 char crtp[14];
  895 
  896 crtp[0] = '\'';
  897 memcpy(crtp+1, xinfo->creator_code, 4);
  898 strcpy(crtp + 5, "','");
  899 memcpy(crtp + 8, xinfo->type_code, 4);
  900 crtp[12] = '\'';
  901 crtp[13]= 0;
  902 iso_msg_debug(t->image->id,
  903         "hfsplus creator,type %s to '%s/%s'",
  904         crtp, ((IsoNode *) t->hfsp_leafs[curnode].node->parent)->name,
  905         t->hfsp_leafs[curnode].node->name);
  906 }
  907 #endif /* Libisofs_ts_debuG */
  908 
  909                   }
  910                 else if (ret < 0)
  911                   return ret;
  912                 else 
  913                   {
  914                 memcpy (common->file_type, "????", 4);
  915                 memcpy (common->file_creator, "????", 4);
  916                   }
  917               }
  918 
  919             if (t->hfsp_leafs[curnode].unix_type == UNIX_SPECIAL
  920                 && (S_ISBLK(t->hfsp_leafs[curnode].node->mode)
  921                 || S_ISCHR(t->hfsp_leafs[curnode].node->mode)))
  922               iso_msb ((uint8_t *) &common->special,
  923                    (((IsoSpecial*) t->hfsp_leafs[curnode].node)->dev & 0xffffffff),
  924                    4);
  925 
  926             iso_msb ((uint8_t *) &common->flags, 2, 2);
  927               }
  928             else if (t->hfsp_leafs[curnode].type == HFSPLUS_DIR)
  929               {
  930             iso_msb ((uint8_t *) &common->flags, 0, 2);
  931               }
  932             curoff += sizeof (*common);
  933             if (t->hfsp_leafs[curnode].type == HFSPLUS_FILE)
  934               {
  935             uint64_t sz;
  936             uint32_t blk;
  937             data_fork = (struct hfsplus_forkdata *) (buffer + curoff);
  938 
  939             if (t->hfsp_leafs[curnode].unix_type == UNIX_SYMLINK)
  940               {
  941                 blk = t->hfsp_leafs[curnode].symlink_block;
  942                 sz = strlen(t->hfsp_leafs[curnode].symlink_dest);
  943               }
  944             else if (t->hfsp_leafs[curnode].unix_type == UNIX_SPECIAL)
  945               {
  946                 blk = 0;
  947                 sz = 0;
  948               }
  949             else
  950               {
  951                 ret = filesrc_block_and_size(t,
  952                              t->hfsp_leafs[curnode].file,
  953                              &blk, &sz);
  954                 if (ret <= 0)
  955                   return ret;
  956                 blk *= block_fac;
  957               }
  958             if (sz == 0)
  959               blk = t->hfsp_part_start;
  960             iso_msb ((uint8_t *) &data_fork->size, sz >> 32, 4);
  961             iso_msb ((uint8_t *) &data_fork->size + 4, sz, 4);
  962             iso_msb ((uint8_t *) &data_fork->clumpsize, block_size, 4);
  963             iso_msb ((uint8_t *) &data_fork->blocks, (sz + block_size - 1) / block_size, 4);
  964             iso_msb ((uint8_t *) &data_fork->extents[0].start, blk - t->hfsp_part_start, 4);
  965             iso_msb ((uint8_t *) &data_fork->extents[0].count, (sz + block_size - 1) / block_size, 4);
  966             
  967             curoff += sizeof (*data_fork) * 2;
  968             /* FIXME: resource fork */
  969               }
  970             break;
  971           }
  972         }
  973           curnode++;
  974         }
  975       iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2);
  976 
  977 #ifdef Libisofs_hfsplus_verbose_debuG
  978       iso_msg_debug(t->image->id, "Write\n");
  979 #endif
  980 
  981       ret = iso_write(t, buffer, cat_node_size);
  982       if (ret < 0)
  983         return ret;
  984     }
  985     curpos = next_lev;
  986     }
  987     memset (buffer, 0, sizeof (buffer));
  988 
  989     iso_msg_debug(t->image->id, "real extent_file_start = %d\n", (int)t->bytes_written / 2048);
  990 
  991     node_head = (struct hfsplus_btnode *) buffer;
  992     node_head->type = 1;
  993     iso_msb ((uint8_t *) &node_head->count, 3, 2);
  994     tree_head = (struct hfsplus_btheader *) (node_head + 1);
  995     iso_msb ((uint8_t *) &tree_head->nodesize, block_size, 2);
  996     iso_msb ((uint8_t *) &tree_head->keysize, 10, 2);
  997     iso_msb ((uint8_t *) &tree_head->total_nodes, 1, 4);
  998     iso_msb ((uint8_t *) &tree_head->free_nodes, 0, 4);
  999     iso_msb ((uint8_t *) &tree_head->clump_size, block_size, 4);
 1000     iso_msb ((uint8_t *) &tree_head->attributes, 2, 4);
 1001     buffer[0xf8] = (char) 0x80;
 1002 
 1003     buffer[block_size - 1] = sizeof (*node_head);
 1004     buffer[block_size - 3] = sizeof (*node_head) + sizeof (*tree_head);
 1005     buffer[block_size - 5] = (char) 0xf8;
 1006     buffer[block_size - 7] = (char) ((block_size - 8) & 0xff);
 1007     buffer[block_size - 8] = (block_size - 8) >> 8;
 1008 
 1009     ret = iso_write(t, buffer, block_size);
 1010     if (ret < 0)
 1011         return ret;
 1012 
 1013     iso_msg_debug(t->image->id, "(d) %d written", (int) t->bytes_written / 0x800);
 1014     memset (buffer, 0, sizeof (buffer));
 1015     for (i = 0; i < t->hfsp_nleafs; i++)
 1016       if (t->hfsp_leafs[i].unix_type == UNIX_SYMLINK)
 1017     {
 1018       int overhead;
 1019 
 1020       ret = iso_write(t, t->hfsp_leafs[i].symlink_dest,
 1021                           strlen(t->hfsp_leafs[i].symlink_dest));
 1022       if (ret < 0)
 1023         return ret;
 1024       overhead = strlen(t->hfsp_leafs[i].symlink_dest) % block_size;
 1025       if (overhead)
 1026         overhead = block_size - overhead;
 1027       ret = iso_write(t, buffer, overhead);
 1028       if (ret < 0)
 1029         return ret;
 1030     }
 1031 
 1032     /* Need to align for start of next writer */
 1033     ret = pad_up_block(t);
 1034     if (ret < 0)
 1035     return ret;
 1036 
 1037     iso_msg_debug(t->image->id, "(a) %d written", (int) t->bytes_written / 0x800);
 1038     return ISO_SUCCESS;
 1039 }
 1040 
 1041 static
 1042 int hfsplus_tail_writer_write_data(IsoImageWriter *writer)
 1043 {
 1044     int ret;
 1045     static char buffer[2 * HFSPLUS_MAX_BLOCK_SIZE];
 1046     uint32_t complete_blocks, remaining_blocks, block_size;
 1047     int over;
 1048     Ecma119Image *t;
 1049 
 1050     if (writer == NULL) {
 1051         return ISO_NULL_POINTER;
 1052     }
 1053 
 1054     t = writer->target;
 1055     block_size = t->opts->hfsp_block_size;
 1056 
 1057 #ifdef Libisofs_ts_debuG
 1058     iso_msg_debug(t->image->id, "hfsplus tail writer writes at = %.f",
 1059                   (double) t->bytes_written);
 1060 #endif
 1061 
 1062     memset (buffer, -1, sizeof (buffer));
 1063     complete_blocks = (t->hfsp_allocation_size - 1) / block_size;
 1064     remaining_blocks = t->hfsp_allocation_blocks - complete_blocks;
 1065 
 1066     while (complete_blocks--)
 1067       {
 1068     ret = iso_write(t, buffer, block_size);
 1069     if (ret < 0)
 1070       return ret;
 1071       }
 1072     over = (t->hfsp_allocation_size - 1) % block_size;
 1073     if (over)
 1074       {
 1075     memset (buffer + over, 0, sizeof (buffer) - over);
 1076     buffer[over] = 0xff00 >> (t->hfsp_total_blocks % 8);
 1077     ret = iso_write(t, buffer, block_size);
 1078     if (ret < 0)
 1079       return ret;
 1080     remaining_blocks--;
 1081       }
 1082     memset (buffer, 0, sizeof (buffer));
 1083     /* When we have both FAT and HFS+ we may to overestimate needed blocks a bit.  */
 1084     while (remaining_blocks--)
 1085       {
 1086     ret = iso_write(t, buffer, block_size);
 1087     if (ret < 0)
 1088       return ret;
 1089       }
 1090 
 1091     ret = pad_up_block(t);
 1092     if (ret < 0)
 1093     return ret;
 1094     iso_msg_debug(t->image->id, "%d written", (int) t->bytes_written);
 1095 
 1096     ret = write_sb (t);
 1097 
 1098 #ifdef Libisofs_ts_debuG
 1099     iso_msg_debug(t->image->id, "hfsplus tail writer ends at = %.f",
 1100                   (double) t->bytes_written);
 1101 #endif
 1102 
 1103     return ret;
 1104 }
 1105 
 1106 static
 1107 int hfsplus_writer_free_data(IsoImageWriter *writer)
 1108 {
 1109     /* free the Hfsplus tree */
 1110     Ecma119Image *t = writer->target;
 1111     uint32_t i;
 1112     for (i = 0; i < t->hfsp_curleaf; i++)
 1113       if (t->hfsp_leafs[i].type != HFSPLUS_FILE_THREAD
 1114       && t->hfsp_leafs[i].type != HFSPLUS_DIR_THREAD)
 1115     {
 1116       free (t->hfsp_leafs[i].name);
 1117       free (t->hfsp_leafs[i].cmp_name);
 1118       if (t->hfsp_leafs[i].symlink_dest != NULL)
 1119           free (t->hfsp_leafs[i].symlink_dest);
 1120     }
 1121     free(t->hfsp_leafs);
 1122     for (i = 0; i < t->hfsp_nlevels; i++)
 1123       free (t->hfsp_levels[i].nodes);
 1124     free(t->hfsp_levels);
 1125     return ISO_SUCCESS;
 1126 }
 1127 
 1128 static
 1129 int nop_writer_free_data(IsoImageWriter *writer)
 1130 {
 1131     return ISO_SUCCESS;
 1132 }
 1133 
 1134 
 1135 /*
 1136    ??? : Change this to binary search ?
 1137          Expected advantage is low except with prefix "MANGLED".
 1138 
 1139    @param flag bit0= array is unsorted, do not abort on first larger element
 1140    @return 0 = collision (collider in *new_idx), 1 = insert at *new_idx
 1141 */
 1142 static
 1143 int search_mangled_pos(Ecma119Image *target, uint32_t idx, uint32_t *new_idx,
 1144                        uint32_t search_start, uint32_t search_end, int flag)
 1145 {
 1146     uint32_t i;
 1147     int rel;
 1148 
 1149     for (i = search_start; i < search_end; i++) {
 1150         if (target->hfsp_leafs[i].type == HFSPLUS_DIR_THREAD ||
 1151             target->hfsp_leafs[i].type == HFSPLUS_FILE_THREAD)
 1152     continue;
 1153         rel = cmp_node(&(target->hfsp_leafs[idx]), &(target->hfsp_leafs[i]));
 1154         if (rel == 0 && idx != i) {
 1155             *new_idx = i;
 1156             return 0; /* Collision */
 1157         }
 1158         if (rel < 0 && !(flag & 1)) {
 1159             if (i <= idx)
 1160                 *new_idx = i;
 1161             else
 1162                 *new_idx = i - 1;
 1163             return 1;
 1164         }
 1165     }
 1166     *new_idx = search_end - 1;
 1167     return 1;
 1168 }
 1169 
 1170 static
 1171 void rotate_hfs_list(Ecma119Image *target, uint32_t old_idx, uint32_t new_idx,
 1172                      int flag)
 1173 {
 1174     uint32_t i, sz;
 1175     HFSPlusNode tr;
 1176 
 1177     if (old_idx == new_idx)
 1178         return;
 1179     sz = sizeof(HFSPlusNode);
 1180     memcpy(&tr, &target->hfsp_leafs[old_idx], sz);
 1181     if (old_idx > new_idx) {
 1182         for (i = old_idx; i > new_idx; i--)
 1183             memcpy(&target->hfsp_leafs[i], &target->hfsp_leafs[i - 1], sz);
 1184     } else {
 1185         for (i = old_idx; i < new_idx; i++)
 1186             memcpy(&target->hfsp_leafs[i], &target->hfsp_leafs[i + 1], sz);
 1187     }
 1188     memcpy(&target->hfsp_leafs[new_idx], &tr, sz);
 1189 }
 1190 
 1191 static
 1192 int subst_symlink_dest_comp(Ecma119Image *target, uint32_t idx,
 1193                             char **dest, unsigned int *dest_len, 
 1194                             char **comp_start, char **comp_end,
 1195                             char *new_name, int flag)
 1196 {
 1197     int new_len;
 1198     unsigned int new_dest_len;
 1199     char *new_dest, *wpt;
 1200 
 1201     new_len = strlen(new_name);
 1202     new_dest_len =
 1203                *comp_start - *dest + new_len + *dest_len - (*comp_end - *dest);
 1204     new_dest = calloc(1, new_dest_len + 1);
 1205     if (new_dest == NULL)
 1206         return ISO_OUT_OF_MEM;
 1207     wpt = new_dest;
 1208     if (*comp_start - *dest > 0)
 1209         memcpy(wpt, *dest, *comp_start - *dest);
 1210     wpt += *comp_start - *dest;
 1211     memcpy(wpt, new_name, new_len);
 1212     wpt += new_len;
 1213     if ((unsigned int) (*comp_end - *dest) < *dest_len)
 1214         memcpy(wpt, *comp_end, *dest_len - (*comp_end - *dest));
 1215     wpt += *dest_len - (*comp_end - *dest);
 1216     *wpt = 0;
 1217 
 1218     *comp_start = new_dest + (*comp_start - *dest);
 1219     *comp_end = *comp_start + new_len;
 1220     target->hfsp_leafs[idx].symlink_dest = new_dest;
 1221     *dest_len = new_dest_len;
 1222     free(*dest);
 1223     *dest = new_dest;
 1224     return ISO_SUCCESS;
 1225 }
 1226 
 1227 /* A specialized version of API call iso_tree_resolve_symlink().
 1228    It updates symlink destination components which lead to the
 1229    HFS+ node [changed_idx] in sync with resolution of the IsoImage
 1230    destination path.
 1231    It seems too much prone to weird link loopings if one would let
 1232    a function underneath iso_tree_resolve_symlink() watch out for
 1233    the IsoNode in question. Multiple passes through that node are
 1234    possible.
 1235    So this function exchanges components when encountered.
 1236 */
 1237 static
 1238 int update_symlink(Ecma119Image *target, uint32_t changed_idx, char *new_name,
 1239                    uint32_t link_idx, int *depth, int flag)
 1240 {
 1241     IsoSymlink *sym;
 1242     IsoDir *cur_dir = NULL;
 1243     IsoNode *n, *resolved_node;
 1244     char *orig_dest, *orig_start, *orig_end;
 1245     char *hfsp_dest, *hfsp_start, *hfsp_end;
 1246     int ret = 0;
 1247     unsigned int comp_len, orig_len, hfsp_len;
 1248 
 1249     if (target->hfsp_leafs[link_idx].node->type != LIBISO_SYMLINK)
 1250         return ISO_SUCCESS;
 1251     sym = (IsoSymlink *) target->hfsp_leafs[link_idx].node;
 1252     orig_dest = sym->dest;
 1253     orig_len = strlen(orig_dest);
 1254     hfsp_dest = target->hfsp_leafs[link_idx].symlink_dest;
 1255     hfsp_len = strlen(hfsp_dest);
 1256 
 1257     if (orig_dest[0] == '/') {
 1258 
 1259         /* >>> ??? How to salvage absolute links without knowing the
 1260                    path of the future mount point ?
 1261                ??? Would it be better to leave them as is ?
 1262            I can only assume that it gets mounted at / during some stage
 1263            of booting.
 1264         */;
 1265 
 1266         cur_dir = target->image->root;
 1267         orig_end = orig_dest;
 1268     } else {
 1269         cur_dir = sym->node.parent;
 1270         if (cur_dir == NULL)
 1271             cur_dir = target->image->root;
 1272         orig_end = orig_dest - 1;
 1273     }
 1274 
 1275     if (hfsp_dest[0] == '/')
 1276         hfsp_end = hfsp_dest;
 1277     else
 1278         hfsp_end = hfsp_dest - 1;
 1279 
 1280     while (orig_end < orig_dest + orig_len) {
 1281         orig_start = orig_end + 1;
 1282         hfsp_start = hfsp_end + 1;
 1283 
 1284         orig_end = strchr(orig_start, '/');
 1285         if (orig_end == NULL)
 1286             orig_end = orig_start + strlen(orig_start);
 1287         comp_len = orig_end - orig_start;
 1288         hfsp_end = strchr(hfsp_start, '/');
 1289         if (hfsp_end == NULL)
 1290             hfsp_end = hfsp_start + strlen(hfsp_start);
 1291 
 1292         if (comp_len == 0 || (comp_len == 1 && orig_start[0] == '.'))
 1293    continue;
 1294         if (comp_len == 2 && orig_start[0] == '.' && orig_start[1] == '.') {
 1295             cur_dir = cur_dir->node.parent;
 1296             if (cur_dir == NULL) /* link shoots over root */
 1297                 return ISO_SUCCESS;
 1298    continue;
 1299         }
 1300 
 1301         /* Search node in cur_dir */
 1302         for (n = cur_dir->children; n != NULL; n = n->next)
 1303             if (strncmp(orig_start, n->name, comp_len) == 0 &&
 1304                 strlen(n->name) == comp_len)
 1305         break;
 1306         if (n == NULL) /* dead link */
 1307             return ISO_SUCCESS;
 1308 
 1309         if (n == target->hfsp_leafs[changed_idx].node) {
 1310             iso_msg_debug(target->image->id,
 1311                           "     link path '%s' touches RR '%s', HFS+ '%s'",
 1312                           orig_dest, (n->name != NULL ? n->name : ""),
 1313                           new_name);
 1314 
 1315             /* Exchange HFS+ component by new_name */
 1316             ret = subst_symlink_dest_comp(target, link_idx,
 1317                                           &hfsp_dest, &hfsp_len,
 1318                                           &hfsp_start, &hfsp_end, new_name, 0);
 1319             if (ret < 0)
 1320                 return ret;
 1321         }
 1322 
 1323         if (n->type == LIBISO_DIR) {
 1324             cur_dir = (IsoDir *) n;
 1325         } else if (n->type == LIBISO_SYMLINK) {
 1326             /* Resolve link and check whether it is a directory */
 1327             if (*depth >= LIBISO_MAX_LINK_DEPTH)
 1328                 return ISO_SUCCESS;
 1329             (*depth)++;
 1330             ret = iso_tree_resolve_symlink(target->image, (IsoSymlink *) n,
 1331                                            &resolved_node, depth, 0);
 1332             if (ret == (int) ISO_DEAD_SYMLINK || ret == (int) ISO_DEEP_SYMLINK)
 1333                 return ISO_SUCCESS;
 1334             if (ret < 0)
 1335                 return ret;
 1336             if (resolved_node->type != LIBISO_DIR)
 1337                 return ISO_SUCCESS;
 1338             cur_dir = (IsoDir *) resolved_node;
 1339         } else {
 1340     break;
 1341         }
 1342     }
 1343     return ISO_SUCCESS;
 1344 }
 1345 
 1346 /* Find the other nodes with old_name and switch to new .name
 1347    One could make assumptions where name-followers are.
 1348    But then there are still the symbolic links. They can be located anywhere.
 1349 */
 1350 static
 1351 int update_name_followers(Ecma119Image *target, uint32_t idx, char *new_name,
 1352                           uint16_t *old_name, uint16_t *old_cmp_name,
 1353                           uint32_t old_strlen)
 1354 {
 1355     uint32_t i;
 1356     int ret, link_depth;
 1357 
 1358     for (i = 0; i < target->hfsp_nleafs; i++) {
 1359         if (target->hfsp_leafs[i].unix_type == UNIX_SYMLINK) {
 1360             link_depth = 0;
 1361             ret = update_symlink(target, idx, new_name, i, &link_depth, 0);
 1362             if (ret < 0)
 1363                 return ret;
 1364         }
 1365         if (target->hfsp_leafs[i].name != old_name)
 1366     continue;
 1367         target->hfsp_leafs[i].name = target->hfsp_leafs[idx].name;
 1368         target->hfsp_leafs[i].strlen = target->hfsp_leafs[idx].strlen;
 1369         if (target->hfsp_leafs[i].cmp_name == old_cmp_name)
 1370             target->hfsp_leafs[i].cmp_name = target->hfsp_leafs[idx].cmp_name;
 1371         if (target->hfsp_leafs[i].strlen > old_strlen)
 1372             target->hfsp_leafs[i].used_size += (target->hfsp_leafs[i].strlen -
 1373                                                 old_strlen) * 2;
 1374         else
 1375             target->hfsp_leafs[i].used_size -= 2 * (old_strlen -
 1376                                                  target->hfsp_leafs[i].strlen);
 1377     }
 1378     return 1;
 1379 }
 1380 
 1381 
 1382 /* @param flag bit0= node is new: do not rotate, do not update followers
 1383 */
 1384 static
 1385 int try_mangle(Ecma119Image *target, uint32_t idx, uint32_t prev_idx,
 1386                uint32_t search_start, uint32_t search_end,
 1387                uint32_t *new_idx, char *prefix, int flag)
 1388 {
 1389     int i, ret = 0;
 1390     char new_name[LIBISO_HFSPLUS_NAME_MAX + 1], number[9];
 1391     uint16_t *old_name, *old_cmp_name;
 1392     uint32_t old_strlen;
 1393 
 1394     old_name = target->hfsp_leafs[idx].name;
 1395     old_cmp_name = target->hfsp_leafs[idx].cmp_name;
 1396     old_strlen = target->hfsp_leafs[idx].strlen;
 1397 
 1398     for (i = -1; i < 0x7fffffff; i++) {
 1399         if (i == -1)
 1400             number[0] = 0;
 1401         else
 1402             sprintf(number, "%X", (unsigned int) i);
 1403         if (strlen(prefix) + 1 + strlen(number) > LIBISO_HFSPLUS_NAME_MAX) {
 1404             ret = 0;
 1405             goto no_success;
 1406         }
 1407 
 1408         /* "-" would sort lower than capital letters ,
 1409            traditional "_" causes longer rotations
 1410          */
 1411         sprintf(new_name, "%s_%s", prefix, number);
 1412 
 1413         /* The original name is kept until the end of the try */
 1414         if (target->hfsp_leafs[idx].name != old_name)
 1415             free(target->hfsp_leafs[idx].name);
 1416         if (target->hfsp_leafs[idx].cmp_name != old_cmp_name)
 1417             free(target->hfsp_leafs[idx].cmp_name);
 1418 
 1419 
 1420         ret = set_hfsplus_name(target, new_name, &(target->hfsp_leafs[idx]));
 1421         if (ret < 0)
 1422             goto no_success;
 1423 
 1424         ret = search_mangled_pos(target, idx, new_idx, search_start,
 1425                                  search_end, (flag & 1));
 1426         if (ret < 0)
 1427             goto no_success;
 1428         if (ret == 0)
 1429     continue; /* collision */
 1430         if (flag & 1)
 1431             *new_idx = idx;
 1432         else
 1433             rotate_hfs_list(target, idx, *new_idx, 0);
 1434 
 1435         /* >>> Get full ISO-RR paths of colliding nodes */;
 1436         /* >>> iso_tree_get_node_path(node); */
 1437 
 1438         iso_msg_debug(target->image->id,
 1439                   "HFS+ name collision with \"%s\" : \"%s\" renamed to \"%s\"",
 1440                   target->hfsp_leafs[prev_idx].node->name,
 1441                   target->hfsp_leafs[*new_idx].node->name, new_name);
 1442 
 1443     break;    
 1444     }
 1445     target->hfsp_leafs[*new_idx].used_size +=
 1446                         (target->hfsp_leafs[*new_idx].strlen - old_strlen) * 2;
 1447 
 1448     if (!(flag & 1)) {
 1449         ret = update_name_followers(target, *new_idx, new_name,
 1450                                     old_name, old_cmp_name, old_strlen);
 1451         if (ret < 0)
 1452             goto no_success;
 1453     }
 1454 
 1455     free(old_name);
 1456     free(old_cmp_name);
 1457     return 1;
 1458 
 1459 no_success:;
 1460     target->hfsp_leafs[idx].name = old_name;
 1461     target->hfsp_leafs[idx].cmp_name = old_cmp_name;
 1462     target->hfsp_leafs[idx].strlen = old_strlen;
 1463     return ret;
 1464 }
 1465 
 1466 static
 1467 int mangle_leafs(Ecma119Image *target, int flag)
 1468 {
 1469     int ret;
 1470     uint32_t i, new_idx, prev, first_prev;
 1471 
 1472     iso_msg_debug(target->image->id, "%s", "HFS+ mangling started ...");
 1473 
 1474     /* Look for the first owner of a name */
 1475     for (prev = 0; prev < target->hfsp_nleafs; prev++) {
 1476         if (target->hfsp_leafs[prev].type == HFSPLUS_DIR_THREAD ||
 1477             target->hfsp_leafs[prev].type == HFSPLUS_FILE_THREAD ||
 1478             target->hfsp_leafs[prev].node == NULL ||
 1479             target->hfsp_leafs[prev].name == NULL ||
 1480             target->hfsp_leafs[prev].cmp_name == NULL)
 1481     continue;
 1482         if (target->hfsp_leafs[prev].node->name == NULL)
 1483     continue;
 1484     break;
 1485     }
 1486 
 1487     first_prev = prev; 
 1488     for (i = prev + 1; i < target->hfsp_nleafs; i++) {
 1489         if (target->hfsp_leafs[i].type == HFSPLUS_DIR_THREAD ||
 1490             target->hfsp_leafs[i].type == HFSPLUS_FILE_THREAD ||
 1491             target->hfsp_leafs[i].node == NULL ||
 1492             target->hfsp_leafs[i].name == NULL ||
 1493             target->hfsp_leafs[i].cmp_name == NULL)
 1494     continue;
 1495         if (target->hfsp_leafs[i].node->name == NULL)
 1496     continue;
 1497         if (cmp_node(&(target->hfsp_leafs[prev]), &(target->hfsp_leafs[i]))
 1498             != 0) {
 1499             prev = i;
 1500     continue;
 1501         }
 1502         target->hfsp_collision_count++;
 1503 
 1504 
 1505 #ifdef Libisofs_with_mangle_masK
 1506 
 1507         /* >>> Development sketch: */
 1508 
 1509         /* >>> define in libisofs.h : enum with LIBISO_NOMANGLE_xyz 
 1510                                       xinfo function for uint32_t
 1511         */
 1512 
 1513         /* >>> inquire xinfo for mangle protection : uint32_t mangle_mask */
 1514 
 1515         if (mangle_mask & (1 << LIBISO_NOMANGLE_HFSPLUS)) {
 1516 
 1517             /* >>> Get full ISO-RR paths of colliding nodes and print
 1518                    error message */;
 1519 
 1520             return ISO_HFSP_NO_MANGLE;
 1521         } else {
 1522 
 1523 #else /* Libisofs_with_mangle_masK */
 1524 
 1525         {
 1526 
 1527 #endif /* ! Libisofs_with_mangle_masK */
 1528 
 1529 
 1530             ret= try_mangle(target, i, prev, i + 1, target->hfsp_nleafs,
 1531                             &new_idx, target->hfsp_leafs[i].node->name, 0);
 1532             if (ret == 0)
 1533                 ret= try_mangle(target, i, prev, 0, target->hfsp_nleafs,
 1534                                 &new_idx, "MANGLED", 0);
 1535             if (ret < 0)
 1536                 return(ret);
 1537             if (new_idx > i) {
 1538                 i--; /* an unprocessed candidate has been rotated to i */
 1539             } else {
 1540                 prev = i; /* advance */
 1541             }
 1542         }
 1543     }
 1544 
 1545     if (target->hfsp_collision_count > 0) {
 1546         /* Mangling cannot be properly performed if the name owners do not
 1547            stay in sorting order.
 1548         */
 1549         prev = first_prev;
 1550         for (i = prev + 1; i < target->hfsp_nleafs; i++) {
 1551             if (target->hfsp_leafs[i].type == HFSPLUS_DIR_THREAD ||
 1552                 target->hfsp_leafs[i].type == HFSPLUS_FILE_THREAD ||
 1553                 target->hfsp_leafs[i].node == NULL ||
 1554                 target->hfsp_leafs[i].name == NULL ||
 1555                 target->hfsp_leafs[i].cmp_name == NULL)
 1556         continue;
 1557             if (target->hfsp_leafs[i].node->name == NULL)
 1558         continue;
 1559             if (cmp_node(&(target->hfsp_leafs[prev]),
 1560                          &(target->hfsp_leafs[i])) > 0) {
 1561 
 1562                 iso_msg_debug(target->image->id,
 1563                      "*********** Mangling messed up sorting *************\n");
 1564 
 1565         break;
 1566             }
 1567             prev = i;
 1568         }
 1569 
 1570         /* Only the owners of names were considered during mangling.
 1571            The HFSPLUS_*_THREAD types must get in line by sorting again.
 1572         */
 1573         qsort(target->hfsp_leafs, target->hfsp_nleafs,
 1574               sizeof(*target->hfsp_leafs), cmp_node);
 1575     }
 1576     iso_msg_debug(target->image->id,
 1577                   "HFS+ mangling done. Resolved Collisions: %lu",
 1578                   (unsigned long) target->hfsp_collision_count);
 1579     return ISO_SUCCESS;
 1580 }
 1581 
 1582 void iso_setup_hfsplus_block_size(Ecma119Image *target)
 1583 {
 1584     if (target->opts->hfsp_block_size == 0)
 1585         target->opts->hfsp_block_size = HFSPLUS_DEFAULT_BLOCK_SIZE;
 1586     target->hfsp_cat_node_size = 2 * target->opts->hfsp_block_size;
 1587     target->hfsp_iso_block_fac = 2048 / target->opts->hfsp_block_size;
 1588 }
 1589 
 1590 int hfsplus_writer_create(Ecma119Image *target)
 1591 {
 1592     int ret;
 1593     IsoImageWriter *writer = NULL;
 1594     int max_levels;
 1595     int level = 0;
 1596     IsoNode *pos;
 1597     IsoDir *dir;
 1598     int i;
 1599     uint32_t cat_node_size;
 1600 
 1601     writer = calloc(1, sizeof(IsoImageWriter));
 1602     if (writer == NULL) {
 1603         ret = ISO_OUT_OF_MEM;
 1604         goto ex;
 1605     }
 1606 
 1607     make_hfsplus_decompose_pages();
 1608     make_hfsplus_class_pages();
 1609 
 1610     iso_setup_hfsplus_block_size(target);
 1611     cat_node_size = target->hfsp_cat_node_size;
 1612 
 1613     writer->compute_data_blocks = hfsplus_writer_compute_data_blocks;
 1614     writer->write_vol_desc = nop_writer_write_vol_desc;
 1615     writer->write_data = hfsplus_writer_write_data;
 1616     writer->free_data = hfsplus_writer_free_data;
 1617     writer->data = NULL;
 1618     writer->target = target;
 1619 
 1620     iso_msg_debug(target->image->id, "Creating HFS+ tree...");
 1621     target->hfsp_nfiles = 0;
 1622     target->hfsp_ndirs = 0;
 1623     target->hfsp_cat_id = 16;
 1624     ret = hfsplus_count_tree(target, (IsoNode*)target->image->root);
 1625     if (ret < 0)
 1626         goto ex;
 1627 
 1628     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
 1629       target->hfsp_bless_id[i] = 0;
 1630 
 1631     target->hfsp_nleafs = 2 * (target->hfsp_nfiles + target->hfsp_ndirs);
 1632     target->hfsp_curleaf = 0;
 1633 
 1634     target->hfsp_leafs = calloc (target->hfsp_nleafs, sizeof (target->hfsp_leafs[0]));
 1635     if (target->hfsp_leafs == NULL) {
 1636         ret = ISO_OUT_OF_MEM;
 1637         goto ex;
 1638     }
 1639     ret = set_hfsplus_name (target, target->image->volume_id,
 1640                             &target->hfsp_leafs[target->hfsp_curleaf]);
 1641     if (ret < 0)
 1642         goto ex;
 1643     target->hfsp_leafs[target->hfsp_curleaf].node = (IsoNode *) target->image->root;
 1644     target->hfsp_leafs[target->hfsp_curleaf].used_size = target->hfsp_leafs[target->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common);
 1645 
 1646     target->hfsp_leafs[target->hfsp_curleaf].type = HFSPLUS_DIR;
 1647     target->hfsp_leafs[target->hfsp_curleaf].file = 0;
 1648     target->hfsp_leafs[target->hfsp_curleaf].cat_id = 2;
 1649     target->hfsp_leafs[target->hfsp_curleaf].parent_id = 1;
 1650     target->hfsp_leafs[target->hfsp_curleaf].nchildren = 0;
 1651     target->hfsp_leafs[target->hfsp_curleaf].unix_type = UNIX_NONE;
 1652     target->hfsp_curleaf++;
 1653 
 1654     target->hfsp_leafs[target->hfsp_curleaf].name = target->hfsp_leafs[target->hfsp_curleaf - 1].name;
 1655     target->hfsp_leafs[target->hfsp_curleaf].cmp_name = 0;
 1656     target->hfsp_leafs[target->hfsp_curleaf].strlen = target->hfsp_leafs[target->hfsp_curleaf - 1].strlen;
 1657     target->hfsp_leafs[target->hfsp_curleaf].used_size = target->hfsp_leafs[target->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_thread);
 1658     target->hfsp_leafs[target->hfsp_curleaf].node = (IsoNode *) target->image->root;
 1659     target->hfsp_leafs[target->hfsp_curleaf].type = HFSPLUS_DIR_THREAD;
 1660     target->hfsp_leafs[target->hfsp_curleaf].file = 0;
 1661     target->hfsp_leafs[target->hfsp_curleaf].cat_id = 1;
 1662     target->hfsp_leafs[target->hfsp_curleaf].parent_id = 2;
 1663     target->hfsp_leafs[target->hfsp_curleaf].unix_type = UNIX_NONE;
 1664     target->hfsp_curleaf++;
 1665 
 1666     dir = (IsoDir*)target->image->root;
 1667 
 1668     pos = dir->children;
 1669     while (pos)
 1670       {
 1671     int cret;
 1672     cret = create_tree(target, pos, 2);
 1673     if (cret < 0) {
 1674         ret = cret;
 1675         goto ex;
 1676     }
 1677     pos = pos->next;
 1678     if (cret > 0)
 1679         target->hfsp_leafs[0].nchildren++;
 1680       }
 1681 
 1682     qsort(target->hfsp_leafs, target->hfsp_nleafs,
 1683           sizeof(*target->hfsp_leafs), cmp_node);
 1684 
 1685     ret = mangle_leafs(target, 0);
 1686     if (ret < 0)
 1687         goto ex;
 1688 
 1689     for (max_levels = 0; target->hfsp_nleafs >> max_levels; max_levels++);
 1690     max_levels += 2;
 1691     target->hfsp_levels = calloc (max_levels, sizeof (target->hfsp_levels[0]));
 1692     if (target->hfsp_levels == NULL) {
 1693     ret = ISO_OUT_OF_MEM;
 1694     goto ex;
 1695     }
 1696 
 1697     target->hfsp_nnodes = 1;
 1698     {
 1699       uint32_t last_start = 0;
 1700       uint32_t i;
 1701       unsigned bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2;
 1702 
 1703       target->hfsp_levels[level].nodes = calloc ((target->hfsp_nleafs + 1),  sizeof (target->hfsp_levels[level].nodes[0]));
 1704       if (!target->hfsp_levels[level].nodes) {
 1705       ret = ISO_OUT_OF_MEM;
 1706       goto ex;
 1707       }
 1708       target->hfsp_levels[level].level_size = 0;  
 1709       for (i = 0; i < target->hfsp_nleafs; i++)
 1710     {
 1711       if (bytes_rem < target->hfsp_leafs[i].used_size)
 1712         {
 1713           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].start = last_start;
 1714           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].cnt = i - last_start;
 1715           if (target->hfsp_leafs[last_start].cmp_name)
 1716         {
 1717           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = target->hfsp_leafs[last_start].strlen;
 1718           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = target->hfsp_leafs[last_start].name;
 1719         }
 1720           else
 1721         {
 1722           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = 0;
 1723           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = NULL;
 1724         }
 1725           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_leafs[last_start].parent_id;
 1726           target->hfsp_levels[level].level_size++;
 1727           last_start = i;
 1728           bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2;
 1729         }
 1730       bytes_rem -= target->hfsp_leafs[i].used_size;
 1731     }
 1732 
 1733       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].start = last_start;
 1734       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].cnt = i - last_start;
 1735       if (target->hfsp_leafs[last_start].cmp_name)
 1736     {
 1737       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = target->hfsp_leafs[last_start].strlen;
 1738       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = target->hfsp_leafs[last_start].name;
 1739     }
 1740       else
 1741     {
 1742       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = 0;
 1743       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = NULL;
 1744     }
 1745       target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_leafs[last_start].parent_id;
 1746       target->hfsp_levels[level].level_size++;
 1747       target->hfsp_nnodes += target->hfsp_levels[level].level_size;
 1748     }
 1749 
 1750     while (target->hfsp_levels[level].level_size > 1)
 1751       {
 1752     uint32_t last_start = 0;
 1753     uint32_t i;
 1754     uint32_t last_size;
 1755     unsigned bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2;
 1756 
 1757     last_size = target->hfsp_levels[level].level_size;
 1758 
 1759     level++;
 1760 
 1761     target->hfsp_levels[level].nodes = calloc (((last_size + 1) / 2),  sizeof (target->hfsp_levels[level].nodes[0]));
 1762     if (!target->hfsp_levels[level].nodes) {
 1763         ret = ISO_OUT_OF_MEM;
 1764         goto ex;
 1765         }
 1766     
 1767     target->hfsp_levels[level].level_size = 0;  
 1768 
 1769     for (i = 0; i < last_size; i++)
 1770       {
 1771         uint32_t used_size;
 1772         used_size = target->hfsp_levels[level - 1].nodes[i].strlen * 2 + 14;
 1773         if (bytes_rem < used_size)
 1774         {
 1775           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].start = last_start;
 1776           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].cnt = i - last_start;
 1777           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = target->hfsp_levels[level - 1].nodes[last_start].strlen;
 1778           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = target->hfsp_levels[level - 1].nodes[last_start].str;
 1779           target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_levels[level - 1].nodes[last_start].parent_id;
 1780           target->hfsp_levels[level].level_size++;
 1781           last_start = i;
 1782           bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2;
 1783         }
 1784       bytes_rem -= used_size;
 1785     }
 1786 
 1787     target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].start = last_start;
 1788     target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].cnt = i - last_start;
 1789     target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].strlen = target->hfsp_levels[level - 1].nodes[last_start].strlen;
 1790     target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].str = target->hfsp_levels[level - 1].nodes[last_start].str;
 1791     target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_levels[level - 1].nodes[last_start].parent_id;
 1792     target->hfsp_levels[level].level_size++;
 1793     target->hfsp_nnodes += target->hfsp_levels[level].level_size;
 1794       }
 1795 
 1796     target->hfsp_nlevels = level + 1;
 1797 
 1798     if (target->hfsp_nnodes > (cat_node_size - 0x100) * 8)
 1799       {
 1800     iso_msg_submit(target->image->id, ISO_HFSPLUS_TOO_MANY_FILES, 0,
 1801             "HFS+ map nodes aren't implemented");
 1802     ret = ISO_HFSPLUS_TOO_MANY_FILES;
 1803     goto ex;
 1804       }
 1805 
 1806     /* add this writer to image */
 1807     target->writers[target->nwriters++] = writer;
 1808     writer = NULL;
 1809 
 1810     ret = ISO_SUCCESS;
 1811 ex:;
 1812     if (writer != NULL)
 1813         free(writer);
 1814     return ret;
 1815 }
 1816 
 1817 int hfsplus_tail_writer_create(Ecma119Image *target)
 1818 {
 1819     IsoImageWriter *writer;
 1820 
 1821     writer = calloc(1, sizeof(IsoImageWriter));
 1822     if (writer == NULL) {
 1823         return ISO_OUT_OF_MEM;
 1824     }
 1825 
 1826     writer->compute_data_blocks = hfsplus_tail_writer_compute_data_blocks;
 1827     writer->write_vol_desc = nop_writer_write_vol_desc;
 1828     writer->write_data = hfsplus_tail_writer_write_data;
 1829     writer->free_data = nop_writer_free_data;
 1830     writer->data = NULL;
 1831     writer->target = target;
 1832 
 1833     /* add this writer to image */
 1834     target->writers[target->nwriters++] = writer;
 1835 
 1836     return ISO_SUCCESS;
 1837 }
 1838 
 1839 
 1840 /* API */
 1841 int iso_hfsplus_xinfo_func(void *data, int flag)
 1842 {
 1843     if (flag == 1 && data != NULL)
 1844         free(data);
 1845     return 1;
 1846 }
 1847 
 1848 /* API */
 1849 struct iso_hfsplus_xinfo_data *iso_hfsplus_xinfo_new(int flag)
 1850 {
 1851     struct iso_hfsplus_xinfo_data *o;
 1852 
 1853     o = calloc(1, sizeof(struct iso_hfsplus_xinfo_data));
 1854     if (o == NULL)
 1855         return NULL;
 1856     o->version = 0;
 1857     return o;
 1858 }
 1859 
 1860 /* The iso_node_xinfo_cloner function which gets associated to
 1861  * iso_hfsplus_xinfo_func by iso_init() or iso_init_with_flag() via
 1862  * iso_node_xinfo_make_clonable()
 1863  */
 1864 int iso_hfsplus_xinfo_cloner(void *old_data, void **new_data, int flag)
 1865 {
 1866     *new_data = NULL;
 1867     if (flag)
 1868         return ISO_XINFO_NO_CLONE;
 1869     if (old_data == NULL)
 1870         return 0;
 1871     *new_data = iso_hfsplus_xinfo_new(0);
 1872     if(*new_data == NULL)
 1873        return ISO_OUT_OF_MEM;
 1874     memcpy(*new_data, old_data, sizeof(struct iso_hfsplus_xinfo_data));
 1875     return ISO_SUCCESS;
 1876 }
 1877