"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