xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

hfsplus.c
Go to the documentation of this file.
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
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
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) {
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
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;
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;
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;
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  {
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 
384  t->hfsp_leafs[t->hfsp_curleaf].cmp_name = NULL;
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;
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
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
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 
555 {
556  return ISO_SUCCESS;
557 }
558 
559 static
561 {
562  if (t->replace_uid) {
563  return t->uid;
564  } else {
565  return n->uid;
566  }
567 }
568 
569 static
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
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);
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
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
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,
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;
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
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
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
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 
1583 {
1584  if (target->opts->hfsp_block_size == 0)
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 
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 
1609 
1611  cat_node_size = target->hfsp_cat_node_size;
1612 
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  {
1801  "HFS+ map nodes aren't implemented");
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 
1818 {
1819  IsoImageWriter *writer;
1820 
1821  writer = calloc(1, sizeof(IsoImageWriter));
1822  if (writer == NULL) {
1823  return ISO_OUT_OF_MEM;
1824  }
1825 
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 */
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 
int iso_write(Ecma119Image *target, void *buf, size_t count)
Definition: ecma119.c:3471
struct hfsplus_node HFSPlusNode
Definition: ecma119.h:552
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
Definition: filesrc.c:69
static int update_name_followers(Ecma119Image *target, uint32_t idx, char *new_name, uint16_t *old_name, uint16_t *old_cmp_name, uint32_t old_strlen)
Definition: hfsplus.c:1351
int write_sb(Ecma119Image *t)
Definition: hfsplus.c:595
int nop_writer_write_vol_desc(IsoImageWriter *writer)
Definition: hfsplus.c:554
static uid_t px_get_uid(Ecma119Image *t, IsoNode *n)
Definition: hfsplus.c:560
void iso_setup_hfsplus_block_size(Ecma119Image *target)
Definition: hfsplus.c:1582
#define HFSPLUS_MAX_BLOCK_SIZE
Definition: hfsplus.c:51
static int subst_symlink_dest_comp(Ecma119Image *target, uint32_t idx, char **dest, unsigned int *dest_len, char **comp_start, char **comp_end, char *new_name, int flag)
Definition: hfsplus.c:1192
static int update_symlink(Ecma119Image *target, uint32_t changed_idx, char *new_name, uint32_t link_idx, int *depth, int flag)
Definition: hfsplus.c:1238
static int filesrc_block_and_size(Ecma119Image *t, IsoFileSrc *src, uint32_t *start_block, uint64_t *total_size)
Definition: hfsplus.c:79
static int hfsplus_writer_free_data(IsoImageWriter *writer)
Definition: hfsplus.c:1107
int hfsplus_writer_create(Ecma119Image *target)
Definition: hfsplus.c:1590
static uid_t px_get_gid(Ecma119Image *t, IsoNode *n)
Definition: hfsplus.c:570
static uint32_t mac_time_offset(uint32_t t)
Definition: hfsplus.c:546
uint16_t iso_hfsplus_cichar(uint16_t x)
Definition: hfsplus_case.c:444
static void rotate_hfs_list(Ecma119Image *target, uint32_t old_idx, uint32_t new_idx, int flag)
Definition: hfsplus.c:1171
static int hfsplus_writer_write_data(IsoImageWriter *writer)
Definition: hfsplus.c:673
static int hfsplus_tail_writer_write_data(IsoImageWriter *writer)
Definition: hfsplus.c:1042
static int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
Definition: hfsplus.c:299
static int hfsplus_tail_writer_compute_data_blocks(IsoImageWriter *writer)
Definition: hfsplus.c:438
static int nop_writer_free_data(IsoImageWriter *writer)
Definition: hfsplus.c:1129
#define HFSPLUS_DEFAULT_BLOCK_SIZE
Definition: hfsplus.c:47
int hfsplus_tail_writer_create(Ecma119Image *target)
Definition: hfsplus.c:1817
static int pad_up_block(Ecma119Image *t)
Definition: hfsplus.c:60
static int hfsplus_count_tree(Ecma119Image *t, IsoNode *iso)
Definition: hfsplus.c:250
struct iso_hfsplus_xinfo_data * iso_hfsplus_xinfo_new(int flag)
Definition: hfsplus.c:1849
static int cmp_node(const void *f1, const void *f2)
Definition: hfsplus.c:416
static uint8_t get_class(uint16_t v)
Definition: hfsplus.c:106
int iso_hfsplus_xinfo_func(void *data, int flag)
Definition: hfsplus.c:1841
int iso_hfsplus_xinfo_cloner(void *old_data, void **new_data, int flag)
Definition: hfsplus.c:1864
static int try_mangle(Ecma119Image *target, uint32_t idx, uint32_t prev_idx, uint32_t search_start, uint32_t search_end, uint32_t *new_idx, char *prefix, int flag)
Definition: hfsplus.c:1385
static mode_t px_get_mode(Ecma119Image *t, IsoNode *n, int isdir)
Definition: hfsplus.c:580
static int mangle_leafs(Ecma119Image *target, int flag)
Definition: hfsplus.c:1467
static int search_mangled_pos(Ecma119Image *target, uint32_t idx, uint32_t *new_idx, uint32_t search_start, uint32_t search_end, int flag)
Definition: hfsplus.c:1143
static int set_hfsplus_name(Ecma119Image *t, char *name, HFSPlusNode *node)
Definition: hfsplus.c:235
static int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer)
Definition: hfsplus.c:494
int iso_get_hfsplus_name(char *input_charset, int imgid, char *name, uint16_t **result, uint32_t *result_len, uint16_t **cmp_name)
Definition: hfsplus.c:118
uint16_t * hfsplus_class_pages[256]
void make_hfsplus_class_pages()
@ HFSPLUS_FILE_THREAD
Definition: hfsplus.h:27
@ HFSPLUS_DIR_THREAD
Definition: hfsplus.h:26
@ HFSPLUS_DIR
Definition: hfsplus.h:24
@ HFSPLUS_FILE
Definition: hfsplus.h:25
void make_hfsplus_decompose_pages()
#define HFSPLUS_MAX_DECOMPOSE_LEN
Definition: hfsplus.h:187
uint16_t(*[256] hfsplus_decompose_pages)[4+1]
#define LIBISO_HFSPLUS_NAME_MAX
Definition: hfsplus.h:20
void iso_msb(uint8_t *buf, uint32_t num, int bytes)
Definition: util.c:1494
int ucscmp(const uint16_t *s1, const uint16_t *s2)
Definition: util.c:1371
int str2utf16be(const char *icharset, const char *input, uint16_t **output)
Definition: util.c:687
uint16_t iso_htons(uint16_t v)
Definition: util.c:2313
size_t ucslen(const uint16_t *str)
Definition: util.c:1331
uint16_t iso_ntohs(uint16_t v)
Definition: util.c:2308
#define ISO_DEEP_SYMLINK
Definition: libisofs.h:9156
#define ISO_SUCCESS
Definition: libisofs.h:8719
#define ISO_DEAD_SYMLINK
Definition: libisofs.h:9153
#define ISO_HFSP_NO_MANGLE
Definition: libisofs.h:9150
@ LIBISO_BOOT
Definition: libisofs.h:233
@ LIBISO_DIR
Definition: libisofs.h:229
@ LIBISO_FILE
Definition: libisofs.h:230
@ LIBISO_SYMLINK
Definition: libisofs.h:231
@ LIBISO_SPECIAL
Definition: libisofs.h:232
#define ISO_OUT_OF_MEM
Definition: libisofs.h:8745
int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data)
Definition: node.c:213
#define ISO_XINFO_NO_CLONE
Definition: libisofs.h:9093
#define LIBISO_MAX_LINK_DEPTH
Definition: libisofs.h:6589
#define ISO_SECT_SCATTERED
Definition: libisofs.h:9116
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
@ LIBISO_HIDE_ON_HFSPLUS
Definition: libisofs.h:311
int iso_tree_resolve_symlink(IsoImage *img, IsoSymlink *sym, IsoNode **res, int *depth, int flag)
Definition: tree.c:1578
#define ISO_HFSPLUS_TOO_MANY_FILES
Definition: libisofs.h:9246
@ ISO_HFSPLUS_BLESS_OSX_FOLDER
Definition: libisofs.h:8595
@ ISO_HFSPLUS_BLESS_MAX
Definition: libisofs.h:8598
#define ISO_ASSERT_FAILURE
Definition: libisofs.h:8737
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt,...)
Definition: messages.c:579
void iso_msg_debug(int imgid, const char *fmt,...)
Definition: messages.c:253
Definition: node.h:140
IsoNode * children
Definition: node.h:144
IsoNode node
Definition: node.h:141
struct iso_file_section * sections
Definition: filesrc.h:56
int nsections
Definition: filesrc.h:57
Definition: node.h:149
Ecma119Image * target
Definition: writer.h:28
int(* write_data)(IsoImageWriter *writer)
Definition: writer.h:23
void * data
Definition: writer.h:27
int(* compute_data_blocks)(IsoImageWriter *writer)
Definition: writer.h:19
int(* write_vol_desc)(IsoImageWriter *writer)
Definition: writer.h:21
int(* free_data)(IsoImageWriter *writer)
Definition: writer.h:25
int id
Definition: image.h:97
char * volume_id
Definition: image.h:47
IsoDir * root
Definition: image.h:43
Definition: node.h:100
gid_t gid
Definition: node.h:117
time_t ctime
Definition: node.h:122
uid_t uid
Definition: node.h:116
char * name
Definition: node.h:113
time_t atime
Definition: node.h:120
IsoDir * parent
Definition: node.h:126
enum IsoNodeType type
Definition: node.h:111
mode_t mode
Definition: node.h:115
int hidden
Definition: node.h:124
IsoNode * next
Definition: node.h:131
time_t mtime
Definition: node.h:121
uint32_t hfsp_collision_count
Definition: ecma119.h:671
IsoImage * image
Definition: ecma119.h:560
uint32_t hfsp_part_start
Definition: ecma119.h:657
uint32_t hfsp_curleaf
Definition: ecma119.h:668
IsoNode * hfsplus_blessed[ISO_HFSPLUS_BLESS_MAX]
Definition: ecma119.h:829
time_t now
Definition: ecma119.h:594
mode_t file_mode
Definition: ecma119.h:586
IsoWriteOpts * opts
Definition: ecma119.h:563
uint32_t hfsp_nleafs
Definition: ecma119.h:667
mode_t dir_mode
Definition: ecma119.h:587
uint32_t hfsp_extent_file_start
Definition: ecma119.h:663
uint32_t hfsp_total_blocks
Definition: ecma119.h:665
uint32_t hfsp_bless_id[ISO_HFSPLUS_BLESS_MAX]
Definition: ecma119.h:670
gid_t gid
Definition: ecma119.h:585
uint32_t hfsp_nlevels
Definition: ecma119.h:656
char * input_charset
Definition: ecma119.h:591
struct hfsplus_btree_level * hfsp_levels
Definition: ecma119.h:655
uid_t uid
Definition: ecma119.h:584
unsigned int replace_dir_mode
Definition: ecma119.h:580
uint32_t hfsp_allocation_file_start
Definition: ecma119.h:662
HFSPlusNode * hfsp_leafs
Definition: ecma119.h:654
unsigned int replace_gid
Definition: ecma119.h:578
uint32_t hfsp_catalog_file_start
Definition: ecma119.h:664
int hfsp_cat_node_size
Definition: ecma119.h:839
uint32_t hfsp_allocation_size
Definition: ecma119.h:666
IsoImageWriter ** writers
Definition: ecma119.h:753
int apm_req_count
Definition: ecma119.h:848
uint32_t hfsp_nfiles
Definition: ecma119.h:658
uint32_t hfsp_ndirs
Definition: ecma119.h:659
struct iso_apm_partition_request * apm_req[63]
Definition: ecma119.h:847
uint32_t hfsp_nnodes
Definition: ecma119.h:669
size_t nwriters
Definition: ecma119.h:752
uint32_t curblock
Definition: ecma119.h:618
uint32_t hfsp_cat_id
Definition: ecma119.h:660
int hfsp_iso_block_fac
Definition: ecma119.h:840
unsigned int replace_uid
Definition: ecma119.h:577
unsigned int replace_file_mode
Definition: ecma119.h:579
uint32_t hfsp_allocation_blocks
Definition: ecma119.h:661
off_t bytes_written
Definition: ecma119.h:610
uint16_t nodesize
Definition: hfsplus.h:143
uint32_t root
Definition: hfsplus.h:139
uint32_t attributes
Definition: hfsplus.h:151
uint16_t depth
Definition: hfsplus.h:138
uint32_t leaf_records
Definition: hfsplus.h:140
uint32_t first_leaf_node
Definition: hfsplus.h:141
uint32_t total_nodes
Definition: hfsplus.h:145
uint32_t last_leaf_node
Definition: hfsplus.h:142
uint8_t key_compare
Definition: hfsplus.h:150
uint32_t free_nodes
Definition: hfsplus.h:146
uint16_t keysize
Definition: hfsplus.h:144
uint32_t clump_size
Definition: hfsplus.h:148
uint8_t height
Definition: hfsplus.h:130
uint32_t prev
Definition: hfsplus.h:128
int8_t type
Definition: hfsplus.h:129
uint16_t count
Definition: hfsplus.h:131
uint32_t next
Definition: hfsplus.h:127
struct hfsplus_btree_node * nodes
Definition: hfsplus.h:42
uint32_t level_size
Definition: hfsplus.h:41
uint32_t strlen
Definition: hfsplus.h:34
uint16_t * str
Definition: hfsplus.h:35
uint32_t cnt
Definition: hfsplus.h:33
uint32_t start
Definition: hfsplus.h:32
uint32_t parent_id
Definition: hfsplus.h:36
uint8_t file_creator[4]
Definition: hfsplus.h:181
uint8_t file_type[4]
Definition: hfsplus.h:180
uint32_t count
Definition: hfsplus.h:77
uint32_t start
Definition: hfsplus.h:75
uint32_t blocks
Definition: hfsplus.h:84
struct hfsplus_extent extents[8]
Definition: hfsplus.h:85
uint32_t clumpsize
Definition: hfsplus.h:83
uint64_t size
Definition: hfsplus.h:82
uint32_t nchildren
Definition: hfsplus.h:63
uint32_t parent_id
Definition: hfsplus.h:62
uint16_t * name
Definition: hfsplus.h:50
char * symlink_dest
Definition: hfsplus.h:57
enum hfsplus_node_type type
Definition: hfsplus.h:59
IsoFileSrc * file
Definition: hfsplus.h:60
enum hfsplus_node::@3 unix_type
IsoNode * node
Definition: hfsplus.h:53
uint16_t * cmp_name
Definition: hfsplus.h:51
uint32_t used_size
Definition: hfsplus.h:66
uint32_t strlen
Definition: hfsplus.h:65
uint32_t symlink_block
Definition: hfsplus.h:56
uint32_t cat_id
Definition: hfsplus.h:61
uint32_t total_blocks
Definition: hfsplus.h:102
uint16_t version
Definition: hfsplus.h:91
uint32_t file_count
Definition: hfsplus.h:99
uint32_t rsrc_clumpsize
Definition: hfsplus.h:105
uint32_t data_clumpsize
Definition: hfsplus.h:106
uint64_t num_serial
Definition: hfsplus.h:117
uint32_t attributes
Definition: hfsplus.h:92
struct hfsplus_forkdata catalog_file
Definition: hfsplus.h:120
uint32_t blksize
Definition: hfsplus.h:101
uint32_t ctime
Definition: hfsplus.h:95
uint16_t magic
Definition: hfsplus.h:90
uint32_t catalog_node_id
Definition: hfsplus.h:107
uint32_t last_mounted_version
Definition: hfsplus.h:93
uint32_t fsck_time
Definition: hfsplus.h:98
uint64_t encodings_bitmap
Definition: hfsplus.h:109
uint32_t folder_count
Definition: hfsplus.h:100
uint32_t ppc_bootdir
Definition: hfsplus.h:110
struct hfsplus_forkdata allocations_file
Definition: hfsplus.h:118
struct hfsplus_forkdata extents_file
Definition: hfsplus.h:119
uint32_t utime
Definition: hfsplus.h:96
uint32_t size
Definition: libisofs.h:259
uint32_t block
Definition: libisofs.h:258
uint8_t creator_code[4]
Definition: libisofs.h:8548
uint8_t type_code[4]
Definition: libisofs.h:8549
uint8_t hfsp_serial_number[8]
Definition: ecma119.h:529
int hfsp_block_size
Definition: ecma119.h:533
int iso_quick_apm_entry(struct iso_apm_partition_request **req_array, int *apm_req_count, uint32_t start_block, uint32_t block_count, char *name, char *type)
Definition: system_area.c:1036