1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2007 Mario Danic
4 * Copyright (c) 2009 - 2020 Thomas Schmitt
5 *
6 * This file is part of the libisofs project; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * or later as published by the Free Software Foundation.
9 * See COPYING file for details.
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "../config.h"
14 #endif
15
16 #include <string.h>
17 #include <stdio.h>
18
19 #include "rockridge.h"
20 #include "node.h"
21 #include "ecma119_tree.h"
22 #include "writer.h"
23 #include "messages.h"
24 #include "image.h"
25 #include "aaip_0_2.h"
26 #include "libisofs.h"
27
28
29 #ifdef Libisofs_with_rrip_rR
30 #define ISO_ROCKRIDGE_IN_DIR_REC 128
31 #else
32 #define ISO_ROCKRIDGE_IN_DIR_REC 124
33 #endif
34
35 #define ISO_CE_ENTRY_SIZE 28
36
37
38 static
39 int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno);
40
41 static
42 int susp_make_CE(Ecma119Image *t, uint8_t **CE,
43 uint32_t block_offset, uint32_t byte_offset, uint32_t size);
44
45
46 static
susp_append(Ecma119Image * t,struct susp_info * susp,uint8_t * data)47 int susp_append(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
48 {
49 susp->n_susp_fields++;
50 susp->susp_fields = realloc(susp->susp_fields, sizeof(void*)
51 * susp->n_susp_fields);
52 if (susp->susp_fields == NULL) {
53 return ISO_OUT_OF_MEM;
54 }
55 susp->susp_fields[susp->n_susp_fields - 1] = data;
56 susp->suf_len += data[2];
57 return ISO_SUCCESS;
58 }
59
60 static
susp_append_ce(Ecma119Image * t,struct susp_info * susp,uint8_t * data)61 int susp_append_ce(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
62 {
63 int to_alloc = 1, ret;
64 unsigned char *pad;
65 uint8_t *CE;
66 size_t next_alloc;
67
68 if (data[0] &&
69 (susp->ce_len + data[2] + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE !=
70 susp->ce_len / BLOCK_SIZE) {
71 /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE.
72 So this Continuation Area needs to end by a CE which points
73 to the start of the next block.
74 */
75 to_alloc = 2;
76 if ((susp->ce_len + ISO_CE_ENTRY_SIZE) % BLOCK_SIZE)
77 to_alloc = 3; /* need a PAD pseudo entry */
78 }
79
80 if (susp->ce_susp_fields == NULL)
81 susp->alloc_ce_susp_fields = 0;
82 if (susp->n_ce_susp_fields + to_alloc > susp->alloc_ce_susp_fields) {
83 next_alloc = susp->alloc_ce_susp_fields;
84 while (susp->n_ce_susp_fields + to_alloc > next_alloc)
85 next_alloc += ISO_SUSP_CE_ALLOC_STEP;
86 susp->ce_susp_fields = realloc(susp->ce_susp_fields,
87 sizeof(uint8_t *) * next_alloc);
88 if (susp->ce_susp_fields == NULL)
89 return ISO_OUT_OF_MEM;
90 susp->alloc_ce_susp_fields = next_alloc;
91 }
92
93 if (to_alloc >= 2) {
94 /* Insert CE entry (actual CE size later by susp_update_CE_sizes) */
95 ret = susp_make_CE(t, &CE, (uint32_t) (susp->ce_block +
96 susp->ce_len / BLOCK_SIZE + 1),
97 (uint32_t) 0, (uint32_t) 2048);
98 if (ret < 0)
99 return ret;
100 susp->ce_susp_fields[susp->n_ce_susp_fields] = CE;
101 susp->ce_len += ISO_CE_ENTRY_SIZE;
102 susp->n_ce_susp_fields++;
103 }
104 if (to_alloc >= 3) {
105
106
107 #ifdef Libisofs_ce_calc_debuG
108
109 fprintf(stderr,
110 "\nlibburn_DEBUG: Inserting %d bytes of CE padding\n\n",
111 (int) (BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE)));
112
113 #endif /* Libisofs_ce_calc_debuG */
114
115 pad = malloc(1);
116 if (pad == NULL)
117 return ISO_OUT_OF_MEM;
118 pad[0] = 0;
119 susp->ce_susp_fields[susp->n_ce_susp_fields] = pad;
120 if (susp->ce_len % BLOCK_SIZE)
121 susp->ce_len += BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE);
122 susp->n_ce_susp_fields++;
123 }
124 susp->ce_susp_fields[susp->n_ce_susp_fields] = data;
125 susp->n_ce_susp_fields++;
126
127 if (data[0] == 0) {
128 if (susp->ce_len % BLOCK_SIZE)
129 susp->ce_len += BLOCK_SIZE - (susp->ce_len % BLOCK_SIZE);
130 } else {
131 susp->ce_len += data[2];
132 }
133 return ISO_SUCCESS;
134 }
135
136 static
px_get_uid(Ecma119Image * t,Ecma119Node * n)137 uid_t px_get_uid(Ecma119Image *t, Ecma119Node *n)
138 {
139 if (t->replace_uid) {
140 return t->uid;
141 } else {
142 return n->node->uid;
143 }
144 }
145
146 static
px_get_gid(Ecma119Image * t,Ecma119Node * n)147 uid_t px_get_gid(Ecma119Image *t, Ecma119Node *n)
148 {
149 if (t->replace_gid) {
150 return t->gid;
151 } else {
152 return n->node->gid;
153 }
154 }
155
156 static
px_get_mode(Ecma119Image * t,Ecma119Node * n)157 mode_t px_get_mode(Ecma119Image *t, Ecma119Node *n)
158 {
159 if ((n->type == ECMA119_DIR || n->type == ECMA119_PLACEHOLDER)) {
160 if (t->replace_dir_mode) {
161 return (n->node->mode & S_IFMT) | t->dir_mode;
162 }
163 } else {
164 if (t->replace_file_mode) {
165 return (n->node->mode & S_IFMT) | t->file_mode;
166 }
167 }
168 return n->node->mode;
169 }
170
171 /**
172 * Add a PX System Use Entry. The PX System Use Entry is used to add POSIX
173 * file attributes, such as access permissions or user and group id, to a
174 * ECMA 119 directory record. (RRIP, 4.1.1)
175 */
176 static
rrip_add_PX(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)177 int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
178 {
179 uint8_t *PX = malloc(44);
180 if (PX == NULL) {
181 return ISO_OUT_OF_MEM;
182 }
183
184 PX[0] = 'P';
185 PX[1] = 'X';
186 if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10 ) {
187 PX[2] = 44;
188 } else {
189 PX[2] = 36;
190 }
191 PX[3] = 1;
192 iso_bb(&PX[4], (uint32_t) px_get_mode(t, n), 4);
193 iso_bb(&PX[12], (uint32_t) n->nlink, 4);
194 iso_bb(&PX[20], (uint32_t) px_get_uid(t, n), 4);
195 iso_bb(&PX[28], (uint32_t) px_get_gid(t, n), 4);
196 if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10) {
197 iso_bb(&PX[36], (uint32_t) n->ino, 4);
198 }
199
200 return susp_append(t, susp, PX);
201 }
202
203 /**
204 * Add to the given tree node a TF System Use Entry, used to record some
205 * time stamps related to the file (RRIP, 4.1.6).
206 */
207 static
rrip_add_TF(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)208 int rrip_add_TF(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
209 {
210 IsoNode *iso;
211 uint8_t *TF = malloc(5 + 3 * 7);
212 if (TF == NULL) {
213 return ISO_OUT_OF_MEM;
214 }
215
216 TF[0] = 'T';
217 TF[1] = 'F';
218 TF[2] = 5 + 3 * 7;
219 TF[3] = 1;
220 TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
221
222 iso = n->node;
223 iso_datetime_7(&TF[5], t->replace_timestamps ? t->timestamp : iso->mtime,
224 t->opts->always_gmt);
225 iso_datetime_7(&TF[12], t->replace_timestamps ? t->timestamp : iso->atime,
226 t->opts->always_gmt);
227 iso_datetime_7(&TF[19], t->replace_timestamps ? t->timestamp : iso->ctime,
228 t->opts->always_gmt);
229 return susp_append(t, susp, TF);
230 }
231
232 /**
233 * Add a PL System Use Entry, used to record the location of the original
234 * parent directory of a directory which has been relocated.
235 *
236 * This is special because it doesn't modify the susp fields of the directory
237 * that gets passed to it; it modifies the susp fields of the ".." entry in
238 * that directory.
239 *
240 * See RRIP, 4.1.5.2 for more details.
241 */
242 static
rrip_add_PL(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)243 int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
244 {
245 uint8_t *PL;
246
247 if (n->type != ECMA119_DIR || n->info.dir->real_parent == NULL) {
248 /* should never occur */
249 return ISO_ASSERT_FAILURE;
250 }
251
252 PL = malloc(12);
253 if (PL == NULL) {
254 return ISO_OUT_OF_MEM;
255 }
256
257 PL[0] = 'P';
258 PL[1] = 'L';
259 PL[2] = 12;
260 PL[3] = 1;
261
262 /* write the location of the real parent, already computed */
263 iso_bb(&PL[4],
264 n->info.dir->real_parent->info.dir->block - t->eff_partition_offset, 4);
265 return susp_append(t, susp, PL);
266 }
267
268 /**
269 * Add a RE System Use Entry to the given tree node. The purpose of the
270 * this System Use Entry is to indicate to an RRIP-compliant receiving
271 * system that the Directory Record in which an "RE" System Use Entry is
272 * recorded has been relocated from another position in the original
273 * Directory Hierarchy.
274 *
275 * See RRIP, 4.1.5.3 for more details.
276 */
277 static
rrip_add_RE(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)278 int rrip_add_RE(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
279 {
280 uint8_t *RE = malloc(4);
281 if (RE == NULL) {
282 return ISO_OUT_OF_MEM;
283 }
284
285 RE[0] = 'R';
286 RE[1] = 'E';
287 RE[2] = 4;
288 RE[3] = 1;
289 return susp_append(t, susp, RE);
290 }
291
292 /**
293 * Add a PN System Use Entry to the given tree node.
294 * The PN System Use Entry is used to store the device number, and it's
295 * mandatory if the tree node corresponds to a character or block device.
296 *
297 * See RRIP, 4.1.2 for more details.
298 */
299 static
rrip_add_PN(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)300 int rrip_add_PN(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
301 {
302 IsoSpecial *node;
303 uint8_t *PN;
304 int high_shift= 0;
305
306 node = (IsoSpecial*)n->node;
307 if (node->node.type != LIBISO_SPECIAL) {
308 /* should never occur */
309 return ISO_ASSERT_FAILURE;
310 }
311
312 PN = malloc(20);
313 if (PN == NULL) {
314 return ISO_OUT_OF_MEM;
315 }
316
317 PN[0] = 'P';
318 PN[1] = 'N';
319 PN[2] = 20;
320 PN[3] = 1;
321
322 /* (dev_t >> 32) causes compiler warnings on FreeBSD.
323 RRIP 1.10 4.1.2 prescribes PN "Dev_t High" to be 0 on 32 bit dev_t.
324 */
325 if (sizeof(node->dev) > 4) {
326 high_shift = 32;
327 iso_bb(&PN[4], (uint32_t) (node->dev >> high_shift), 4);
328 } else
329 iso_bb(&PN[4], 0, 4);
330 iso_bb(&PN[12], (uint32_t) (node->dev & 0xffffffff), 4);
331 return susp_append(t, susp, PN);
332 }
333
334 /**
335 * Add to the given tree node a CL System Use Entry, that is used to record
336 * the new location of a directory which has been relocated.
337 *
338 * See RRIP, 4.1.5.1 for more details.
339 */
340 static
rrip_add_CL(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)341 int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
342 {
343 uint8_t *CL;
344 if (n->type != ECMA119_PLACEHOLDER) {
345 /* should never occur */
346 return ISO_ASSERT_FAILURE;
347 }
348 CL = malloc(12);
349 if (CL == NULL) {
350 return ISO_OUT_OF_MEM;
351 }
352
353 CL[0] = 'C';
354 CL[1] = 'L';
355 CL[2] = 12;
356 CL[3] = 1;
357 iso_bb(&CL[4], n->info.real_me->info.dir->block - t->eff_partition_offset,
358 4);
359 return susp_append(t, susp, CL);
360 }
361
362 /**
363 * Convert a RR filename to the requested charset. On any conversion error,
364 * the original name will be used.
365 * @param flag bit0= do not issue error messages
366 */
iso_get_rr_name(IsoWriteOpts * opts,char * input_charset,char * output_charset,int imgid,char * str,char ** name,int flag)367 int iso_get_rr_name(IsoWriteOpts *opts, char *input_charset,
368 char *output_charset, int imgid,
369 char *str, char **name, int flag)
370 {
371 int ret;
372
373 if (!strcmp(input_charset, output_charset)) {
374 /* no conversion needed */
375 ret = iso_clone_mem(str, name, 0);
376 return ret;
377 }
378
379 ret = strconv(str, input_charset, output_charset, name);
380 if (ret < 0) {
381 /* TODO we should check for possible cancellation */
382 if (!(flag & 1))
383 iso_msg_submit(imgid, ISO_FILENAME_WRONG_CHARSET, ret,
384 "Charset conversion error. Cannot convert %s from %s to %s",
385 str, input_charset, output_charset);
386 *name = NULL;
387 return ISO_FILENAME_WRONG_CHARSET;
388 }
389
390 return ISO_SUCCESS;
391 }
392
393 static
get_rr_fname(Ecma119Image * t,char * str)394 char *get_rr_fname(Ecma119Image *t, char *str)
395 {
396 int ret;
397 char *name = NULL;
398
399 ret = iso_get_rr_name(t->opts, t->input_charset, t->output_charset,
400 t->image->id, str, &name, 0);
401 if (ret < 0)
402 return NULL;
403 return name;
404 }
405
406 /**
407 * Add a NM System Use Entry to the given tree node. The purpose of this
408 * System Use Entry is to store the content of an Alternate Name to support
409 * POSIX-style or other names.
410 *
411 * See RRIP, 4.1.4 for more details.
412 *
413 * @param size
414 * Length of the name to be included into the NM
415 * @param flags
416 * @param ce
417 * Whether to add or not to CE
418 */
419 static
rrip_add_NM(Ecma119Image * t,struct susp_info * susp,char * name,int size,int flags,int ce)420 int rrip_add_NM(Ecma119Image *t, struct susp_info *susp, char *name, int size,
421 int flags, int ce)
422 {
423 uint8_t *NM;
424
425 if (size > 250)
426 return ISO_ASSERT_FAILURE;
427
428 NM = malloc(size + 5);
429 if (NM == NULL) {
430 return ISO_OUT_OF_MEM;
431 }
432
433 NM[0] = 'N';
434 NM[1] = 'M';
435 NM[2] = size + 5;
436 NM[3] = 1;
437 NM[4] = flags;
438 if (size) {
439 memcpy(&NM[5], name, size);
440 }
441 if (ce) {
442 return susp_append_ce(t, susp, NM);
443 } else {
444 return susp_append(t, susp, NM);
445 }
446 }
447
448 /**
449 * Add a new SL component (RRIP, 4.1.3.1) to a list of components.
450 *
451 * @param n
452 * Number of components. It will be updated.
453 * @param compos
454 * Pointer to the list of components.
455 * @param s
456 * The component content
457 * @param size
458 * Size of the component content
459 * @param fl
460 * Flags
461 * @return
462 * 1 on success, < 0 on error
463 */
464 static
rrip_SL_append_comp(size_t * n,uint8_t *** comps,char * s,int size,char fl)465 int rrip_SL_append_comp(size_t *n, uint8_t ***comps, char *s, int size, char fl)
466 {
467 uint8_t *comp = malloc(size + 2);
468 if (comp == NULL) {
469 return ISO_OUT_OF_MEM;
470 }
471
472 (*n)++;
473 comp[0] = fl;
474 comp[1] = size;
475 *comps = realloc(*comps, (*n) * sizeof(void*));
476 if (*comps == NULL) {
477 free(comp);
478 return ISO_OUT_OF_MEM;
479 }
480 (*comps)[(*n) - 1] = comp;
481
482 if (size) {
483 memcpy(&comp[2], s, size);
484 }
485 return ISO_SUCCESS;
486 }
487
488
489 #ifdef Libisofs_with_rrip_rR
490
491 /**
492 * Add a RR System Use Entry to the given tree node. This is an obsolete
493 * entry from before RRIP-1.10. Nevertheless mkisofs produces it. There
494 * is the suspicion that some operating systems could take it as indication
495 * for Rock Ridge.
496 *
497 * The meaning of the payload byte is documented e.g. in
498 * /usr/src/linux/fs/isofs/rock.h
499 * It announces the presence of entries PX, PN, SL, NM, CL, PL, RE, TF
500 * by payload byte bits 0 to 7.
501 */
502 static
rrip_add_RR(Ecma119Image * t,Ecma119Node * n,struct susp_info * susp)503 int rrip_add_RR(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
504 {
505 uint8_t *RR;
506 RR = malloc(5);
507 if (RR == NULL) {
508 return ISO_OUT_OF_MEM;
509 }
510
511 RR[0] = 'R';
512 RR[1] = 'R';
513 RR[2] = 5;
514 RR[3] = 1;
515
516 /* <<< ts B20307 : Not all directories have NM, many files have more entries */
517 RR[4] = 0x89; /* TF, NM , PX */
518
519 /* >>> ts B20307 : find out whether n carries
520 PX, PN, SL, NM, CL, PL, RE, TF and mark by bit0 to bit7 in RR[4]
521 */
522
523 return susp_append(t, susp, RR);
524 }
525
526 #endif /* Libisofs_with_rrip_rR */
527
528
529 /**
530 * Add a SL System Use Entry to the given tree node. This is used to store
531 * the content of a symbolic link, and is mandatory if the tree node
532 * indicates a symbolic link (RRIP, 4.1.3).
533 *
534 * @param comp
535 * Components of the SL System Use Entry. If they don't fit in a single
536 * SL, more than one SL will be added.
537 * @param n
538 * Number of components in comp
539 * @param ce
540 * Whether to add to a continuation area or system use field.
541 */
542 static
rrip_add_SL(Ecma119Image * t,struct susp_info * susp,uint8_t ** comp,size_t n,int ce)543 int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, uint8_t **comp,
544 size_t n, int ce)
545 {
546 int ret;
547 size_t i, j;
548 int total_comp_len = 0;
549 size_t pos, written = 0;
550
551 uint8_t *SL;
552
553 for (i = 0; i < n; i++) {
554
555 total_comp_len += comp[i][1] + 2;
556 if (total_comp_len > 250) {
557 /* we need a new SL entry */
558 total_comp_len -= comp[i][1] + 2;
559 SL = malloc(total_comp_len + 5);
560 if (SL == NULL) {
561 return ISO_OUT_OF_MEM;
562 }
563
564 SL[0] = 'S';
565 SL[1] = 'L';
566 SL[2] = total_comp_len + 5;
567 SL[3] = 1;
568 SL[4] = 1; /* CONTINUE */
569 pos = 5;
570 for (j = written; j < i; j++) {
571 memcpy(&SL[pos], comp[j], comp[j][1] + 2);
572 pos += comp[j][1] + 2;
573 }
574
575 /*
576 * In this case we are sure we're writing to CE. Check for
577 * debug purposes
578 */
579 if (ce == 0) {
580 free(SL);
581 return ISO_ASSERT_FAILURE;
582 }
583 ret = susp_append_ce(t, susp, SL);
584 if (ret < 0) {
585 free(SL);
586 return ret;
587 }
588 SL = NULL; /* now owned by susp */
589 written = i;
590 total_comp_len = comp[i][1] + 2;
591 }
592 }
593
594 SL = malloc(total_comp_len + 5);
595 if (SL == NULL) {
596 return ISO_OUT_OF_MEM;
597 }
598
599 SL[0] = 'S';
600 SL[1] = 'L';
601 SL[2] = total_comp_len + 5;
602 SL[3] = 1;
603 SL[4] = 0;
604 pos = 5;
605
606 for (j = written; j < n; j++) {
607 memcpy(&SL[pos], comp[j], comp[j][1] + 2);
608 pos += comp[j][1] + 2;
609 }
610 if (ce) {
611 ret = susp_append_ce(t, susp, SL);
612 } else {
613 ret = susp_append(t, susp, SL);
614 }
615 return ret;
616 }
617
618
619 /* @param flag bit1= care about crossing block boundaries */
620 static
susp_calc_add_to_ce(size_t * ce,size_t base_ce,int add,int flag)621 int susp_calc_add_to_ce(size_t *ce, size_t base_ce, int add, int flag)
622 {
623 if (flag & 2) {
624 /* Account for inserted CE before size exceeds block size */
625 if ((*ce + base_ce + add + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE !=
626 (*ce + base_ce) / BLOCK_SIZE) {
627 /* Insert CE and padding */
628 *ce += ISO_CE_ENTRY_SIZE;
629 if ((*ce + base_ce) % BLOCK_SIZE)
630 *ce += BLOCK_SIZE - ((*ce + base_ce) % BLOCK_SIZE);
631 }
632 }
633 *ce += add;
634 return ISO_SUCCESS;
635 }
636
637
638 /*
639 @param flag bit0= only account sizes in sua_free resp. ce_len.
640 Parameter susp may be NULL in this case
641 bit1= account for crossing block boundaries
642 (implied by bit0 == 0)
643 @param ce_len counts the freshly added CA size of the current node
644 @param ce_mem tells the CA size of previous nodes in the same directory
645 */
646 static
aaip_add_AL(Ecma119Image * t,struct susp_info * susp,uint8_t ** data,size_t num_data,size_t * sua_free,size_t * ce_len,size_t ce_mem,int flag)647 int aaip_add_AL(Ecma119Image *t, struct susp_info *susp,
648 uint8_t **data, size_t num_data,
649 size_t *sua_free, size_t *ce_len, size_t ce_mem, int flag)
650 {
651 int ret, done = 0, len, es_extra = 0;
652 uint8_t *aapt, *cpt;
653 size_t count = 0;
654
655 if (!(flag & 1))
656 flag |= 2;
657 if (!t->opts->aaip_susp_1_10)
658 es_extra = 5;
659 if (*sua_free < num_data + es_extra || *ce_len > 0) {
660 if (es_extra > 0)
661 susp_calc_add_to_ce(ce_len, ce_mem, es_extra, flag & 2);
662 done = 0;
663 for (aapt = *data; !done; aapt += aapt[2]) {
664 done = !(aapt[4] & 1);
665 len = aapt[2];
666 susp_calc_add_to_ce(ce_len, ce_mem, len, flag & 2);
667 count += len;
668 }
669 } else {
670 *sua_free -= num_data + es_extra;
671 }
672 if (flag & 1)
673 return ISO_SUCCESS;
674
675 /* If AAIP enabled and announced by ER : Write ES field to announce AAIP */
676 if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
677 ret = susp_add_ES(t, susp, (*ce_len > 0), 1);
678 if (ret < 0)
679 return ret;
680 }
681 aapt = *data;
682 if (!(aapt[4] & 1)) {
683 /* Single field can be handed over directly */
684 if (*ce_len > 0) {
685 ret = susp_append_ce(t, susp, aapt);
686 } else {
687 ret = susp_append(t, susp, aapt);
688 }
689 *data = NULL;
690 return ISO_SUCCESS;
691 }
692
693 /* Multiple fields have to be handed over as single field copies */
694 done = 0;
695 for (aapt = *data; !done; aapt += aapt[2]) {
696 done = !(aapt[4] & 1);
697 len = aapt[2];
698 cpt = calloc(aapt[2], 1);
699 if (cpt == NULL)
700 return ISO_OUT_OF_MEM;
701 memcpy(cpt, aapt, len);
702 if (*ce_len > 0) {
703 ret = susp_append_ce(t, susp, cpt);
704 } else {
705 ret = susp_append(t, susp, cpt);
706 }
707 if (ret == -1)
708 return ret;
709 }
710 free(*data);
711 *data = NULL;
712 return ISO_SUCCESS;
713 }
714
715
716 /**
717 * Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
718 *
719 * The "ER" System Use Entry is used to uniquely identify a specification
720 * compliant with SUSP. This method adds to the given tree node "." entry
721 * the "ER" corresponding to the RR protocol.
722 *
723 * See SUSP, 5.5 and RRIP, 4.3 for more details.
724 */
725 static
rrip_add_ER(Ecma119Image * t,struct susp_info * susp)726 int rrip_add_ER(Ecma119Image *t, struct susp_info *susp)
727 {
728 unsigned char *ER;
729
730 if (!t->opts->rrip_version_1_10) {
731 /*
732 According to RRIP 1.12 this is the future form:
733 4.3 "Specification of the ER System Use Entry Values for RRIP"
734 talks of "IEEE_P1282" in each of the three strings and finally states
735 "Note: Upon adoption as an IEEE standard, these lengths will each
736 decrease by 1."
737 So "IEEE_P1282" would be the new form, "RRIP_1991A" is the old form.
738 */
739
740 ER = malloc(182);
741 if (ER == NULL) {
742 return ISO_OUT_OF_MEM;
743 }
744
745 ER[0] = 'E';
746 ER[1] = 'R';
747 ER[2] = 182;
748 ER[3] = 1;
749 ER[4] = 9;
750 ER[5] = 72;
751 ER[6] = 93;
752 ER[7] = 1;
753 memcpy(&ER[8], "IEEE_1282", 9);
754 memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
755 "FILE SYSTEM SEMANTICS.", 72);
756 memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
757 "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
758 } else {
759 /*
760 RRIP 1.09 and 1.10:
761 4.3 Specification of the ER System Use Field Values for RRIP
762 The Extension Version number for the version of the RRIP defined herein
763 shall be 1. The content of the Extension Identifier field shall be
764 "RRIP_1991A". The Identifier Length shall be 10. The recommended
765 content of the Extension Descriptor shall be "THE ROCK RIDGE
766 INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
767 The corresponding Description Length is 84.
768 The recommended content of the Extension Source shall be "PLEASE
769 CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER
770 IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION."
771 The corresponding Source Length is 135.
772 */
773
774 ER = malloc(237);
775 if (ER == NULL) {
776 return ISO_OUT_OF_MEM;
777 }
778
779 ER[0] = 'E';
780 ER[1] = 'R';
781 ER[2] = 237;
782 ER[3] = 1;
783 ER[4] = 10;
784 ER[5] = 84;
785 ER[6] = 135;
786 ER[7] = 1;
787
788 memcpy(&ER[8], "RRIP_1991A", 10);
789 memcpy(&ER[18], "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", 84);
790 memcpy(&ER[102], "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", 135);
791 }
792
793 /** This always goes to continuation area */
794 return susp_append_ce(t, susp, ER);
795 }
796
797
798 static
aaip_add_ER(Ecma119Image * t,struct susp_info * susp,int flag)799 int aaip_add_ER(Ecma119Image *t, struct susp_info *susp, int flag)
800 {
801 unsigned char *ER;
802
803 ER = malloc(160);
804 if (ER == NULL) {
805 return ISO_OUT_OF_MEM;
806 }
807
808 ER[0] = 'E';
809 ER[1] = 'R';
810 ER[2] = 160;
811 ER[3] = 1;
812 ER[4] = 9;
813 ER[5] = 81;
814 ER[6] = 62;
815 ER[7] = 1;
816 memcpy(ER + 8, "AAIP_0200", 9);
817 memcpy(ER + 17,
818 "AL PROVIDES VIA AAIP 2.0 SUPPORT FOR ARBITRARY FILE ATTRIBUTES"
819 " IN ISO 9660 IMAGES", 81);
820 memcpy(ER + 98,
821 "PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG",
822 62);
823
824 /** This always goes to continuation area */
825 return susp_append_ce(t, susp, ER);
826 }
827
828
829 /**
830 * Create the byte representation of a CE entry.
831 * (SUSP, 5.1).
832 */
833 static
susp_make_CE(Ecma119Image * t,uint8_t ** CE,uint32_t block_offset,uint32_t byte_offset,uint32_t size)834 int susp_make_CE(Ecma119Image *t, uint8_t **CE,
835 uint32_t block_offset, uint32_t byte_offset, uint32_t size)
836 {
837 uint8_t *data;
838
839 *CE = NULL;
840 data = calloc(1, 28);
841 if (data == NULL)
842 return ISO_OUT_OF_MEM;
843 *CE = data;
844
845 data[0] = 'C';
846 data[1] = 'E';
847 data[2] = 28;
848 data[3] = 1;
849
850 iso_bb(&data[4], block_offset - t->eff_partition_offset, 4);
851 iso_bb(&data[12], byte_offset, 4);
852 iso_bb(&data[20], size, 4);
853
854 return ISO_SUCCESS;
855 }
856
857
858 /**
859 * Add a CE System Use Entry to the given tree node. A "CE" is used to add
860 * a continuation area, where additional System Use Entry can be written.
861 * (SUSP, 5.1).
862 */
863 static
susp_add_CE(Ecma119Image * t,size_t ce_len,struct susp_info * susp)864 int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp)
865 {
866 uint32_t block_offset, byte_offset;
867 uint8_t *CE;
868 int ret;
869
870 /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE
871 * Here the byte_offset is reduced to the minimum.
872 */
873 block_offset = susp->ce_block + susp->ce_len / BLOCK_SIZE;
874 byte_offset = susp->ce_len % BLOCK_SIZE;
875 ret = susp_make_CE(t, &CE, block_offset, byte_offset, (uint32_t) ce_len);
876 if (ret < 0)
877 return ret;
878 return susp_append(t, susp, CE);
879 }
880
881 /**
882 * Add a SP System Use Entry. The SP provide an identifier that the SUSP is
883 * used within the volume. The SP shall be recorded in the "." entry of the
884 * root directory. See SUSP, 5.3 for more details.
885 */
886 static
susp_add_SP(Ecma119Image * t,struct susp_info * susp)887 int susp_add_SP(Ecma119Image *t, struct susp_info *susp)
888 {
889 unsigned char *SP = malloc(7);
890 if (SP == NULL) {
891 return ISO_OUT_OF_MEM;
892 }
893
894 SP[0] = 'S';
895 SP[1] = 'P';
896 SP[2] = (char)7;
897 SP[3] = (char)1;
898 SP[4] = 0xbe;
899 SP[5] = 0xef;
900 SP[6] = 0;
901 return susp_append(t, susp, SP);
902 }
903
904
905 /**
906 * SUSP 1.12: [...] shall specify as an 8-bit number the Extension
907 * Sequence Number of the extension specification utilized in the entries
908 * immediately following this System Use Entry. The Extension Sequence
909 * Numbers of multiple extension specifications on a volume shall correspond to
910 * the order in which their "ER" System Use Entries are recorded [...]
911 */
912 static
susp_add_ES(Ecma119Image * t,struct susp_info * susp,int to_ce,int seqno)913 int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno)
914 {
915 unsigned char *ES = malloc(5);
916
917 if (ES == NULL) {
918 return ISO_OUT_OF_MEM;
919 }
920 ES[0] = 'E';
921 ES[1] = 'S';
922 ES[2] = (unsigned char) 5;
923 ES[3] = (unsigned char) 1;
924 ES[4] = (unsigned char) seqno;
925 if (to_ce) {
926 return susp_append_ce(t, susp, ES);
927 } else {
928 return susp_append(t, susp, ES);
929 }
930 }
931
932
933 /**
934 * A field beginning by 0 causes rrip_write_ce_fields() to pad up to the
935 * next block.
936 */
937 static
pseudo_susp_add_PAD(Ecma119Image * t,struct susp_info * susp)938 int pseudo_susp_add_PAD(Ecma119Image *t, struct susp_info *susp)
939 {
940 unsigned char *pad;
941 int ret;
942
943 pad = malloc(1);
944 if (pad == NULL)
945 return ISO_OUT_OF_MEM;
946 pad[0] = 0;
947 ret = susp_append_ce(t, susp, pad);
948 if (ret < 0)
949 return ret;
950 return ISO_SUCCESS;
951 }
952
953
954 /**
955 * see doc/zisofs_format.txt : "ZF System Use Entry Format"
956 * see doc/zisofs2_format.txt : "ZF System Use Entry Format", "Z2 ..."
957 */
958 static
zisofs_add_ZF(Ecma119Image * t,struct susp_info * susp,int to_ce,uint8_t algo[2],int header_size_div4,int block_size_log2,uint64_t uncompressed_size,int flag)959 int zisofs_add_ZF(Ecma119Image *t, struct susp_info *susp, int to_ce,
960 uint8_t algo[2], int header_size_div4, int block_size_log2,
961 uint64_t uncompressed_size, int flag)
962 {
963 unsigned char *ZF = malloc(16);
964
965 /* Intimate friendship with this variable in filters/zisofs.c */
966 extern int iso_zisofs2_enable_susp_z2;
967
968 if (ZF == NULL) {
969 return ISO_OUT_OF_MEM;
970 }
971 ZF[0] = 'Z';
972 ZF[1] = 'F';
973 ZF[2] = (unsigned char) 16;
974 if (algo[0] == 'p' && algo[1] == 'z') {
975 ZF[3] = (unsigned char) 1;
976 } else {
977 ZF[3] = (unsigned char) 2;
978 if (iso_zisofs2_enable_susp_z2)
979 ZF[1] = '2';
980 }
981 ZF[4] = (unsigned char) algo[0];
982 ZF[5] = (unsigned char) algo[1];
983 ZF[6] = (unsigned char) header_size_div4;
984 ZF[7] = (unsigned char) block_size_log2;
985 if (algo[0] == 'p' && algo[1] == 'z') {
986 if (uncompressed_size > (uint64_t) 0xffffffff)
987 return ISO_ZISOFS_TOO_LARGE;
988 iso_bb(&ZF[8], (uint32_t) uncompressed_size, 4);
989 } else {
990 iso_lsb64(&ZF[8], uncompressed_size);
991 }
992 if (to_ce) {
993 return susp_append_ce(t, susp, ZF);
994 } else {
995 return susp_append(t, susp, ZF);
996 }
997 }
998
999
1000 /* @param flag bit0= Do not add data but only count sua_free and ce_len
1001 bit1= account for crossing block boundaries
1002 (implied by bit0 == 0)
1003 */
1004 static
add_zf_field(Ecma119Image * t,Ecma119Node * n,struct susp_info * info,size_t * sua_free,size_t * ce_len,size_t base_ce,int flag)1005 int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
1006 size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
1007 {
1008 int ret, will_copy = 1, stream_type = 0, do_zf = 0;
1009 int header_size_div4 = 0, block_size_log2 = 0;
1010 uint64_t uncompressed_size = 0;
1011 IsoStream *stream = NULL, *input_stream, *last_stream, *first_stream;
1012 IsoStream *first_filter = NULL;
1013 IsoFile *file;
1014 void *xipt;
1015 struct zisofs_zf_info *zf;
1016 uint8_t algo[2];
1017
1018 /* Intimate friendship with this function in filters/zisofs.c */
1019 int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
1020 uint8_t zisofs_algo[2],
1021 int *header_size_div4, int *block_size_log2,
1022 uint64_t *uncompressed_size, int flag);
1023
1024 if (!(flag & 1))
1025 flag |= 2;
1026
1027 if (iso_node_get_type(n->node) != LIBISO_FILE)
1028 return 2;
1029 file = (IsoFile *) n->node;
1030
1031 /* Inspect: last_stream < ... < first_filter < first_stream */
1032 /* The content is in zisofs format if:
1033 It gets copied and
1034 the last stream is a ziso stream,
1035 or it had a ZF entry and is unfiltered
1036 or it has a zf xinfo record (because its last stream delivered a
1037 zisofs file header when inquired)
1038 or it stays uncopied and
1039 the first filter is an osiz stream,
1040 or it had a ZF entry
1041 or it has a zf xinfo record (because its first stream delivered a
1042 zisofs file header when inquired)
1043 */
1044
1045 if (t->opts->appendable && file->from_old_session)
1046 will_copy = 0;
1047
1048 first_filter = first_stream = last_stream = iso_file_get_stream(file);
1049 while (1) {
1050 input_stream = iso_stream_get_input_stream(first_stream, 0);
1051 if (input_stream == NULL)
1052 break;
1053 first_filter = first_stream;
1054 first_stream = input_stream;
1055 }
1056 if (will_copy) {
1057 stream = last_stream;
1058 } else {
1059 /* (the eventual osiz filter on the image stream) */
1060 stream = first_filter;
1061 }
1062
1063 /* Determine stream type : 1=ziso , -1=osiz , 0=other */
1064 algo[0] = algo[1] = 0;
1065 ret = ziso_is_zisofs_stream(stream, &stream_type, algo, &header_size_div4,
1066 &block_size_log2, &uncompressed_size, 0);
1067 if (ret < 0)
1068 return ret;
1069
1070 if (stream_type == 1 && will_copy) {
1071 do_zf = 1;
1072 } else if (stream_type == -1 && !will_copy) {
1073 do_zf = 1;
1074 } else if(first_stream == last_stream || !will_copy) {
1075 /* Try whether the image side stream remembers a ZF field */
1076 ret = iso_stream_get_src_zf(first_stream, algo, &header_size_div4,
1077 &block_size_log2, &uncompressed_size, 0);
1078 if (ret == 1 && header_size_div4 > 0)
1079 do_zf = 1;
1080 }
1081 if (!do_zf) {
1082 /* Look for an xinfo mark of a zisofs header */
1083 ret = iso_node_get_xinfo((IsoNode *) file, zisofs_zf_xinfo_func,
1084 &xipt);
1085 if (ret == 1) {
1086 zf = xipt;
1087 header_size_div4 = zf->header_size_div4;
1088 block_size_log2 = zf->block_size_log2;
1089 uncompressed_size = zf->uncompressed_size;
1090 algo[0] = zf->zisofs_algo[0];
1091 algo[1] = zf->zisofs_algo[1];
1092 if (header_size_div4 > 0)
1093 do_zf = 1;
1094 }
1095 }
1096
1097 if (!do_zf)
1098 return 2;
1099
1100 /* Account for field size */
1101 if (*sua_free < 16 || *ce_len > 0) {
1102 susp_calc_add_to_ce(ce_len, base_ce, 16, flag & 2);
1103 } else {
1104 *sua_free -= 16;
1105 }
1106 if (flag & 1)
1107 return 1;
1108
1109 /* write ZF field */
1110 ret = zisofs_add_ZF(t, info, (*ce_len > 0), algo, header_size_div4,
1111 block_size_log2, uncompressed_size, 0);
1112 if (ret < 0)
1113 return ret;
1114 return 1;
1115 }
1116
1117 /* API */
aaip_xinfo_func(void * data,int flag)1118 int aaip_xinfo_func(void *data, int flag)
1119 {
1120 if (flag & 1) {
1121 free(data);
1122 }
1123 return 1;
1124 }
1125
1126 /* API */
aaip_xinfo_cloner(void * old_data,void ** new_data,int flag)1127 int aaip_xinfo_cloner(void *old_data, void **new_data, int flag)
1128 {
1129 size_t aa_size;
1130
1131 *new_data = NULL;
1132 if (old_data == NULL)
1133 return 0;
1134 aa_size = aaip_count_bytes((unsigned char *) old_data, 0);
1135 if (aa_size <= 0)
1136 return ISO_AAIP_BAD_AASTRING;
1137 *new_data = calloc(1, aa_size);
1138 if (*new_data == NULL)
1139 return ISO_OUT_OF_MEM;
1140 memcpy(*new_data, old_data, aa_size);
1141 return (int) aa_size;
1142 }
1143
1144 /**
1145 * Compute SUA length and eventual Continuation Area length of field NM and
1146 * eventually fields SL and AL. Because CA usage makes necessary the use of
1147 * a CE entry of 28 bytes in SUA, this computation fails if not the 28 bytes
1148 * are taken into account at start. In this case the caller should retry with
1149 * bit0 set.
1150 * If the resulting *ce added to base_ce is in a different block than base_ce,
1151 * then computation with bit0 fails and the caller should finally try bit1.
1152 *
1153 * @param flag bit0= assume CA usage (else return 0 on SUA overflow)
1154 * bit1= let CA start at block start (else return 0 if
1155 * *ce crosses a block boundary)
1156 * @return 1= ok, computation of *su_size and *ce is valid
1157 * 0= not ok, CA usage is necessary but bit0 was not set
1158 * or *ce crosses boundary and bit1 was not set
1159 * (*su_size and *ce stay unaltered in this case)
1160 * <0= error:
1161 * -1= not enough SUA space for 28 bytes of CE entry
1162 * -2= out of memory
1163 */
1164 static
susp_calc_nm_sl_al(Ecma119Image * t,Ecma119Node * n,size_t space,size_t * su_size,size_t * ce,size_t base_ce,int flag)1165 int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space,
1166 size_t *su_size, size_t *ce, size_t base_ce, int flag)
1167 {
1168 char *name;
1169 size_t namelen, su_mem, ce_mem, ce_prepad = 0;
1170 void *xipt;
1171 size_t num_aapt = 0, sua_free = 0;
1172 int ret;
1173 uint8_t *aapt;
1174
1175 #ifdef Libisofs_ce_calc_debug_extrA
1176
1177 if (n->node->name != NULL)
1178 fprintf(stderr, "libburn_DEBUG: susp_calc_nm_sl_al : %.f %s \n",
1179 (double) base_ce, n->node->name);
1180
1181 #endif /* Libisofs_ce_calc_debug_extrA */
1182
1183 su_mem = *su_size;
1184 ce_mem = *ce;
1185 if (*ce > 0 && !(flag & 1))
1186 goto unannounced_ca;
1187
1188 if (flag & 2) {
1189 flag |= 1;
1190 if (base_ce % BLOCK_SIZE) {
1191
1192 #ifdef Libisofs_ce_calc_debuG
1193
1194 fprintf(stderr,
1195 "\nlibburn_DEBUG: Accounting for %d bytes CE padding : %s\n\n",
1196 (int) (BLOCK_SIZE - (base_ce % BLOCK_SIZE)), n->node->name);
1197
1198 #endif /* Libisofs_ce_calc_debuG */
1199
1200 ce_prepad = BLOCK_SIZE - (base_ce % BLOCK_SIZE);
1201 }
1202 }
1203
1204 namelen = 0;
1205 name = get_rr_fname(t, n->node->name);
1206 if (name != NULL) {
1207 namelen = strlen(name);
1208 free(name);
1209 }
1210
1211 if (flag & 1) {
1212 /* Account for 28 bytes of CE field */
1213 if (*su_size + 28 > space) {
1214 *ce += ce_prepad;
1215 return -1;
1216 }
1217 *su_size += 28;
1218 }
1219
1220 /* NM entry */
1221 if (*su_size + 5 + namelen <= space) {
1222 /* ok, it fits in System Use Area */
1223 *su_size += 5 + namelen;
1224 } else {
1225 /* the NM will be divided in a CA */
1226 if (!(flag & 1))
1227 goto unannounced_ca;
1228 namelen = namelen - (space - *su_size - 5);
1229
1230 /* >>> SUPER_LONG_RR: Need to handle CA part lengths > 250
1231 (This cannot happen with name lengths <= 256, as a part
1232 of the name will always fit into the directory entry.)
1233 */;
1234
1235 susp_calc_add_to_ce(ce, base_ce, 5 + namelen, flag & 2);
1236 *su_size = space;
1237 }
1238 if (n->type == ECMA119_SYMLINK) {
1239 /*
1240 * for symlinks, we also need to write the SL
1241 */
1242 char *dest, *cur, *prev;
1243 size_t sl_len = 5;
1244 int cew = (*ce != 0); /* are we writing to CA ? */
1245
1246 dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
1247 if (dest == NULL) {
1248 *ce += ce_prepad;
1249 return -2;
1250 }
1251 prev = dest;
1252 cur = strchr(prev, '/');
1253 while (1) {
1254 size_t clen;
1255 if (cur) {
1256 clen = cur - prev;
1257 } else {
1258 /* last component */
1259 clen = strlen(prev);
1260 }
1261
1262 if (clen == 1 && prev[0] == '.') {
1263 clen = 0;
1264 } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
1265 clen = 0;
1266 }
1267
1268 /* flags and len for each component record (RRIP, 4.1.3.1) */
1269 clen += 2;
1270
1271 if (!cew) {
1272 /* we are still writing to the SUA */
1273 if (*su_size + sl_len + clen > space) {
1274 /*
1275 * ok, we need a Continuation Area anyway
1276 * TODO this can be handled better, but for now SL
1277 * will be completely moved into the CA
1278 */
1279 if (!(flag & 1)) {
1280 free(dest);
1281 goto unannounced_ca;
1282 }
1283 cew = 1;
1284 } else {
1285 sl_len += clen;
1286 }
1287 }
1288 if (cew) {
1289 if (sl_len + clen > 255) {
1290 /* we need an additional SL entry */
1291 if (clen > 250) {
1292 /*
1293 * case 1, component too large to fit in a
1294 * single SL entry. Thus, the component need
1295 * to be divided anyway.
1296 * Note than clen can be up to 255 + 2 = 257.
1297 *
1298 * First, we check how many bytes fit in current
1299 * SL field
1300 */
1301 ssize_t fit = 255 - sl_len - 2;
1302 if ((ssize_t) (clen - 250) <= fit) {
1303 /*
1304 * the component can be divided between this
1305 * and another SL entry
1306 */
1307 /* Will fill up old SL and write it */
1308 susp_calc_add_to_ce(ce, base_ce, 255, flag & 2);
1309 sl_len = 5 + (clen - fit); /* Start new SL */
1310 } else {
1311 /*
1312 * the component will need a 2rd SL entry in
1313 * any case, so we prefer to don't write
1314 * anything in this SL
1315 */
1316 /* Will write non-full old SL */
1317 susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1318 /* Will write another full SL */
1319 susp_calc_add_to_ce(ce, base_ce, 255, flag & 2);
1320 sl_len = 5 + (clen - 250) + 2; /* Start new SL */
1321 }
1322 } else {
1323 /* case 2, create a new SL entry */
1324 /* Will write non-full old SL */
1325 susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1326 sl_len = 5 + clen; /* Start new SL */
1327 }
1328 } else {
1329 sl_len += clen;
1330 }
1331 }
1332
1333 if (!cur || cur[1] == '\0') {
1334 /* cur[1] can be \0 if dest ends with '/' */
1335 break;
1336 }
1337 prev = cur + 1;
1338 cur = strchr(prev, '/');
1339 }
1340
1341 free(dest);
1342
1343 /* and finally write the pending SL field */
1344 if (!cew) {
1345 /* the whole SL fits into the SUA */
1346 *su_size += sl_len;
1347 } else {
1348 susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2);
1349 }
1350
1351 }
1352
1353 /* Find out whether ZF is to be added and account for its bytes */
1354 sua_free = space - *su_size;
1355 add_zf_field(t, n, NULL, &sua_free, ce, base_ce, 1 | (flag & 2));
1356 *su_size = space - sua_free;
1357 if (*ce > 0 && !(flag & 1))
1358 goto unannounced_ca;
1359
1360 *ce += ce_prepad;
1361 ce_prepad = 0;
1362
1363 /* obtain num_aapt from node */
1364 xipt = NULL;
1365 num_aapt = 0;
1366 if (t->opts->aaip) {
1367 ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt);
1368 if (ret == 1) {
1369 num_aapt = aaip_count_bytes((unsigned char *) xipt, 0);
1370 }
1371 }
1372 /* let the expert decide where to add num_aapt */
1373 if (num_aapt > 0) {
1374 sua_free = space - *su_size;
1375 aapt = (uint8_t *) xipt;
1376 aaip_add_AL(t, NULL, &aapt, num_aapt, &sua_free, ce, base_ce,
1377 1 | (flag & 2));
1378 *su_size = space - sua_free;
1379 if (*ce > 0 && !(flag & 1))
1380 goto unannounced_ca;
1381 }
1382
1383 #ifdef Libisofs_ce_calc_debug_filetraP
1384
1385 if (n->node->name != NULL)
1386 if (strcmp(n->node->name, "...insert.leaf.name.here...") == 0)
1387 fprintf(stderr,
1388 "libburn_DEBUG: filename breakpoint susp_calc_nm_sl_al\n");
1389
1390 #endif /* Libisofs_ce_calc_debug_filetraP */
1391
1392 if (*ce > 0 && !(flag & 2)) {
1393 if (base_ce / BLOCK_SIZE !=
1394 (base_ce + *ce + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE) {
1395
1396 #ifdef Libisofs_ce_calc_debuG
1397
1398 fprintf(stderr,
1399 "\nlibburn_DEBUG: Crossed block boundary: %.f (%lu) -> %.f (%lu) : %s\n\n",
1400 (double) base_ce, (unsigned long) (base_ce / BLOCK_SIZE),
1401 (double) (base_ce + *ce - 1),
1402 (unsigned long)
1403 ((base_ce + *ce + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE),
1404 n->node->name);
1405
1406 #endif /* Libisofs_ce_calc_debuG */
1407
1408 /* Crossed a block boundary */
1409 *su_size = su_mem;
1410 *ce = ce_mem;
1411 return 0;
1412 }
1413 }
1414
1415 *ce += ce_prepad;
1416 return 1;
1417
1418 unannounced_ca:;
1419 *su_size = su_mem;
1420 *ce = ce_mem;
1421 return 0;
1422 }
1423
1424
1425 /* @param flag bit0= Do not add data but only count sua_free and ce_len
1426 param info may be NULL in this case
1427 bit1= account for crossing block boundaries
1428 (implied by bit0 == 0)
1429 */
1430 static
add_aa_string(Ecma119Image * t,Ecma119Node * n,struct susp_info * info,size_t * sua_free,size_t * ce_len,size_t base_ce,int flag)1431 int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
1432 size_t *sua_free, size_t *ce_len, size_t base_ce, int flag)
1433 {
1434 int ret;
1435 uint8_t *aapt;
1436 void *xipt;
1437 size_t num_aapt= 0;
1438
1439 if (!t->opts->aaip)
1440 return 1;
1441
1442 ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt);
1443 if (ret == 1) {
1444 num_aapt = aaip_count_bytes((unsigned char *) xipt, 0);
1445 if (num_aapt > 0) {
1446 if (flag & 1) {
1447 aapt = (unsigned char *) xipt;
1448 ret = aaip_add_AL(t, NULL, &aapt, num_aapt, sua_free, ce_len,
1449 base_ce, flag & (1 | 2));
1450 } else {
1451 aapt = malloc(num_aapt);
1452 if (aapt == NULL)
1453 return ISO_OUT_OF_MEM;
1454 memcpy(aapt, xipt, num_aapt);
1455 ret = aaip_add_AL(t, info, &aapt, num_aapt, sua_free, ce_len,
1456 base_ce, 0);
1457 /* aapt is NULL now and the memory is owned by t */
1458 }
1459 if (ret < 0)
1460 return ret;
1461 }
1462 }
1463 return 1;
1464 }
1465
1466
1467 /**
1468 * Compute the length needed for write all RR and SUSP entries for a given
1469 * node.
1470 *
1471 * @param type
1472 * 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
1473 * for that node (i.e., it will refer to the parent)
1474 * @param used_up
1475 * Already occupied space in the directory record.
1476 * @param ce
1477 * Will be filled with the space needed in a CE
1478 * @param base_ce
1479 * Predicted fill of continuation area by previous nodes of same dir
1480 * @return
1481 * The size needed for the RR entries in the System Use Area
1482 */
rrip_calc_len(Ecma119Image * t,Ecma119Node * n,int type,size_t used_up,size_t * ce,size_t base_ce)1483 size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up,
1484 size_t *ce, size_t base_ce)
1485 {
1486 size_t su_size, space;
1487 int ret;
1488 size_t aaip_sua_free= 0, aaip_len= 0;
1489
1490 /* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
1491 */
1492 space = 254 - used_up - (used_up % 2);
1493 if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
1494 iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
1495 "Unknown node type %d or short RR space %d < %d in directory record",
1496 type, (int) space, ISO_ROCKRIDGE_IN_DIR_REC);
1497 return ISO_ASSERT_FAILURE;
1498 }
1499
1500 *ce = 0;
1501 su_size = 0;
1502
1503 /* If AAIP enabled and announced by ER : account for 5 bytes of ES */;
1504 if (t->opts->aaip && !t->opts->aaip_susp_1_10)
1505 su_size += 5;
1506
1507 #ifdef Libisofs_with_rrip_rR
1508 /* obsolete RR field (once in RRIP-1.09) */
1509 su_size += 5;
1510 #endif
1511
1512 /* PX and TF, we are sure they always fit in SUA */
1513 if (t->opts->rrip_1_10_px_ino || !t->opts->rrip_version_1_10) {
1514 su_size += 44 + 26;
1515 } else {
1516 su_size += 36 + 26;
1517 }
1518
1519 if (n->type == ECMA119_DIR) {
1520 if (n->info.dir->real_parent != NULL) {
1521 /* it is a reallocated entry */
1522 if (type == 2) {
1523 /* we need to add a PL entry */
1524 su_size += 12;
1525 } else if (type == 0) {
1526 /* we need to add a RE entry */
1527 su_size += 4;
1528 }
1529 } else if(ecma119_is_dedicated_reloc_dir(t, n) &&
1530 (t->opts->rr_reloc_flags & 1)) {
1531 /* The dedicated relocation directory shall be marked by RE */
1532 su_size += 4;
1533 }
1534 } else if (n->type == ECMA119_SPECIAL) {
1535 if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
1536 /* block or char device, we need a PN entry */
1537 su_size += 20;
1538 }
1539 } else if (n->type == ECMA119_PLACEHOLDER) {
1540 /* we need the CL entry */
1541 su_size += 12;
1542 }
1543
1544 if (type == 0) {
1545
1546 /* Try without CE */
1547 ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 0);
1548 if (ret == 0) /* Retry with CE but no block crossing */
1549 ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1);
1550 if (ret == 0) /* Retry with aligned CE and block hopping */
1551 ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1 | 2);
1552 if (ret == -2)
1553 return ISO_OUT_OF_MEM;
1554
1555 } else {
1556
1557 /* "." or ".." entry */
1558
1559 if (!t->opts->rrip_version_1_10)
1560 su_size += 5; /* NM field */
1561
1562 if (type == 1 && n->parent == NULL) {
1563 /*
1564 * "." for root directory
1565 * we need to write SP and ER entries. The first fits in SUA,
1566 * ER needs a Continuation Area, thus we also need a CE entry
1567 */
1568 su_size += 7 + 28; /* SP + CE */
1569 /* ER of RRIP */
1570 if (t->opts->rrip_version_1_10) {
1571 *ce = 237;
1572 } else {
1573 *ce = 182;
1574 }
1575 if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
1576 *ce += 160; /* ER of AAIP */
1577 }
1578 /* Compute length of AAIP string of root node.
1579 Will write all AIIP to CA, which already starts at
1580 block boundary. So no need for three tries.
1581 */
1582 aaip_sua_free= 0;
1583 ret = add_aa_string(t, n, NULL, &aaip_sua_free, &aaip_len, base_ce,
1584 1 | 2);
1585 if (ret < 0)
1586 return ret;
1587 *ce += aaip_len;
1588 }
1589 }
1590
1591 /*
1592 * The System Use field inside the directory record must be padded if
1593 * it is an odd number (ECMA-119, 9.1.13)
1594 */
1595 su_size += (su_size % 2);
1596 return su_size;
1597 }
1598
1599 /**
1600 * Free all info in a struct susp_info.
1601 */
1602 static
susp_info_free(struct susp_info * susp)1603 void susp_info_free(struct susp_info* susp)
1604 {
1605 size_t i;
1606
1607 for (i = 0; i < susp->n_susp_fields; ++i) {
1608 free(susp->susp_fields[i]);
1609 }
1610 free(susp->susp_fields);
1611
1612 for (i = 0; i < susp->n_ce_susp_fields; ++i) {
1613 free(susp->ce_susp_fields[i]);
1614 }
1615 free(susp->ce_susp_fields);
1616 }
1617
1618
1619 /**
1620 * Fill a struct susp_info with the RR/SUSP entries needed for a given
1621 * node.
1622 *
1623 * @param type
1624 * 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
1625 * for that node (i.e., it will refer to the parent)
1626 * @param used_up
1627 * Already occupied space in the directory record.
1628 * @param info
1629 * Pointer to the struct susp_info where the entries will be stored.
1630 * If some entries need to go to a Continuation Area, they will be added
1631 * to the existing ce_susp_fields, and ce_len will be incremented
1632 * properly. Please ensure ce_block is initialized properly.
1633 * @return
1634 * 1 success, < 0 error
1635 */
rrip_get_susp_fields(Ecma119Image * t,Ecma119Node * n,int type,size_t used_up,struct susp_info * info)1636 int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
1637 size_t used_up, struct susp_info *info)
1638 {
1639 int ret;
1640 size_t i;
1641 Ecma119Node *node;
1642 char *name = NULL;
1643 char *dest = NULL;
1644 size_t aaip_er_len= 0;
1645 size_t rrip_er_len= 182;
1646 size_t su_size_pd, ce_len_pd; /* predicted sizes of SUA and CA */
1647 int ce_is_predicted = 0;
1648 size_t aaip_sua_free= 0, aaip_len= 0, ce_mem;
1649 int space;
1650
1651 if (t == NULL || n == NULL || info == NULL) {
1652 return ISO_NULL_POINTER;
1653 }
1654
1655 /* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
1656 */
1657 space = 254 - used_up - (used_up % 2);
1658 if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
1659 iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
1660 "Unknown node type %d or short RR space %d < %d in directory record",
1661 type, space, ISO_ROCKRIDGE_IN_DIR_REC);
1662 return ISO_ASSERT_FAILURE;
1663 }
1664
1665 /* Mark start index of node's continuation area for later update */
1666 info->current_ce_start = info->n_ce_susp_fields;
1667 ce_mem = info->ce_len;
1668
1669 #ifdef Libisofs_ce_calc_debug_filetraP
1670
1671 if (n->node->name != NULL)
1672 if (strcmp(n->node->name, "...put.leafname.here...") == 0)
1673 fprintf(stderr, "libburn_DEBUG: filename breakpoint\n");
1674
1675 #endif /* Libisofs_ce_calc_debug_filetraP */
1676
1677 if (type == 2 && n->parent != NULL) {
1678 node = n->parent;
1679 } else {
1680 node = n;
1681 }
1682
1683 /*
1684 * SP must be the first entry for the "." record of the root directory
1685 * (SUSP, 5.3)
1686 */
1687 if (type == 1 && n->parent == NULL) {
1688 ret = susp_add_SP(t, info);
1689 if (ret < 0) {
1690 goto add_susp_cleanup;
1691 }
1692 }
1693
1694 /* If AAIP enabled and announced by ER : Announce RRIP by ES */
1695 if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
1696 ret = susp_add_ES(t, info, 0, 0);
1697 if (ret < 0)
1698 goto add_susp_cleanup;
1699 }
1700
1701 #ifdef Libisofs_with_rrip_rR
1702 ret = rrip_add_RR(t, node, info);
1703 if (ret < 0) {
1704 goto add_susp_cleanup;
1705 }
1706 #endif /* Libisofs_with_rrip_rR */
1707
1708 /* PX and TF, we are sure they always fit in SUA */
1709 ret = rrip_add_PX(t, node, info);
1710 if (ret < 0) {
1711 goto add_susp_cleanup;
1712 }
1713 ret = rrip_add_TF(t, node, info);
1714 if (ret < 0) {
1715 goto add_susp_cleanup;
1716 }
1717
1718 if (n->type == ECMA119_DIR) {
1719 if (n->info.dir->real_parent != NULL) {
1720 /* it is a reallocated entry */
1721 if (type == 2) {
1722 /*
1723 * we need to add a PL entry
1724 * Note that we pass "n" as parameter, not "node"
1725 */
1726 ret = rrip_add_PL(t, n, info);
1727 if (ret < 0) {
1728 goto add_susp_cleanup;
1729 }
1730 } else if (type == 0) {
1731 /* we need to add a RE entry */
1732 ret = rrip_add_RE(t, node, info);
1733 if (ret < 0) {
1734 goto add_susp_cleanup;
1735 }
1736 }
1737 } else if(ecma119_is_dedicated_reloc_dir(t, n) &&
1738 (t->opts->rr_reloc_flags & 1)) {
1739 /* The dedicated relocation directory shall be marked by RE */
1740 ret = rrip_add_RE(t, node, info);
1741 if (ret < 0)
1742 goto add_susp_cleanup;
1743 }
1744 } else if (n->type == ECMA119_SPECIAL) {
1745 if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
1746 /* block or char device, we need a PN entry */
1747 ret = rrip_add_PN(t, node, info);
1748 if (ret < 0) {
1749 goto add_susp_cleanup;
1750 }
1751 }
1752 } else if (n->type == ECMA119_PLACEHOLDER) {
1753 /* we need the CL entry */
1754 ret = rrip_add_CL(t, node, info);
1755 if (ret < 0) {
1756 goto add_susp_cleanup;
1757 }
1758 }
1759
1760 if (info->suf_len + 28 > space) {
1761 iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
1762 "Directory Record overflow. name='%s' , suf_len=%d > space=%d - 28\n",
1763 node->iso_name, (int) info->suf_len, space);
1764 return ISO_ASSERT_FAILURE;
1765 }
1766
1767 if (type == 0) {
1768 size_t sua_free; /* free space in the SUA */
1769 int nm_type = 0; /* 0 whole entry in SUA, 1 part in CE */
1770 size_t ce_len = 0; /* len of the CE */
1771 size_t namelen;
1772
1773 /* this two are only defined for symlinks */
1774 uint8_t **comps= NULL; /* components of the SL field */
1775 size_t n_comp = 0; /* number of components */
1776
1777 namelen = 0;
1778 name = get_rr_fname(t, n->node->name);
1779 if (name == NULL)
1780 name = strdup("");
1781 if (name == NULL) {
1782 ret = ISO_OUT_OF_MEM;
1783 goto add_susp_cleanup;
1784 }
1785 namelen = strlen(name);
1786 sua_free = space - info->suf_len;
1787
1788 /* Try whether NM, SL, AL will fit into SUA */
1789 su_size_pd = info->suf_len;
1790 ce_len_pd = ce_len;
1791 ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1792 &su_size_pd, &ce_len_pd, info->ce_len, 0);
1793 if (ret == 0) { /* Have to use CA. 28 bytes of CE are necessary */
1794 ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1795 &su_size_pd, &ce_len_pd, info->ce_len, 1);
1796 if (ret == 0) /* Retry with aligned CE and block hopping */
1797 ret = susp_calc_nm_sl_al(t, n, (size_t) space,
1798 &su_size_pd, &ce_len_pd, info->ce_len,
1799 1 | 2);
1800 sua_free -= 28;
1801 ce_is_predicted = 1;
1802 }
1803 if (ret == -2) {
1804 ret = ISO_OUT_OF_MEM;
1805 goto add_susp_cleanup;
1806 }
1807
1808 /* NM entry */
1809 if (5 + namelen <= sua_free) {
1810 /* ok, it fits in System Use Area */
1811 sua_free -= (5 + namelen);
1812 nm_type = 0;
1813 } else {
1814 /* the NM will be divided in a CE */
1815 nm_type = 1;
1816 namelen = namelen - (sua_free - 5);
1817 ce_len = 5 + namelen;
1818 sua_free = 0;
1819 }
1820 if (n->type == ECMA119_SYMLINK) {
1821 /*
1822 * for symlinks, we also need to write the SL
1823 */
1824 char *cur, *prev;
1825 size_t sl_len = 5;
1826 int cew = (nm_type == 1); /* are we writing to CE? */
1827
1828 dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
1829 if (dest == NULL)
1830 dest = strdup("");
1831 if (dest == NULL) {
1832 ret = ISO_OUT_OF_MEM;
1833 goto add_susp_cleanup;
1834 }
1835
1836 prev = dest;
1837 cur = strchr(prev, '/');
1838 while (1) {
1839 size_t clen;
1840 char cflag = 0; /* component flag (RRIP, 4.1.3.1) */
1841 if (cur) {
1842 clen = cur - prev;
1843 } else {
1844 /* last component */
1845 clen = strlen(prev);
1846 }
1847
1848 if (clen == 0) {
1849 /* this refers to the roor directory, '/' */
1850 cflag = 1 << 3;
1851 }
1852 if (clen == 1 && prev[0] == '.') {
1853 clen = 0;
1854 cflag = 1 << 1;
1855 } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
1856 clen = 0;
1857 cflag = 1 << 2;
1858 }
1859
1860 /* flags and len for each component record (RRIP, 4.1.3.1) */
1861 clen += 2;
1862
1863 if (!cew) {
1864 /* we are still writing to the SUA */
1865 if (sl_len + clen > sua_free) {
1866 /*
1867 * ok, we need a Continuation Area anyway
1868 * TODO this can be handled better, but for now SL
1869 * will be completely moved into the CA
1870 */
1871
1872 /* sua_free, ce_len, nm_type already account for CE */
1873 cew = 1;
1874
1875 } else {
1876 /* add the component */
1877 ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1878 clen - 2, cflag);
1879 if (ret < 0) {
1880 goto add_susp_cleanup;
1881 }
1882 sl_len += clen;
1883 }
1884 }
1885 if (cew) {
1886 if (sl_len + clen > 255) {
1887 /* we need an addition SL entry */
1888 if (clen > 250) {
1889 /*
1890 * case 1, component too large to fit in a
1891 * single SL entry. Thus, the component need
1892 * to be divided anyway.
1893 * Note than clen can be up to 255 + 2 = 257.
1894 *
1895 * First, we check how many bytes fit in current
1896 * SL field
1897 */
1898 ssize_t fit = 255 - sl_len - 2;
1899 if ((ssize_t) (clen - 250) <= fit) {
1900 /*
1901 * the component can be divided between this
1902 * and another SL entry
1903 */
1904 ret = rrip_SL_append_comp(&n_comp, &comps,
1905 prev, fit, 0x01);
1906 if (ret < 0) {
1907 goto add_susp_cleanup;
1908 }
1909 /*
1910 * and another component, that will go in
1911 * other SL entry
1912 */
1913 ret = rrip_SL_append_comp(&n_comp, &comps, prev
1914 + fit, clen - fit - 2, 0);
1915 if (ret < 0) {
1916 goto add_susp_cleanup;
1917 }
1918 ce_len += 255; /* this SL, full */
1919 sl_len = 5 + (clen - fit);
1920 } else {
1921 /*
1922 * the component will need a 2rd SL entry in
1923 * any case, so we prefer to don't write
1924 * anything in this SL
1925 */
1926 ret = rrip_SL_append_comp(&n_comp, &comps,
1927 prev, 248, 0x01);
1928 if (ret < 0) {
1929 goto add_susp_cleanup;
1930 }
1931 ret = rrip_SL_append_comp(&n_comp, &comps, prev
1932 + 248, strlen(prev + 248), 0x00);
1933 if (ret < 0) {
1934 goto add_susp_cleanup;
1935 }
1936 ce_len += sl_len + 255;
1937 sl_len = 5 + (clen - 250) + 2;
1938 }
1939 } else {
1940 /* case 2, create a new SL entry */
1941 ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1942 clen - 2, cflag);
1943 if (ret < 0) {
1944 goto add_susp_cleanup;
1945 }
1946 ce_len += sl_len;
1947 sl_len = 5 + clen;
1948 }
1949 } else {
1950 /* the component fit in the SL entry */
1951 ret = rrip_SL_append_comp(&n_comp, &comps, prev,
1952 clen - 2, cflag);
1953 if (ret < 0) {
1954 goto add_susp_cleanup;
1955 }
1956 sl_len += clen;
1957 }
1958 }
1959
1960 if (!cur || cur[1] == '\0') {
1961 /* cur[1] can be \0 if dest ends with '/' */
1962 break;
1963 }
1964 prev = cur + 1;
1965 cur = strchr(prev, '/');
1966 }
1967
1968 if (cew) {
1969 ce_len += sl_len;
1970 }
1971 }
1972
1973 /*
1974 * We we reach here:
1975 * - We know if NM fill in the SUA (nm_type == 0)
1976 * - If SL needs an to be written in CE (ce_len > 0)
1977 * - The components for SL entry (or entries)
1978 */
1979
1980 if (nm_type == 0) {
1981 /* the full NM fills in SUA */
1982 ret = rrip_add_NM(t, info, name, strlen(name), 0, 0);
1983 if (ret < 0) {
1984 goto add_susp_cleanup;
1985 }
1986 } else {
1987 /*
1988 * Write the NM part that fits in SUA... Note that CE
1989 * entry and NM in the continuation area is added below
1990 */
1991
1992 namelen = space - info->suf_len - 28 * (!!ce_is_predicted) - 5;
1993 ret = rrip_add_NM(t, info, name, namelen, 1, 0);
1994 if (ret < 0) {
1995 goto add_susp_cleanup;
1996 }
1997 }
1998
1999 if (ce_is_predicted) {
2000 if ((info->ce_len % BLOCK_SIZE) &&
2001 (info->ce_len + ce_len_pd - 1 ) / BLOCK_SIZE !=
2002 info->ce_len / BLOCK_SIZE) {
2003 /* Linux fs/isofs wants byte_offset + ce_len <= BLOCK_SIZE
2004 * Insert padding to shift CE offset to next block start
2005 */
2006
2007 #ifdef Libisofs_ce_calc_debuG
2008
2009 fprintf(stderr,
2010 "\nlibburn_DEBUG: Inserting %d bytes of CE padding : %s\n\n",
2011 (int) (BLOCK_SIZE - (info->ce_len % BLOCK_SIZE)),
2012 n->node->name);
2013
2014 #endif /* Libisofs_ce_calc_debuG */
2015
2016 ret = pseudo_susp_add_PAD(t, info);
2017 if (ret < 0)
2018 goto add_susp_cleanup;
2019 }
2020 /* Add the CE entry */
2021 ret = susp_add_CE(t, ce_len_pd, info);
2022 if (ret < 0) {
2023 goto add_susp_cleanup;
2024 }
2025 }
2026
2027 if (nm_type == 1) {
2028 /*
2029 * ..and the part that goes to continuation area.
2030 */
2031
2032 /* >>> SUPER_LONG_RR : Need a loop to handle CA lengths > 250
2033 (This cannot happen with name lengths <= 256, as a part
2034 of the name will always fit into the directory entry.)
2035 */;
2036
2037 ret = rrip_add_NM(t, info, name + namelen, strlen(name + namelen),
2038 0, 1);
2039 if (ret < 0) {
2040 goto add_susp_cleanup;
2041 }
2042 }
2043
2044 if (n->type == ECMA119_SYMLINK) {
2045
2046 /* add the SL entry (or entries) */
2047 ret = rrip_add_SL(t, info, comps, n_comp, (ce_len > 0));
2048
2049 /* free the components */
2050 for (i = 0; i < n_comp; i++) {
2051 free(comps[i]);
2052 }
2053 free(comps);
2054
2055 if (ret < 0) {
2056 goto add_susp_cleanup;
2057 }
2058 }
2059
2060 /* Eventually write zisofs ZF field */
2061 ret = add_zf_field(t, n, info, &sua_free, &ce_len, ce_mem, 0);
2062 if (ret < 0)
2063 goto add_susp_cleanup;
2064
2065 /* Eventually obtain AAIP field string from node
2066 and write it to directory entry or CE area.
2067 */
2068 ret = add_aa_string(t, n, info, &sua_free, &ce_len, ce_mem, 0);
2069 if (ret < 0)
2070 goto add_susp_cleanup;
2071
2072
2073 } else {
2074
2075 /* "." or ".." entry */
2076
2077 /* write the NM entry */
2078 if (t->opts->rrip_version_1_10) {
2079 /* RRIP-1.10:
2080 "NM" System Use Fields recorded for the ISO 9660 directory
2081 records with names (00) and (01), used to designate the
2082 current and parent directories, respectively, should be
2083 ignored. Instead, the receiving system should convert these
2084 names to the appropriate receiving system-dependent
2085 designations for the current and parent directories.
2086 */
2087 /* mkisofs obviously writes no NM for '.' and '..' .
2088 Program isoinfo shows empty names with records as of RRIP-1.12
2089 */
2090 /* no op */;
2091 } else {
2092 /* RRIP-1.12:
2093 If the ISO 9660 Directory Record File Identifier is (00), then
2094 the CURRENT bit of the "NM" Flags field [...], if present, shall
2095 be set to ONE. If the ISO 9660 Directory Record File Identifier
2096 is (01), then the PARENT bit of the "NM" Flags field [...],
2097 if present, shall be set to ONE.
2098 [...]
2099 "BP 3 - Length (LEN_NM)" shall specify as an 8-bit number the
2100 length in bytes [...]. If bit position 1, 2, or 5 of the "NM"
2101 Flags is set to ONE, the value of this field shall be 5 and no
2102 Name Content shall be recorded.
2103 [The CURRENT bit has position 1. The PARENT bit has position 2.]
2104 */
2105 ret = rrip_add_NM(t, info, NULL, 0, 1 << type, 0);
2106 if (ret < 0)
2107 goto add_susp_cleanup;
2108 }
2109
2110 if (type == 1 && n->parent == NULL) {
2111 /*
2112 * "." for root directory
2113 * we need to write SP and ER entries. The first fits in SUA,
2114 * ER needs a Continuation Area, thus we also need a CE entry.
2115 * Note that SP entry was already added above
2116 */
2117
2118 if (t->opts->rrip_version_1_10) {
2119 rrip_er_len = 237;
2120 } else {
2121 rrip_er_len = 182;
2122 }
2123 if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
2124 aaip_er_len = 160;
2125 }
2126
2127 /* Compute length of AAIP string of root node */
2128 aaip_sua_free= 0;
2129 ret = add_aa_string(t, n, NULL, &aaip_sua_free, &aaip_len, ce_mem,
2130 1 | 2);
2131 if (ret < 0)
2132 goto add_susp_cleanup;
2133
2134 /* Allocate the necessary CE space */
2135 ret = susp_add_CE(t, rrip_er_len + aaip_er_len + aaip_len, info);
2136 if (ret < 0) {
2137 goto add_susp_cleanup;
2138 }
2139 ret = rrip_add_ER(t, info);
2140 if (ret < 0) {
2141 goto add_susp_cleanup;
2142 }
2143 if (t->opts->aaip && !t->opts->aaip_susp_1_10) {
2144 ret = aaip_add_ER(t, info, 0);
2145 if (ret < 0) {
2146 goto add_susp_cleanup;
2147 }
2148 }
2149 /* Write AAIP string of root node */
2150 aaip_sua_free= aaip_len= 0;
2151 ret = add_aa_string(t, n, info, &aaip_sua_free, &aaip_len, ce_mem,
2152 0);
2153 if (ret < 0)
2154 goto add_susp_cleanup;
2155
2156 }
2157 }
2158
2159
2160 /*
2161 * The System Use field inside the directory record must be padded if
2162 * it is an odd number (ECMA-119, 9.1.13)
2163 */
2164 info->suf_len += (info->suf_len % 2);
2165
2166 free(name);
2167 free(dest);
2168 return ISO_SUCCESS;
2169
2170 add_susp_cleanup: ;
2171 if (name != NULL)
2172 free(name);
2173 if (dest != NULL)
2174 free(dest);
2175 susp_info_free(info);
2176 return ret;
2177 }
2178
2179
2180 /* Update the sizes of CE fields at end of info->susp_fields and in
2181 single node range of info->ce_susp_fields.
2182 */
2183 static
susp_update_CE_sizes(Ecma119Image * t,struct susp_info * info,int flag)2184 int susp_update_CE_sizes(Ecma119Image *t, struct susp_info *info, int flag)
2185 {
2186 size_t i, curr_pos;
2187 uint8_t *curr_ce;
2188 uint32_t size;
2189
2190 if (info->n_susp_fields == 0 ||
2191 info->n_ce_susp_fields - info->current_ce_start == 0)
2192 return ISO_SUCCESS;
2193
2194 for (i = 0; i < info->n_susp_fields; i++)
2195 if (info->susp_fields[i][0] == 'C')
2196 if(info->susp_fields[i][1] == 'E')
2197 break;
2198 if (i >= info->n_susp_fields) {
2199 iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
2200 "System Use Area field contains no CE, but there are fields in Continuation Area");
2201 return ISO_ASSERT_FAILURE;
2202 }
2203 curr_ce = info->susp_fields[i];
2204 curr_pos = 0;
2205 for (i = info->current_ce_start; i < info->n_ce_susp_fields; i++) {
2206 if (info->ce_susp_fields[i][0] == 0) {
2207 curr_pos = 0; /* pseudo SUSP PAD */
2208 continue;
2209 }
2210 if (info->ce_susp_fields[i][0] == 'C' &&
2211 info->ce_susp_fields[i][1] == 'E') {
2212 size = (curr_pos + info->ce_susp_fields[i][2]) % BLOCK_SIZE;
2213 if (size == 0)
2214 size = BLOCK_SIZE;
2215 iso_bb(curr_ce + 20, size, 4);
2216 curr_ce = info->ce_susp_fields[i];
2217 }
2218 curr_pos = (curr_pos + info->ce_susp_fields[i][2]) % 2048;
2219 }
2220 if (curr_pos > 0) {
2221 size = curr_pos % BLOCK_SIZE;
2222 iso_bb(curr_ce + 20, size, 4);
2223 }
2224 return ISO_SUCCESS;
2225 }
2226
2227
2228 /**
2229 * Write the given SUSP fields into buf. Note that Continuation Area
2230 * fields are not written.
2231 * If info does not contain any SUSP entry this function just return.
2232 * After written, the info susp_fields array will be freed, and the counters
2233 * updated properly.
2234 */
rrip_write_susp_fields(Ecma119Image * t,struct susp_info * info,uint8_t * buf)2235 void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info,
2236 uint8_t *buf)
2237 {
2238 size_t i;
2239 size_t pos = 0;
2240 int ret;
2241
2242 if (info->n_susp_fields == 0) {
2243 return;
2244 }
2245
2246 ret = susp_update_CE_sizes(t, info, 0);
2247 if (ret < 0)
2248 return;
2249
2250 for (i = 0; i < info->n_susp_fields; i++) {
2251 memcpy(buf + pos, info->susp_fields[i], info->susp_fields[i][2]);
2252 pos += info->susp_fields[i][2];
2253 }
2254
2255 /* free susp_fields */
2256 for (i = 0; i < info->n_susp_fields; ++i) {
2257 free(info->susp_fields[i]);
2258 }
2259 free(info->susp_fields);
2260 info->susp_fields = NULL;
2261 info->n_susp_fields = 0;
2262 info->suf_len = 0;
2263 }
2264
2265 /**
2266 * Write the Continuation Area entries for the given struct susp_info, using
2267 * the iso_write() function.
2268 * After written, the ce_susp_fields array will be freed.
2269 */
rrip_write_ce_fields(Ecma119Image * t,struct susp_info * info)2270 int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info)
2271 {
2272 size_t i;
2273 uint8_t *padding = NULL;
2274 int ret= ISO_SUCCESS;
2275 uint64_t written = 0, pad_size;
2276
2277 if (info->n_ce_susp_fields == 0) {
2278 goto ex;
2279 }
2280 LIBISO_ALLOC_MEM(padding, uint8_t, BLOCK_SIZE);
2281
2282 for (i = 0; i < info->n_ce_susp_fields; i++) {
2283 if (info->ce_susp_fields[i][0] == 0) {
2284 /* Pseudo field: pad up to next block boundary */
2285 pad_size = BLOCK_SIZE - (written % BLOCK_SIZE);
2286 if (pad_size == BLOCK_SIZE)
2287 continue;
2288 memset(padding, 0, pad_size);
2289 ret = iso_write(t, padding, pad_size);
2290 if (ret < 0)
2291 goto write_ce_field_cleanup;
2292 written += pad_size;
2293 continue;
2294 }
2295 ret = iso_write(t, info->ce_susp_fields[i],
2296 info->ce_susp_fields[i][2]);
2297 if (ret < 0) {
2298 goto write_ce_field_cleanup;
2299 }
2300 written += info->ce_susp_fields[i][2];
2301 }
2302
2303 /* pad continuation area until block size */
2304 i = BLOCK_SIZE - (info->ce_len % BLOCK_SIZE);
2305 if (i > 0 && i < BLOCK_SIZE) {
2306 memset(padding, 0, i);
2307 ret = iso_write(t, padding, i);
2308 if (ret < 0)
2309 goto write_ce_field_cleanup;
2310 written += i;
2311 }
2312
2313 write_ce_field_cleanup: ;
2314 /* free ce_susp_fields */
2315 for (i = 0; i < info->n_ce_susp_fields; ++i) {
2316 free(info->ce_susp_fields[i]);
2317 }
2318 free(info->ce_susp_fields);
2319 info->ce_susp_fields = NULL;
2320 info->n_ce_susp_fields = 0;
2321 info->alloc_ce_susp_fields = 0;
2322 info->ce_len = 0;
2323 ex:;
2324 LIBISO_FREE_MEM(padding);
2325 return ret;
2326 }
2327
2328