1 /* @(#)multi.c 1.104 16/01/06 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)multi.c 1.104 16/01/06 joerg";
6 #endif
7 /*
8 * File multi.c - scan existing iso9660 image and merge into
9 * iso9660 filesystem. Used for multisession support.
10 *
11 * Written by Eric Youngdale (1996).
12 * Copyright (c) 1999-2016 J. Schilling
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 #include "mkisofs.h"
30 #include "rock.h"
31 #include <schily/time.h>
32 #include <schily/errno.h>
33 #include <schily/utypes.h>
34 #include <schily/schily.h>
35 #include <schily/ctype.h> /* Needed for printasc() */
36
37 #ifdef VMS
38
39 #include <sys/file.h>
40 #include <vms/fabdef.h>
41 #include "vms.h"
42 #endif
43
44 #ifndef howmany
45 #define howmany(x, y) (((x)+((y)-1))/(y))
46 #endif
47 #ifndef roundup
48 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
49 #endif
50
51 /*
52 * Cannot debug memset() with gdb on Linux, so use fillbytes()
53 */
54 /*#define memset(s, c, n) fillbytes(s, n, c)*/
55
56 #define TF_CREATE 1
57 #define TF_MODIFY 2
58 #define TF_ACCESS 4
59 #define TF_ATTRIBUTES 8
60
61 LOCAL void printasc __PR((char *txt, unsigned char *p, int len));
62 LOCAL void prbytes __PR((char *txt, unsigned char *p, int len));
63 unsigned char *parse_xa __PR((unsigned char *pnt, int *lenp,
64 struct directory_entry *dpnt));
65 EXPORT int rr_flags __PR((struct iso_directory_record *idr));
66 LOCAL int parse_rrflags __PR((Uchar *pnt, int len, int cont_flag));
67 LOCAL BOOL find_rr __PR((struct iso_directory_record *idr, Uchar **pntp, int *lenp));
68 LOCAL int parse_rr __PR((unsigned char *pnt, int len,
69 struct directory_entry *dpnt));
70 LOCAL int check_rr_dates __PR((struct directory_entry *dpnt,
71 struct directory_entry *current,
72 struct stat *statbuf,
73 struct stat *lstatbuf));
74 LOCAL BOOL valid_iso_directory __PR((struct iso_directory_record *idr,
75 int idr_off,
76 size_t space_left));
77 LOCAL struct directory_entry **
78 read_merging_directory __PR((struct iso_directory_record *, int *));
79 LOCAL int free_mdinfo __PR((struct directory_entry **, int len));
80 LOCAL void free_directory_entry __PR((struct directory_entry *dirp));
81 LOCAL int iso_dir_ents __PR((struct directory_entry *de));
82 LOCAL void copy_mult_extent __PR((struct directory_entry *se1,
83 struct directory_entry *se2));
84 LOCAL void merge_remaining_entries __PR((struct directory *,
85 struct directory_entry **, int));
86
87 LOCAL int merge_old_directory_into_tree __PR((struct directory_entry *,
88 struct directory *));
89 LOCAL void check_rr_relocation __PR((struct directory_entry *de));
90
91 FILE *in_image = NULL;
92 BOOL ignerr = FALSE;
93 int su_version = -1;
94 int rr_version = -1;
95 int aa_version = -1;
96 char er_id[256];
97
98 #ifndef USE_SCG
99 /*
100 * Don't define readsecs if mkisofs is linked with
101 * the SCSI library.
102 * readsecs() will be implemented as SCSI command in this case.
103 *
104 * Use global var in_image directly in readsecs()
105 * the SCSI equivalent will not use a FILE* for I/O.
106 *
107 * The main point of this pointless abstraction is that Solaris won't let
108 * you read 2K sectors from the cdrom driver. The fact that 99.9% of the
109 * discs out there have a 2K sectorsize doesn't seem to matter that much.
110 * Anyways, this allows the use of a scsi-generics type of interface on
111 * Solaris.
112 */
113 #ifdef PROTOTYPES
114 EXPORT int
readsecs(UInt32_t startsecno,void * buffer,int sectorcount)115 readsecs(UInt32_t startsecno, void *buffer, int sectorcount)
116 #else
117 EXPORT int
118 readsecs(startsecno, buffer, sectorcount)
119 UInt32_t startsecno;
120 void *buffer;
121 int sectorcount;
122 #endif
123 {
124 int f = fileno(in_image);
125
126 if (lseek(f, (off_t)startsecno * SECTOR_SIZE, SEEK_SET) == (off_t)-1) {
127 comerr(_("Seek error on old image\n"));
128 }
129 if (read(f, buffer, (sectorcount * SECTOR_SIZE))
130 != (sectorcount * SECTOR_SIZE)) {
131 comerr(_("Read error on old image\n"));
132 }
133 return (sectorcount * SECTOR_SIZE);
134 }
135
136 #endif
137
138 LOCAL void
printasc(txt,p,len)139 printasc(txt, p, len)
140 char *txt;
141 unsigned char *p;
142 int len;
143 {
144 int i;
145
146 error("%s ", txt);
147 for (i = 0; i < len; i++) {
148 if (isprint(p[i]))
149 error("%c", p[i]);
150 else
151 error(".");
152 }
153 error("\n");
154 }
155
156 LOCAL void
prbytes(txt,p,len)157 prbytes(txt, p, len)
158 char *txt;
159 register Uchar *p;
160 register int len;
161 {
162 error("%s", txt);
163 while (--len >= 0)
164 error(" %02X", *p++);
165 error("\n");
166 }
167
168 unsigned char *
parse_xa(pnt,lenp,dpnt)169 parse_xa(pnt, lenp, dpnt)
170 unsigned char *pnt;
171 int *lenp;
172 struct directory_entry *dpnt;
173 {
174 struct iso_xa_dir_record *xadp;
175 int len = *lenp;
176 static int did_xa = 0;
177
178 /*error("len: %d\n", len);*/
179
180 if (len >= 14) {
181 xadp = (struct iso_xa_dir_record *)pnt;
182
183 /* if (dpnt) prbytes("XA ", pnt, len);*/
184 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
185 xadp->reserved[0] == '\0') {
186 len -= 14;
187 pnt += 14;
188 *lenp = len;
189 if (!did_xa) {
190 did_xa = 1;
191 errmsgno(EX_BAD, _("Found XA directory extension record.\n"));
192 }
193 } else if (pnt[2] == 0) {
194 char *cp = NULL;
195
196 if (dpnt)
197 cp = (char *)&dpnt->isorec;
198 if (cp) {
199 prbytes("ISOREC:", (Uchar *)cp, 33+cp[32]);
200 printasc("ISOREC:", (Uchar *)cp, 33+cp[32]);
201 prbytes("XA REC:", pnt, len);
202 printasc("XA REC:", pnt, len);
203 }
204 if (no_rr == 0) {
205 errmsgno(EX_BAD, _("Disabling RR / XA / AA.\n"));
206 no_rr = 1;
207 }
208 *lenp = 0;
209 if (cp) {
210 errmsgno(EX_BAD, _("Problems with old ISO directory entry for file: '%s'.\n"), &cp[33]);
211 }
212 errmsgno(EX_BAD, _("Illegal extended directory attributes found (bad XA disk?).\n"));
213 /* errmsgno(EX_BAD, _("Disabling Rock Ridge for old session.\n"));*/
214 comerrno(EX_BAD, _("Try again using the -no-rr option.\n"));
215 }
216 }
217 if (len >= 4 && pnt[3] != 1 && pnt[3] != 2) {
218 prbytes("BAD RR ATTRIBUTES:", pnt, len);
219 printasc("BAD RR ATTRIBUTES:", pnt, len);
220 }
221 return (pnt);
222 }
223
224 LOCAL BOOL
find_rr(idr,pntp,lenp)225 find_rr(idr, pntp, lenp)
226 struct iso_directory_record *idr;
227 Uchar **pntp;
228 int *lenp;
229 {
230 struct iso_xa_dir_record *xadp;
231 int len;
232 unsigned char *pnt;
233 BOOL ret = FALSE;
234
235 len = idr->length[0] & 0xff;
236 len -= sizeof (struct iso_directory_record);
237 len += sizeof (idr->name);
238 len -= idr->name_len[0];
239
240 pnt = (unsigned char *) idr;
241 pnt += sizeof (struct iso_directory_record);
242 pnt -= sizeof (idr->name);
243 pnt += idr->name_len[0];
244 if ((idr->name_len[0] & 1) == 0) {
245 pnt++;
246 len--;
247 }
248 if (len >= 14) {
249 xadp = (struct iso_xa_dir_record *)pnt;
250
251 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
252 xadp->reserved[0] == '\0') {
253 len -= 14;
254 pnt += 14;
255 ret = TRUE;
256 }
257 }
258 *pntp = pnt;
259 *lenp = len;
260 return (ret);
261 }
262
263 LOCAL int
parse_rrflags(pnt,len,cont_flag)264 parse_rrflags(pnt, len, cont_flag)
265 Uchar *pnt;
266 int len;
267 int cont_flag;
268 {
269 int ncount;
270 UInt32_t cont_extent;
271 UInt32_t cont_offset;
272 UInt32_t cont_size;
273 int flag1;
274 int flag2;
275
276 cont_extent = cont_offset = cont_size = 0;
277
278 ncount = 0;
279 flag1 = -1;
280 flag2 = 0;
281 while (len >= 4) {
282 if (pnt[3] != 1 && pnt[3] != 2) {
283 errmsgno(EX_BAD,
284 _("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
285 pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
286 return (0); /* JS ??? Is this right ??? */
287 }
288 if (pnt[2] < 4) {
289 errmsgno(EX_BAD,
290 _("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
291 pnt[2], pnt, pnt[0], pnt[1]);
292 return (0); /* JS ??? Is this right ??? */
293 }
294 ncount++;
295 if (pnt[0] == 'R' && pnt[1] == 'R')
296 flag1 = pnt[4] & 0xff;
297
298 if (strncmp((char *)pnt, "PX", 2) == 0) /* POSIX attributes */
299 flag2 |= RR_FLAG_PX;
300 if (strncmp((char *)pnt, "PN", 2) == 0) /* POSIX device number */
301 flag2 |= RR_FLAG_PN;
302 if (strncmp((char *)pnt, "SL", 2) == 0) /* Symlink */
303 flag2 |= RR_FLAG_SL;
304 if (strncmp((char *)pnt, "NM", 2) == 0) /* Alternate Name */
305 flag2 |= RR_FLAG_NM;
306 if (strncmp((char *)pnt, "CL", 2) == 0) /* Child link */
307 flag2 |= RR_FLAG_CL;
308 if (strncmp((char *)pnt, "PL", 2) == 0) /* Parent link */
309 flag2 |= RR_FLAG_PL;
310 if (strncmp((char *)pnt, "RE", 2) == 0) /* Relocated Direcotry */
311 flag2 |= RR_FLAG_RE;
312 if (strncmp((char *)pnt, "TF", 2) == 0) /* Time stamp */
313 flag2 |= RR_FLAG_TF;
314 if (strncmp((char *)pnt, "SP", 2) == 0) { /* SUSP record */
315 flag2 |= RR_FLAG_SP;
316 if (su_version < 0)
317 su_version = pnt[3] & 0xff;
318 }
319 if (strncmp((char *)pnt, "AA", 2) == 0) { /* Apple Signature record */
320 flag2 |= RR_FLAG_AA;
321 if (aa_version < 0)
322 aa_version = pnt[3] & 0xff;
323 }
324 if (strncmp((char *)pnt, "ER", 2) == 0) {
325 flag2 |= RR_FLAG_ER; /* ER record */
326 if (rr_version < 0)
327 rr_version = pnt[7] & 0xff; /* Ext Version */
328 strlcpy(er_id, (char *)&pnt[8], (pnt[4] & 0xFF) + 1);
329 }
330
331 if (strncmp((char *)pnt, "CE", 2) == 0) { /* Continuation Area */
332 cont_extent = get_733(pnt+4);
333 cont_offset = get_733(pnt+12);
334 cont_size = get_733(pnt+20);
335 }
336 if (strncmp((char *)pnt, "ST", 2) == 0) { /* Terminate SUSP */
337 break;
338 }
339
340 len -= pnt[2];
341 pnt += pnt[2];
342 }
343 if (cont_extent) {
344 unsigned char sector[SECTOR_SIZE];
345
346 readsecs(cont_extent, sector, 1);
347 flag2 |= parse_rrflags(§or[cont_offset], cont_size, 1);
348 }
349 return (flag2);
350 }
351
352 int
rr_flags(idr)353 rr_flags(idr)
354 struct iso_directory_record *idr;
355 {
356 int len;
357 unsigned char *pnt;
358 int ret = 0;
359
360 if (find_rr(idr, &pnt, &len))
361 ret |= RR_FLAG_XA;
362 ret |= parse_rrflags(pnt, len, 0);
363 return (ret);
364 }
365
366 /*
367 * Parse the RR attributes so we can find the file name.
368 */
369 LOCAL int
parse_rr(pnt,len,dpnt)370 parse_rr(pnt, len, dpnt)
371 unsigned char *pnt;
372 int len;
373 struct directory_entry *dpnt;
374 {
375 UInt32_t cont_extent;
376 UInt32_t cont_offset;
377 UInt32_t cont_size;
378 char name_buf[256];
379
380 cont_extent = cont_offset = cont_size = 0;
381
382 pnt = parse_xa(pnt, &len, dpnt /* 0 */);
383
384 while (len >= 4) {
385 if (pnt[3] != 1 && pnt[3] != 2) {
386 errmsgno(EX_BAD,
387 _("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
388 pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
389 return (-1);
390 }
391 if (pnt[2] < 4) {
392 errmsgno(EX_BAD,
393 _("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
394 pnt[2], pnt, pnt[0], pnt[1]);
395 return (-1);
396 }
397 if (strncmp((char *)pnt, "NM", 2) == 0) {
398 strncpy(name_buf, (char *)pnt + 5, pnt[2] - 5);
399 name_buf[pnt[2] - 5] = 0;
400 if (dpnt->name) {
401 size_t nlen = strlen(dpnt->name);
402
403 /*
404 * append to name from previous NM records
405 */
406 dpnt->name = realloc(dpnt->name, nlen +
407 strlen(name_buf) + 1);
408 strcpy(dpnt->name + nlen, name_buf);
409 } else {
410 dpnt->name = e_strdup(name_buf);
411 dpnt->got_rr_name = 1;
412 }
413 /* continue searching for more NM records */
414 } else if (strncmp((char *)pnt, "CE", 2) == 0) {
415 cont_extent = get_733(pnt + 4);
416 cont_offset = get_733(pnt + 12);
417 cont_size = get_733(pnt + 20);
418 } else if (strncmp((char *)pnt, "ST", 2) == 0) {
419 break;
420 }
421
422 len -= pnt[2];
423 pnt += pnt[2];
424 }
425 if (cont_extent) {
426 unsigned char sector[SECTOR_SIZE];
427
428 readsecs(cont_extent, sector, 1);
429 if (parse_rr(§or[cont_offset], cont_size, dpnt) == -1)
430 return (-1);
431 }
432
433 /* Fall back to the iso name if no RR name found */
434 if (dpnt->name == NULL) {
435 char *cp;
436
437 strlcpy(name_buf, dpnt->isorec.name, sizeof (name_buf));
438 cp = strchr(name_buf, ';');
439 if (cp != NULL) {
440 *cp = '\0';
441 }
442 dpnt->name = e_strdup(name_buf);
443 }
444 return (0);
445 } /* parse_rr */
446
447
448 /*
449 * Returns 1 if the two files are identical
450 * Returns 0 if the two files differ
451 */
452 LOCAL int
check_rr_dates(dpnt,current,statbuf,lstatbuf)453 check_rr_dates(dpnt, current, statbuf, lstatbuf)
454 struct directory_entry *dpnt;
455 struct directory_entry *current;
456 struct stat *statbuf;
457 struct stat *lstatbuf;
458 {
459 UInt32_t cont_extent;
460 UInt32_t cont_offset;
461 UInt32_t cont_size;
462 UInt32_t offset;
463 unsigned char *pnt;
464 int len;
465 int same_file;
466 int same_file_type;
467 mode_t mode;
468 char time_buf[7];
469
470
471 cont_extent = cont_offset = cont_size = 0;
472 same_file = 1;
473 same_file_type = 1;
474
475 pnt = dpnt->rr_attributes;
476 len = dpnt->rr_attr_size;
477 /*
478 * We basically need to parse the rr attributes again, and dig out the
479 * dates and file types.
480 */
481 pnt = parse_xa(pnt, &len, /* dpnt */ 0);
482 while (len >= 4) {
483 if (pnt[3] != 1 && pnt[3] != 2) {
484 errmsgno(EX_BAD,
485 _("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
486 pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
487 return (-1);
488 }
489 if (pnt[2] < 4) {
490 errmsgno(EX_BAD,
491 _("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
492 pnt[2], pnt, pnt[0], pnt[1]);
493 return (-1);
494 }
495
496 /*
497 * If we have POSIX file modes, make sure that the file type is
498 * the same. If it isn't, then we must always write the new
499 * file.
500 */
501 if (strncmp((char *)pnt, "PX", 2) == 0) {
502 mode = get_733(pnt + 4);
503 if ((lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT)) {
504 same_file_type = 0;
505 same_file = 0;
506 }
507 }
508 if (strncmp((char *)pnt, "TF", 2) == 0) {
509 offset = 5;
510 if (pnt[4] & TF_CREATE) {
511 iso9660_date((char *)time_buf,
512 lstatbuf->st_ctime);
513 if (memcmp(time_buf, pnt + offset, 7) != 0)
514 same_file = 0;
515 offset += 7;
516 }
517 if (pnt[4] & TF_MODIFY) {
518 iso9660_date((char *)time_buf,
519 lstatbuf->st_mtime);
520 if (memcmp(time_buf, pnt + offset, 7) != 0)
521 same_file = 0;
522 offset += 7;
523 }
524 }
525 if (strncmp((char *)pnt, "CE", 2) == 0) {
526 cont_extent = get_733(pnt + 4);
527 cont_offset = get_733(pnt + 12);
528 cont_size = get_733(pnt + 20);
529 }
530 if (strncmp((char *)pnt, "ST", 2) == 0) { /* Terminate SUSP */
531 break;
532 }
533
534 len -= pnt[2];
535 pnt += pnt[2];
536 }
537 if (cont_extent) {
538 unsigned char sector[SECTOR_SIZE];
539
540 readsecs(cont_extent, sector, 1);
541 /*
542 * Continue to scan the extension record.
543 * Note that this has not been tested yet, but it is
544 * definitely more correct that calling parse_rr()
545 * as done in Eric's old code.
546 */
547 pnt = §or[cont_offset];
548 len = cont_size;
549 /*
550 * Clear the "pending extension record" state as
551 * we did already read it now.
552 */
553 cont_extent = cont_offset = cont_size = 0;
554 }
555
556 /*
557 * If we have the same fundamental file type, then it is clearly safe
558 * to reuse the TRANS.TBL entry.
559 */
560 if (same_file_type) {
561 current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
562 }
563 return (same_file);
564 }
565
566 LOCAL BOOL
valid_iso_directory(idr,idr_off,space_left)567 valid_iso_directory(idr, idr_off, space_left)
568 struct iso_directory_record *idr;
569 int idr_off;
570 size_t space_left;
571 {
572 size_t idr_length = idr->length[0] & 0xFF;
573 size_t idr_ext_length = idr->ext_attr_length[0] & 0xFF;
574 size_t idr_namelength = idr->name_len[0] & 0xFF;
575 int namelimit = space_left -
576 offsetof(struct iso_directory_record, name[0]);
577 int nlimit = (idr_namelength < namelimit) ?
578 idr_namelength : namelimit;
579
580 /*
581 * Check for sane length entries.
582 */
583 if (idr_length > space_left) {
584 comerrno(EX_BAD,
585 _("Bad directory length %zu (> %d available) for '%.*s'.\n"),
586 idr_length, namelimit, nlimit, idr->name);
587 }
588
589 if (idr_length == 0) {
590 if ((idr_off % SECTOR_SIZE) != 0) {
591 /*
592 * It marks a valid continuation entry.
593 */
594 return (TRUE);
595 } else {
596 comerrno(EX_BAD,
597 _("Zero directory length for '%.*s'.\n"),
598 nlimit, idr->name);
599 }
600 }
601 if (idr_length <= offsetof(struct iso_directory_record, name[0])) {
602 comerrno(EX_BAD, _("Bad directory length %zu (< %zu minimum).\n"),
603 idr_length, 1 + offsetof(struct iso_directory_record, name[0]));
604 }
605 if ((idr_length & 1) != 0) {
606 comerrno(EX_BAD, _("Odd directory length %zu for '%.*s'.\n"),
607 idr_length, nlimit, idr->name);
608 }
609
610 if (idr_namelength == 0) {
611 comerrno(EX_BAD, _("Zero filename length.\n"));
612 }
613
614 if (!(idr_namelength & 1)) {
615 /*
616 * if nam_len[0] is even, there has to be a pad byte at the end
617 * to make the directory length even
618 */
619 idr_namelength++;
620 }
621 if ((offsetof(struct iso_directory_record, name[0]) +
622 idr_namelength) > idr_length) {
623 int xlimit = idr_length -
624 offsetof(struct iso_directory_record, name[0]) -
625 idr_ext_length;
626
627 if (xlimit < 0)
628 xlimit = 0;
629 if (nlimit < xlimit)
630 xlimit = nlimit;
631 comerrno(EX_BAD, _("Bad filename length %zu (> %d) for '%.*s'.\n"),
632 idr_namelength, xlimit, xlimit, idr->name);
633 }
634 if ((offsetof(struct iso_directory_record, name[0]) +
635 idr_namelength + idr_ext_length) > idr_length) {
636 int xlimit = idr_length -
637 offsetof(struct iso_directory_record, name[0]) -
638 idr_namelength;
639
640 comerrno(EX_BAD, _("Bad extended attribute length %zu (> %d) for '%.*s'.\n"),
641 idr_ext_length, xlimit, nlimit, idr->name);
642 }
643
644 #ifdef __do_rr_
645 /* check for rock ridge extensions */
646
647 if (no_rr) {
648 /*
649 * Rock Ridge extensions are not present or manually disabled.
650 */
651 return (TRUE);
652 } else {
653 int rlen = idr_length -
654 offsetof(struct iso_directory_record, name[0]) -
655 idr_namelength;
656
657 /* Check for the minimum of Rock Ridge extensions. */
658 }
659 #endif
660 return (TRUE);
661 }
662
663 LOCAL struct directory_entry **
read_merging_directory(mrootp,nentp)664 read_merging_directory(mrootp, nentp)
665 struct iso_directory_record *mrootp;
666 int *nentp;
667 {
668 unsigned char *cpnt;
669 unsigned char *cpnt1;
670 char *p;
671 char *dirbuff;
672 int i;
673 struct iso_directory_record *idr;
674 UInt32_t len;
675 UInt32_t nbytes;
676 int nent;
677 int nmult; /* # of multi extent root entries */
678 int mx;
679 struct directory_entry **pnt;
680 UInt32_t rlen;
681 struct directory_entry **rtn;
682 int seen_rockridge;
683 unsigned char *tt_buf;
684 UInt32_t tt_extent;
685 UInt32_t tt_size;
686
687 static int warning_given = 0;
688
689 /*
690 * This is the number of sectors we will need to read. We need to
691 * round up to get the last fractional sector - we are asking for the
692 * data in terms of a number of sectors.
693 */
694 nbytes = roundup(get_733(mrootp->size), SECTOR_SIZE);
695
696 /*
697 * First, allocate a buffer large enough to read in the entire
698 * directory.
699 */
700 dirbuff = (char *)e_malloc(nbytes);
701
702 readsecs(get_733(mrootp->extent), dirbuff, nbytes / SECTOR_SIZE);
703
704 /*
705 * Next look over the directory, and count up how many entries we have.
706 */
707 len = get_733(mrootp->size);
708 i = 0;
709 *nentp = 0;
710 nent = 0;
711 nmult = 0;
712 mx = 0;
713 while ((i + offsetof(struct iso_directory_record, name[0])) < len) {
714 idr = (struct iso_directory_record *)&dirbuff[i];
715
716 if (!valid_iso_directory(idr, i, len - i))
717 break;
718
719 if (idr->length[0] == 0) {
720 i = ISO_ROUND_UP(i);
721 continue;
722 }
723 nent++;
724 if ((mx & ISO_MULTIEXTENT) == 0 &&
725 (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
726 nmult++; /* Need a multi extent root entry */
727 }
728 mx = idr->flags[0];
729 i += idr->length[0];
730 }
731
732 /*
733 * Now allocate the buffer which will hold the array we are about to
734 * return. We need one entry per real directory entry and in addition
735 * one multi-extent root entry per multi-extent file.
736 */
737 rtn = (struct directory_entry **)e_malloc((nent+nmult) * sizeof (*rtn));
738
739 /*
740 * Finally, scan the directory one last time, and pick out the relevant
741 * bits of information, and store it in the relevant bits of the
742 * structure.
743 */
744 i = 0;
745 pnt = rtn;
746 tt_extent = 0;
747 seen_rockridge = 0;
748 tt_size = 0;
749 mx = 0;
750 while ((i + offsetof(struct iso_directory_record, name[0])) < len) {
751 idr = (struct iso_directory_record *)&dirbuff[i];
752
753 if (!valid_iso_directory(idr, i, len - i))
754 break;
755
756 if (idr->length[0] == 0) {
757 i = ISO_ROUND_UP(i);
758 continue;
759 }
760 *pnt = (struct directory_entry *)e_malloc(sizeof (**rtn));
761 (*pnt)->next = NULL;
762 #ifdef DEBUG
763 error("IDR name: '%s' ist: %d soll: %d\n",
764 idr->name, strlen(idr->name), idr->name_len[0]);
765 #endif
766 movebytes(idr, &(*pnt)->isorec, idr->length[0] & 0xFF);
767 (*pnt)->starting_block =
768 get_733(idr->extent);
769 (*pnt)->size = get_733(idr->size);
770 if ((*pnt)->size == 0) {
771 /*
772 * Find lowest used inode number for zero sized files
773 */
774 if (((UInt32_t)(*pnt)->starting_block) <= null_inodes) {
775 null_inodes = (UInt32_t)(*pnt)->starting_block;
776 null_inodes--;
777 }
778 }
779 (*pnt)->priority = 0;
780 (*pnt)->name = NULL;
781 (*pnt)->got_rr_name = 0;
782 (*pnt)->table = NULL;
783 (*pnt)->whole_name = NULL;
784 (*pnt)->filedir = NULL;
785 (*pnt)->parent_rec = NULL;
786 /*
787 * Set this information so that we correctly cache previous
788 * session bits of information.
789 */
790 (*pnt)->inode = (*pnt)->starting_block;
791 (*pnt)->dev = PREV_SESS_DEV;
792 (*pnt)->rr_attributes = NULL;
793 (*pnt)->rr_attr_size = 0;
794 (*pnt)->total_rr_attr_size = 0;
795 (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
796 #ifdef APPLE_HYB
797 (*pnt)->assoc = NULL;
798 (*pnt)->hfs_ent = NULL;
799 #endif /* APPLE_HYB */
800
801 /*
802 * Check for and parse any RR attributes for the file. All we
803 * are really looking for here is the original name of the
804 * file.
805 */
806 rlen = idr->length[0] & 0xff;
807 cpnt = (unsigned char *) idr;
808
809 rlen -= offsetof(struct iso_directory_record, name[0]);
810 cpnt += offsetof(struct iso_directory_record, name[0]);
811
812 rlen -= idr->name_len[0];
813 cpnt += idr->name_len[0];
814
815 if ((idr->name_len[0] & 1) == 0) {
816 cpnt++;
817 rlen--;
818 }
819
820 if (no_rr)
821 rlen = 0;
822 if (rlen > 0) {
823 (*pnt)->total_rr_attr_size =
824 (*pnt)->rr_attr_size = rlen;
825 (*pnt)->rr_attributes = e_malloc(rlen);
826 memcpy((*pnt)->rr_attributes, cpnt, rlen);
827 seen_rockridge = 1;
828 }
829 #ifdef DEBUG
830 error("INT name: '%s' ist: %d soll: %d\n",
831 (*pnt)->isorec.name, strlen((*pnt)->isorec.name),
832 idr->name_len[0]);
833 #endif
834
835 if (idr->name_len[0] < sizeof ((*pnt)->isorec.name)) {
836 /*
837 * Now zero out the remainder of the name field.
838 */
839 cpnt = (unsigned char *) (*pnt)->isorec.name;
840 cpnt += idr->name_len[0];
841 memset(cpnt, 0,
842 sizeof ((*pnt)->isorec.name) - idr->name_len[0]);
843 } else {
844 /*
845 * Simple sanity work to make sure that we have no
846 * illegal data structures in our tree.
847 */
848 (*pnt)->isorec.name[MAX_ISONAME] = '\0';
849 (*pnt)->isorec.name_len[0] = MAX_ISONAME;
850 }
851 /*
852 * If the filename len from the old session is more
853 * then 31 chars, there is a high risk of hard violations
854 * of the ISO9660 standard.
855 * Run it through our name canonication machine....
856 */
857 if (idr->name_len[0] > LEN_ISONAME || check_oldnames) {
858 iso9660_check(idr, *pnt);
859 }
860
861 if (parse_rr((*pnt)->rr_attributes, rlen, *pnt) == -1) {
862 comerrno(EX_BAD,
863 _("Cannot parse Rock Ridge attributes for '%s'.\n"),
864 idr->name);
865 }
866 if (((*pnt)->isorec.name_len[0] == 1) &&
867 (((*pnt)->isorec.name[0] == 0) || /* "." entry */
868 ((*pnt)->isorec.name[0] == 1))) { /* ".." entry */
869
870 if ((*pnt)->name != NULL) {
871 free((*pnt)->name);
872 }
873 if ((*pnt)->whole_name != NULL) {
874 free((*pnt)->whole_name);
875 }
876 if ((*pnt)->isorec.name[0] == 0) {
877 (*pnt)->name = e_strdup(".");
878 } else {
879 (*pnt)->name = e_strdup("..");
880 }
881 }
882 #ifdef DEBUG
883 fprintf(stderr, "got DE name: %s\n", (*pnt)->name);
884 #endif
885
886 if (strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) {
887 if ((*pnt)->name != NULL) {
888 free((*pnt)->name);
889 }
890 if ((*pnt)->whole_name != NULL) {
891 free((*pnt)->whole_name);
892 }
893 /* (*pnt)->name = e_strdup("<translation table>");*/
894 (*pnt)->name = e_strdup(trans_tbl);
895 tt_extent = get_733(idr->extent);
896 tt_size = get_733(idr->size);
897 if (tt_extent == 0)
898 tt_size = 0;
899 }
900 /*
901 * The beginning of a new multi extent directory chain is when
902 * the last directory had no ISO_MULTIEXTENT flag set and the
903 * current entry did set ISO_MULTIEXTENT.
904 */
905 if ((mx & ISO_MULTIEXTENT) == 0 &&
906 (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
907 struct directory_entry *s_entry;
908 struct iso_directory_record *idr2 = idr;
909 int i2 = i;
910 off_t tsize = 0;
911
912 /*
913 * Sum up the total file size for the multi extent file
914 */
915 while ((i2 + offsetof(struct iso_directory_record, name[0])) < len) {
916 idr2 = (struct iso_directory_record *)&dirbuff[i2];
917 if (idr2->length[0] == 0) {
918 i2 = ISO_ROUND_UP(i2);
919 continue;
920 }
921
922 tsize += get_733(idr2->size);
923 if ((idr2->flags[0] & ISO_MULTIEXTENT) == 0)
924 break;
925 i2 += idr2->length[0];
926 }
927
928 s_entry = dup_directory_entry(*pnt); /* dup first for mxroot */
929 s_entry->de_flags |= MULTI_EXTENT;
930 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
931 s_entry->size = tsize;
932 s_entry->starting_block = (*pnt)->starting_block;
933 s_entry->mxroot = s_entry;
934 s_entry->mxpart = 0;
935 s_entry->next = *pnt; /* Next in list */
936 pnt[1] = pnt[0]; /* Move to next slot */
937 *pnt = s_entry; /* First slot is mxroot */
938 pnt++; /* Point again to cur. */
939 }
940 if ((mx & ISO_MULTIEXTENT) != 0 ||
941 (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
942 (*pnt)->de_flags |= MULTI_EXTENT;
943 (*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
944 (pnt[-1])->next = *pnt;
945 (*pnt)->mxroot = (pnt[-1])->mxroot;
946 (*pnt)->mxpart = (pnt[-1])->mxpart + 1;
947 }
948 pnt++;
949 mx = idr->flags[0];
950 i += idr->length[0];
951 }
952 #ifdef APPLE_HYB
953 /*
954 * If we find an associated file, check if there is a file
955 * with same ISO name and link it to this entry
956 */
957 for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
958 int j;
959
960 rlen = get_711((*pnt)->isorec.name_len);
961 if ((*pnt)->isorec.flags[0] & ISO_ASSOCIATED) {
962 for (j = 0; j < nent; j++) {
963 if (strncmp(rtn[j]->isorec.name,
964 (*pnt)->isorec.name, rlen) == 0 &&
965 (rtn[j]->isorec.flags[0] & ISO_ASSOCIATED) == 0) {
966 rtn[j]->assoc = *pnt;
967
968 /*
969 * don't want this entry to be
970 * in the Joliet tree
971 */
972 (*pnt)->de_flags |= INHIBIT_JOLIET_ENTRY;
973 /*
974 * XXX Is it correct to exclude UDF too?
975 */
976 (*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
977
978 /*
979 * as we have associated files, then
980 * assume we are are dealing with
981 * Apple's extensions - if not already
982 * set
983 */
984 if (apple_both == 0) {
985 apple_both = apple_ext = 1;
986 }
987 break;
988 }
989 }
990 }
991 }
992 #endif /* APPLE_HYB */
993
994 /*
995 * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
996 * to get the filenames of the files. Also, save the table info, just
997 * in case we need to use it.
998 *
999 * The entries look something like: F ISODUMP.;1 isodump
1000 */
1001 if (tt_extent != 0 && tt_size != 0) {
1002 nbytes = roundup(tt_size, SECTOR_SIZE);
1003 tt_buf = (unsigned char *) e_malloc(nbytes);
1004 readsecs(tt_extent, tt_buf, nbytes / SECTOR_SIZE);
1005
1006 /*
1007 * Loop through the file, examine each entry, and attempt to
1008 * attach it to the correct entry.
1009 */
1010 cpnt = tt_buf;
1011 cpnt1 = tt_buf;
1012 while (cpnt - tt_buf < tt_size) {
1013 /* Skip to a line terminator, or end of the file. */
1014 while ((cpnt1 - tt_buf < tt_size) &&
1015 (*cpnt1 != '\n') &&
1016 (*cpnt1 != '\0')) {
1017 cpnt1++;
1018 }
1019 /* Zero terminate this particular line. */
1020 if (cpnt1 - tt_buf < tt_size) {
1021 *cpnt1 = '\0';
1022 }
1023 /*
1024 * Now dig through the actual directories, and try and
1025 * find the attachment for this particular filename.
1026 */
1027 for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
1028 rlen = get_711((*pnt)->isorec.name_len);
1029
1030 /*
1031 * If this filename is so long that it would
1032 * extend past the end of the file, it cannot
1033 * be the one we want.
1034 */
1035 if (cpnt + 2 + rlen - tt_buf >= tt_size) {
1036 continue;
1037 }
1038 /*
1039 * Now actually compare the name, and make sure
1040 * that the character at the end is a ' '.
1041 */
1042 if (strncmp((char *)cpnt + 2,
1043 (*pnt)->isorec.name, rlen) == 0 &&
1044 cpnt[2 + rlen] == ' ' &&
1045 (p = strchr((char *)&cpnt[2 + rlen], '\t'))) {
1046 p++;
1047 /*
1048 * This is a keeper. Now determine the
1049 * correct table entry that we will
1050 * use on the new image.
1051 */
1052 if (strlen(p) > 0) {
1053 (*pnt)->table =
1054 e_malloc(strlen(p) + 4);
1055 sprintf((*pnt)->table,
1056 "%c\t%s\n",
1057 *cpnt, p);
1058 }
1059 if (!(*pnt)->got_rr_name) {
1060 if ((*pnt)->name != NULL) {
1061 free((*pnt)->name);
1062 }
1063 (*pnt)->name = e_strdup(p);
1064 }
1065 break;
1066 }
1067 }
1068 cpnt = cpnt1 + 1;
1069 cpnt1 = cpnt;
1070 }
1071
1072 free(tt_buf);
1073 } else if (!seen_rockridge && !warning_given) {
1074 /*
1075 * Warn the user that iso-9660 names were used because neither
1076 * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were
1077 * found.
1078 */
1079 fprintf(stderr,
1080 _("Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n"));
1081 fprintf(stderr,
1082 _("name translations were found on previous session.\n"));
1083 fprintf(stderr,
1084 _("ISO-9660 file names have been used instead.\n"));
1085 warning_given = 1;
1086 }
1087 if (dirbuff != NULL) {
1088 free(dirbuff);
1089 }
1090 *nentp = nent + nmult;
1091 return (rtn);
1092 } /* read_merging_directory */
1093
1094 /*
1095 * Free any associated data related to the structures.
1096 */
1097 LOCAL int
free_mdinfo(ptr,len)1098 free_mdinfo(ptr, len)
1099 struct directory_entry **ptr;
1100 int len;
1101 {
1102 int i;
1103 struct directory_entry **p;
1104
1105 p = ptr;
1106 for (i = 0; i < len; i++, p++) {
1107 /*
1108 * If the tree-handling code decided that it needed an entry, it
1109 * will have removed it from the list. Thus we must allow for
1110 * null pointers here.
1111 */
1112 if (*p == NULL) {
1113 continue;
1114 }
1115 free_directory_entry(*p);
1116 }
1117
1118 free(ptr);
1119 return (0);
1120 }
1121
1122 LOCAL void
free_directory_entry(dirp)1123 free_directory_entry(dirp)
1124 struct directory_entry *dirp;
1125 {
1126 if (dirp->name != NULL)
1127 free(dirp->name);
1128
1129 if (dirp->whole_name != NULL)
1130 free(dirp->whole_name);
1131
1132 if (dirp->rr_attributes != NULL)
1133 free(dirp->rr_attributes);
1134
1135 if (dirp->table != NULL)
1136 free(dirp->table);
1137
1138 free(dirp);
1139 }
1140
1141 /*
1142 * Search the list to see if we have any entries from the previous
1143 * session that match this entry. If so, copy the extent number
1144 * over so we don't bother to write it out to the new session.
1145 */
1146 int
check_prev_session(ptr,len,curr_entry,statbuf,lstatbuf,odpnt)1147 check_prev_session(ptr, len, curr_entry, statbuf, lstatbuf, odpnt)
1148 struct directory_entry **ptr;
1149 int len;
1150 struct directory_entry *curr_entry;
1151 struct stat *statbuf;
1152 struct stat *lstatbuf;
1153 struct directory_entry **odpnt;
1154 {
1155 int i;
1156 int rr;
1157 int retcode = -2; /* Default not found */
1158
1159 for (i = 0; i < len; i++) {
1160 if (ptr[i] == NULL) { /* Used or empty entry skip */
1161 continue;
1162 }
1163 #if 0
1164 if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1165 ptr[i]->name[0] == '\0') {
1166 continue;
1167 }
1168 if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1169 ptr[i]->name[0] == 1) {
1170 continue;
1171 }
1172 #else
1173 if (ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0) {
1174 continue;
1175 }
1176 if (ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0) {
1177 continue;
1178 }
1179 #endif
1180
1181 if (ptr[i]->name != NULL &&
1182 strcmp(ptr[i]->name, curr_entry->name) != 0) {
1183 /* Not the same name continue */
1184 continue;
1185 }
1186 /*
1187 * It's a directory so we must always merge it with the new
1188 * session. Never ever reuse directory extents. See comments
1189 * in tree.c for an explaination of why this must be the case.
1190 */
1191 if ((curr_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1192 retcode = i;
1193 goto found_it;
1194 }
1195 /*
1196 * We know that the files have the same name. If they also
1197 * have the same file type (i.e. file, dir, block, etc), then
1198 * we can safely reuse the TRANS.TBL entry for this file. The
1199 * check_rr_dates() function will do this for us.
1200 *
1201 * Verify that the file type and dates are consistent. If not,
1202 * we probably have a different file, and we need to write it
1203 * out again.
1204 */
1205 retcode = i;
1206
1207 if (ptr[i]->rr_attributes != NULL) {
1208 if ((rr = check_rr_dates(ptr[i], curr_entry, statbuf,
1209 lstatbuf)) == -1)
1210 return (-1);
1211
1212 if (rr == 0) { /* Different files */
1213 goto found_it;
1214 }
1215 }
1216 /*
1217 * Verify size and timestamp. If rock ridge is in use, we
1218 * need to compare dates from RR too. Directories are special,
1219 * we calculate their size later.
1220 */
1221 if (ptr[i]->size != curr_entry->size) {
1222 /* Different files */
1223 goto found_it;
1224 }
1225 if (memcmp(ptr[i]->isorec.date,
1226 curr_entry->isorec.date, 7) != 0) {
1227 /* Different files */
1228 goto found_it;
1229 }
1230 /* We found it and we can reuse the extent */
1231 memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
1232 curr_entry->starting_block = get_733(ptr[i]->isorec.extent);
1233 curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1234
1235 if ((curr_entry->isorec.flags[0] & ISO_MULTIEXTENT) ||
1236 (ptr[i]->isorec.flags[0] & ISO_MULTIEXTENT)) {
1237 copy_mult_extent(curr_entry, ptr[i]);
1238 }
1239 goto found_it;
1240 }
1241 return (retcode);
1242
1243 found_it:
1244 if (ptr[i]->mxroot == ptr[i]) { /* Remove all multi ext. entries */
1245 int j = i + 1; /* First one will be removed below */
1246
1247 while (j < len && ptr[j] && ptr[j]->mxroot == ptr[i]) {
1248 free(ptr[j]);
1249 ptr[j++] = NULL;
1250 }
1251 }
1252 if (odpnt != NULL) {
1253 *odpnt = ptr[i];
1254 } else {
1255 free(ptr[i]);
1256 }
1257 ptr[i] = NULL;
1258 return (retcode);
1259 }
1260
1261 /*
1262 * Return the number of directory entries for a file. This is usually 1
1263 * but may be 3 or more in case of multi extent files.
1264 */
1265 LOCAL int
iso_dir_ents(de)1266 iso_dir_ents(de)
1267 struct directory_entry *de;
1268 {
1269 struct directory_entry *de2;
1270 int ret = 0;
1271
1272 if (de->mxroot == NULL)
1273 return (1);
1274 de2 = de;
1275 while (de2 != NULL && de2->mxroot == de->mxroot) {
1276 ret++;
1277 de2 = de2->next;
1278 }
1279 return (ret);
1280 }
1281
1282 /*
1283 * Copy old multi-extent directory information from the previous session.
1284 * If both the old session and the current session are created by mkisofs
1285 * then this code could be extremely simple as the information is only copied
1286 * in case that the file did not change since the last session was made.
1287 * As we don't know the other ISO formatter program, any combination of
1288 * multi-extent files and even a single extent file could be possible.
1289 * We need to handle all files the same way ad the old session was created as
1290 * we reuse the data extents from the file in the old session.
1291 */
1292 LOCAL void
copy_mult_extent(se1,se2)1293 copy_mult_extent(se1, se2)
1294 struct directory_entry *se1;
1295 struct directory_entry *se2;
1296 {
1297 struct directory_entry *curr_entry = se1;
1298 int len1;
1299 int len2;
1300 int mxpart = 0;
1301
1302 len1 = iso_dir_ents(se1);
1303 len2 = iso_dir_ents(se2);
1304
1305 if (len1 == 1) {
1306 /*
1307 * Convert single-extent to multi-extent.
1308 * If *se1 is not multi-extent, *se2 definitely is
1309 * and we need to set up a MULTI_EXTENT directory header.
1310 */
1311 se1->de_flags |= MULTI_EXTENT;
1312 se1->isorec.flags[0] |= ISO_MULTIEXTENT;
1313 se1->mxroot = curr_entry;
1314 se1->mxpart = 0;
1315 se1 = dup_directory_entry(se1);
1316 curr_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
1317 se1->de_flags |= INHIBIT_UDF_ENTRY;
1318 se1->next = curr_entry->next;
1319 curr_entry->next = se1;
1320 se1 = curr_entry;
1321 len1 = 2;
1322 }
1323
1324 while (se2->isorec.flags[0] & ISO_MULTIEXTENT) {
1325 len1--;
1326 len2--;
1327 if (len1 <= 0) {
1328 struct directory_entry *sex = dup_directory_entry(se1);
1329
1330 sex->mxroot = curr_entry;
1331 sex->next = se1->next;
1332 se1->next = sex;
1333 len1++;
1334 }
1335 memcpy(se1->isorec.extent, se2->isorec.extent, 8);
1336 se1->starting_block = get_733(se2->isorec.extent);
1337 se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1338 se1->de_flags |= MULTI_EXTENT;
1339 se1->isorec.flags[0] |= ISO_MULTIEXTENT;
1340 se1->mxroot = curr_entry;
1341 se1->mxpart = mxpart++;
1342
1343 se1 = se1->next;
1344 se2 = se2->next;
1345 }
1346 memcpy(se1->isorec.extent, se2->isorec.extent, 8);
1347 se1->starting_block = get_733(se2->isorec.extent);
1348 se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1349 se1->isorec.flags[0] &= ~ISO_MULTIEXTENT; /* Last entry */
1350 se1->mxpart = mxpart;
1351 while (len1 > 1) { /* Drop other entries */
1352 struct directory_entry *sex;
1353
1354 sex = se1->next;
1355 se1->next = sex->next;
1356 free(sex);
1357 len1--;
1358 }
1359 }
1360
1361 /*
1362 * open_merge_image: Open an existing image.
1363 */
1364 int
open_merge_image(path)1365 open_merge_image(path)
1366 char *path;
1367 {
1368 #ifndef USE_SCG
1369 in_image = fopen(path, "rb");
1370 if (in_image == NULL) {
1371 return (-1);
1372 }
1373 #else
1374 in_image = fopen(path, "rb");
1375 if (in_image == NULL) {
1376 if (scsidev_open(path) < 0)
1377 return (-1);
1378 }
1379 #endif
1380 return (0);
1381 }
1382
1383 /*
1384 * close_merge_image: Close an existing image.
1385 */
1386 int
close_merge_image()1387 close_merge_image()
1388 {
1389 #ifdef USE_SCG
1390 return (scsidev_close());
1391 #else
1392 return (fclose(in_image));
1393 #endif
1394 }
1395
1396 /*
1397 * merge_isofs: Scan an existing image, and return a pointer
1398 * to the root directory for this image.
1399 */
1400 struct iso_directory_record *
merge_isofs(path)1401 merge_isofs(path)
1402 char *path;
1403 {
1404 char buffer[SECTOR_SIZE];
1405 int file_addr;
1406 int i;
1407 int sum = 0;
1408 char *p = buffer;
1409 struct iso_primary_descriptor *pri = NULL;
1410 struct iso_directory_record *rootp;
1411 struct iso_volume_descriptor *vdp;
1412
1413 /*
1414 * Start by searching for the volume header. Ultimately, we need to
1415 * search for volume headers in multiple places because we might be
1416 * starting with a multisession image. FIXME(eric).
1417 */
1418 get_session_start(&file_addr);
1419
1420 for (i = 0; i < 100; i++) {
1421 if (readsecs(file_addr, buffer,
1422 sizeof (buffer) / SECTOR_SIZE) != sizeof (buffer)) {
1423 comerr(_("Read error on old image %s\n"), path);
1424 }
1425 vdp = (struct iso_volume_descriptor *)buffer;
1426
1427 if ((strncmp(vdp->id, ISO_STANDARD_ID, sizeof (vdp->id)) == 0) &&
1428 (get_711(vdp->type) == ISO_VD_PRIMARY)) {
1429 break;
1430 }
1431 file_addr += 1;
1432 }
1433
1434 if (i == 100) {
1435 return (NULL);
1436 }
1437 for (i = 0; i < 2048-3; i++) {
1438 sum += p[i] & 0xFF;
1439 }
1440 pri = (struct iso_primary_descriptor *)vdp;
1441
1442 /* Check the blocksize of the image to make sure it is compatible. */
1443 if (get_723(pri->logical_block_size) != SECTOR_SIZE) {
1444 errmsgno(EX_BAD,
1445 _("Previous session has incompatible sector size %u.\n"),
1446 get_723(pri->logical_block_size));
1447 return (NULL);
1448 }
1449 if (get_723(pri->volume_set_size) != 1) {
1450 errmsgno(EX_BAD,
1451 _("Previous session has volume set size %u (must be 1).\n"),
1452 get_723(pri->volume_set_size));
1453 return (NULL);
1454 }
1455 /* Get the location and size of the root directory. */
1456 rootp = (struct iso_directory_record *)
1457 e_malloc(sizeof (struct iso_directory_record));
1458
1459 memcpy(rootp, pri->root_directory_record,
1460 sizeof (pri->root_directory_record));
1461
1462 for (i = 0; i < 100; i++) {
1463 if (readsecs(file_addr, buffer,
1464 sizeof (buffer) / SECTOR_SIZE) != sizeof (buffer)) {
1465 comerr(_("Read error on old image %s\n"), path);
1466 }
1467 if (strncmp(buffer, "MKI ", 4) == 0) {
1468 int sum2;
1469
1470 sum2 = p[2045] & 0xFF;
1471 sum2 *= 256;
1472 sum2 += p[2046] & 0xFF;
1473 sum2 *= 256;
1474 sum2 += p[2047] & 0xFF;
1475 if (sum == sum2) {
1476 error(_("ISO-9660 image includes checksum signature for correct inode numbers.\n"));
1477 } else {
1478 correct_inodes = FALSE;
1479 rrip112 = FALSE;
1480 }
1481 break;
1482 }
1483 file_addr += 1;
1484 }
1485
1486 return (rootp);
1487 }
1488
1489 LOCAL void
merge_remaining_entries(this_dir,pnt,n_orig)1490 merge_remaining_entries(this_dir, pnt, n_orig)
1491 struct directory *this_dir;
1492 struct directory_entry **pnt;
1493 int n_orig;
1494 {
1495 int i;
1496 struct directory_entry *s_entry;
1497 UInt32_t ttbl_extent = 0;
1498 unsigned int ttbl_index = 0;
1499 char whole_path[PATH_MAX];
1500
1501 /*
1502 * Whatever is leftover in the list needs to get merged back into the
1503 * directory.
1504 */
1505 for (i = 0; i < n_orig; i++) {
1506 if (pnt[i] == NULL) {
1507 continue;
1508 }
1509 if (pnt[i]->name != NULL && pnt[i]->whole_name == NULL) {
1510 /* Set the name for this directory. */
1511 strlcpy(whole_path, this_dir->de_name,
1512 sizeof (whole_path));
1513 strcat(whole_path, SPATH_SEPARATOR);
1514 strcat(whole_path, pnt[i]->name);
1515
1516 pnt[i]->whole_name = e_strdup(whole_path);
1517 }
1518 if (pnt[i]->name != NULL &&
1519 /* strcmp(pnt[i]->name, "<translation table>") == 0 )*/
1520 strcmp(pnt[i]->name, trans_tbl) == 0) {
1521 ttbl_extent =
1522 get_733(pnt[i]->isorec.extent);
1523 ttbl_index = i;
1524 continue;
1525 }
1526
1527 /*
1528 * Skip directories for now - these need to be treated
1529 * differently.
1530 */
1531 if ((pnt[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1532 /*
1533 * FIXME - we need to insert this directory into the
1534 * tree, so that the path tables we generate will be
1535 * correct.
1536 */
1537 if ((strcmp(pnt[i]->name, ".") == 0) ||
1538 (strcmp(pnt[i]->name, "..") == 0)) {
1539 free_directory_entry(pnt[i]);
1540 pnt[i] = NULL;
1541 continue;
1542 } else {
1543 merge_old_directory_into_tree(pnt[i], this_dir);
1544 }
1545 }
1546 pnt[i]->next = this_dir->contents;
1547 pnt[i]->filedir = this_dir;
1548 this_dir->contents = pnt[i];
1549 pnt[i] = NULL;
1550 }
1551
1552
1553 /*
1554 * If we don't have an entry for the translation table, then don't
1555 * bother trying to copy the starting extent over. Note that it is
1556 * possible that if we are copying the entire directory, the entry for
1557 * the translation table will have already been inserted into the
1558 * linked list and removed from the old entries list, in which case we
1559 * want to leave the extent number as it was before.
1560 */
1561 if (ttbl_extent == 0) {
1562 return;
1563 }
1564 /*
1565 * Finally, check the directory we are creating to see whether there
1566 * are any new entries in it. If there are not, we can reuse the same
1567 * translation table.
1568 */
1569 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1570 /*
1571 * Don't care about '.' or '..'. They are never in the table
1572 * anyways.
1573 */
1574 if (s_entry->name != NULL && strcmp(s_entry->name, ".") == 0) {
1575 continue;
1576 }
1577 if (s_entry->name != NULL && strcmp(s_entry->name, "..") == 0) {
1578 continue;
1579 }
1580 /* if (s_entry->name != NULL &&*/
1581 /* strcmp(s_entry->name, "<translation table>") == 0)*/
1582 if (s_entry->name != NULL &&
1583 strcmp(s_entry->name, trans_tbl) == 0) {
1584 continue;
1585 }
1586 if ((s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0) {
1587 return;
1588 }
1589 }
1590
1591 /*
1592 * Locate the translation table, and re-use the same extent. It isn't
1593 * clear that there should ever be one in there already so for now we
1594 * try and muddle through the best we can.
1595 */
1596 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1597 /* if (strcmp(s_entry->name, "<translation table>") == 0)*/
1598 if (strcmp(s_entry->name, trans_tbl) == 0) {
1599 fprintf(stderr, "Should never get here\n");
1600 set_733(s_entry->isorec.extent, ttbl_extent);
1601 return;
1602 }
1603 }
1604
1605 pnt[ttbl_index]->next = this_dir->contents;
1606 pnt[ttbl_index]->filedir = this_dir;
1607 this_dir->contents = pnt[ttbl_index];
1608 pnt[ttbl_index] = NULL;
1609 }
1610
1611
1612 /*
1613 * Here we have a case of a directory that has completely disappeared from
1614 * the face of the earth on the tree we are mastering from. Go through and
1615 * merge it into the tree, as well as everything beneath it.
1616 *
1617 * Note that if a directory has been moved for some reason, this will
1618 * incorrectly pick it up and attempt to merge it back into the old
1619 * location. FIXME(eric).
1620 */
1621 LOCAL int
merge_old_directory_into_tree(dpnt,parent)1622 merge_old_directory_into_tree(dpnt, parent)
1623 struct directory_entry *dpnt;
1624 struct directory *parent;
1625 {
1626 struct directory_entry **contents = NULL;
1627 int i;
1628 int n_orig;
1629 struct directory *this_dir,
1630 *next_brother;
1631 char whole_path[PATH_MAX];
1632
1633 this_dir = (struct directory *)e_malloc(sizeof (struct directory));
1634 memset(this_dir, 0, sizeof (struct directory));
1635 this_dir->next = NULL;
1636 this_dir->subdir = NULL;
1637 this_dir->self = dpnt;
1638 this_dir->contents = NULL;
1639 this_dir->size = 0;
1640 this_dir->extent = 0;
1641 this_dir->depth = parent->depth + 1;
1642 this_dir->parent = parent;
1643 if (!parent->subdir)
1644 parent->subdir = this_dir;
1645 else {
1646 next_brother = parent->subdir;
1647 while (next_brother->next)
1648 next_brother = next_brother->next;
1649 next_brother->next = this_dir;
1650 }
1651
1652 /* Set the name for this directory. */
1653 if (strlcpy(whole_path, parent->de_name, sizeof (whole_path)) >= sizeof (whole_path) ||
1654 strlcat(whole_path, SPATH_SEPARATOR, sizeof (whole_path)) >= sizeof (whole_path) ||
1655 strlcat(whole_path, dpnt->name, sizeof (whole_path)) >= sizeof (whole_path))
1656 comerrno(EX_BAD, _("Path name '%s%s%s' exceeds max length %zd\n"),
1657 parent->de_name,
1658 SPATH_SEPARATOR,
1659 dpnt->name,
1660 sizeof (whole_path));
1661 this_dir->de_name = e_strdup(whole_path);
1662 this_dir->whole_name = e_strdup(whole_path);
1663
1664 /*
1665 * Now fill this directory using information from the previous session.
1666 */
1667 contents = read_merging_directory(&dpnt->isorec, &n_orig);
1668 /*
1669 * Start by simply copying the '.', '..' and non-directory entries to
1670 * this directory. Technically we could let merge_remaining_entries
1671 * handle this, but it gets rather confused by the '.' and '..' entries
1672 */
1673 for (i = 0; i < n_orig; i++) {
1674 /*
1675 * We can always reuse the TRANS.TBL in this particular case.
1676 */
1677 contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1678
1679 if (((contents[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) &&
1680 (i >= 2)) {
1681 continue;
1682 }
1683 /* If we have a directory, don't reuse the extent number. */
1684 if ((contents[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1685 memset(contents[i]->isorec.extent, 0, 8);
1686
1687 if (strcmp(contents[i]->name, ".") == 0)
1688 this_dir->dir_flags |= DIR_HAS_DOT;
1689
1690 if (strcmp(contents[i]->name, "..") == 0)
1691 this_dir->dir_flags |= DIR_HAS_DOTDOT;
1692 }
1693 /*
1694 * for regilar files, we do it here.
1695 * If it has CL or RE attributes, remember its extent
1696 */
1697 check_rr_relocation(contents[i]);
1698
1699 /*
1700 * Set the whole name for this file.
1701 */
1702 if (strlcpy(whole_path, this_dir->whole_name, sizeof (whole_path)) >= sizeof (whole_path) ||
1703 strlcat(whole_path, SPATH_SEPARATOR, sizeof (whole_path)) >= sizeof (whole_path) ||
1704 strlcat(whole_path, contents[i]->name, sizeof (whole_path)) >= sizeof (whole_path))
1705 comerrno(EX_BAD, _("Path name '%s%s%s' exceeds max length %zd\n"),
1706 this_dir->whole_name,
1707 SPATH_SEPARATOR,
1708 contents[i]->name,
1709 sizeof (whole_path));
1710
1711 contents[i]->whole_name = e_strdup(whole_path);
1712
1713 contents[i]->next = this_dir->contents;
1714 contents[i]->filedir = this_dir;
1715 this_dir->contents = contents[i];
1716 contents[i] = NULL;
1717 }
1718
1719 /*
1720 * and for directories, we do it here.
1721 * If it has CL or RE attributes, remember its extent
1722 */
1723 check_rr_relocation(dpnt);
1724
1725 /*
1726 * Zero the extent number for ourselves.
1727 */
1728 memset(dpnt->isorec.extent, 0, 8);
1729
1730 /*
1731 * Anything that is left are other subdirectories that need to be
1732 * merged.
1733 */
1734 merge_remaining_entries(this_dir, contents, n_orig);
1735 free_mdinfo(contents, n_orig);
1736 #if 0
1737 /*
1738 * This is no longer required. The post-scan sort will handle all of
1739 * this for us.
1740 */
1741 sort_n_finish(this_dir);
1742 #endif
1743
1744 return (0);
1745 }
1746
1747
1748 char *cdrecord_data = NULL;
1749
1750 int
get_session_start(file_addr)1751 get_session_start(file_addr)
1752 int *file_addr;
1753 {
1754 char *pnt;
1755
1756 #ifdef CDRECORD_DETERMINES_FIRST_WRITABLE_ADDRESS
1757 /*
1758 * FIXME(eric). We need to coordinate with cdrecord to obtain the
1759 * parameters. For now, we assume we are writing the 2nd session, so
1760 * we start from the session that starts at 0.
1761 */
1762 if (file_addr != NULL)
1763 *file_addr = 16;
1764
1765 /*
1766 * We need to coordinate with cdrecord to get the next writable address
1767 * from the device. Here is where we use it.
1768 */
1769 session_start = last_extent = last_extent_written = cdrecord_result();
1770 #else
1771
1772 if (file_addr != NULL)
1773 *file_addr = 0L;
1774 session_start = last_extent = last_extent_written = 0L;
1775 if (check_session && cdrecord_data == NULL)
1776 return (0);
1777
1778 if (cdrecord_data == NULL) {
1779 comerrno(EX_BAD,
1780 _("Special parameters for cdrecord not specified with -C\n"));
1781 }
1782 /*
1783 * Next try and find the ',' in there which delimits the two numbers.
1784 */
1785 pnt = strchr(cdrecord_data, ',');
1786 if (pnt == NULL) {
1787 comerrno(EX_BAD, _("Malformed cdrecord parameters\n"));
1788 }
1789
1790 *pnt = '\0';
1791 if (file_addr != NULL) {
1792 *file_addr = atol(cdrecord_data);
1793 }
1794 pnt++;
1795
1796 session_start = last_extent = last_extent_written = atol(pnt);
1797
1798 pnt--;
1799 *pnt = ',';
1800
1801 #endif
1802 return (0);
1803 }
1804
1805 /*
1806 * This function scans the directory tree, looking for files, and it makes
1807 * note of everything that is found. We also begin to construct the ISO9660
1808 * directory entries, so that we can determine how large each directory is.
1809 */
1810 int
merge_previous_session(this_dir,mrootp,reloc_root,reloc_old_root)1811 merge_previous_session(this_dir, mrootp, reloc_root, reloc_old_root)
1812 struct directory *this_dir;
1813 struct iso_directory_record *mrootp;
1814 char *reloc_root;
1815 char *reloc_old_root;
1816 {
1817 struct directory_entry **orig_contents = NULL;
1818 struct directory_entry *odpnt = NULL;
1819 int n_orig;
1820 struct directory_entry *s_entry;
1821 int status;
1822 int lstatus;
1823 struct stat statbuf,
1824 lstatbuf;
1825 int retcode;
1826
1827 /* skip leading slash */
1828 while (reloc_old_root && reloc_old_root[0] == PATH_SEPARATOR) {
1829 reloc_old_root++;
1830 }
1831 while (reloc_root && reloc_root[0] == PATH_SEPARATOR) {
1832 reloc_root++;
1833 }
1834
1835 /*
1836 * Parse the same directory in the image that we are merging for
1837 * multisession stuff.
1838 */
1839 orig_contents = read_merging_directory(mrootp, &n_orig);
1840 if (orig_contents == NULL) {
1841 if (reloc_old_root) {
1842 comerrno(EX_BAD,
1843 _("Reading old session failed, cannot execute -old-root.\n"));
1844 }
1845 return (0);
1846 }
1847
1848 if (reloc_old_root && reloc_old_root[0]) {
1849 struct directory_entry **new_orig_contents = orig_contents;
1850 int new_n_orig = n_orig;
1851
1852 /* decend until we reach the original root */
1853 while (reloc_old_root[0]) {
1854 int i;
1855 char *next;
1856 int last;
1857
1858 for (next = reloc_old_root; *next && *next != PATH_SEPARATOR; next++);
1859 if (*next) {
1860 last = 0;
1861 *next = 0;
1862 next++;
1863 } else {
1864 last = 1;
1865 }
1866 while (*next == PATH_SEPARATOR) {
1867 next++;
1868 }
1869
1870 for (i = 0; i < new_n_orig; i++) {
1871 struct iso_directory_record subroot;
1872
1873 if (new_orig_contents[i]->name != NULL &&
1874 strcmp(new_orig_contents[i]->name, reloc_old_root) != 0) {
1875 /* Not the same name continue */
1876 continue;
1877 }
1878 /*
1879 * enter directory, free old one only if not the top level,
1880 * which is still needed
1881 */
1882 subroot = new_orig_contents[i]->isorec;
1883 if (new_orig_contents != orig_contents) {
1884 free_mdinfo(new_orig_contents, new_n_orig);
1885 }
1886 new_orig_contents = read_merging_directory(&subroot, &new_n_orig);
1887
1888 if (!new_orig_contents) {
1889 comerrno(EX_BAD,
1890 _("Reading directory %s in old session failed, cannot execute -old-root.\n"),
1891 reloc_old_root);
1892 }
1893 i = -1;
1894 break;
1895 }
1896
1897 if (i == new_n_orig) {
1898 comerrno(EX_BAD,
1899 _("-old-root (sub)directory %s not found in old session.\n"),
1900 reloc_old_root);
1901 }
1902
1903 /* restore string, proceed to next sub directory */
1904 if (!last) {
1905 reloc_old_root[strlen(reloc_old_root)] = PATH_SEPARATOR;
1906 }
1907 reloc_old_root = next;
1908 }
1909
1910 /*
1911 * preserve the old session, skipping those dirs/files that are found again
1912 * in the new root
1913 */
1914 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1915 status = stat_filter(s_entry->whole_name, &statbuf);
1916 lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
1917
1918 /*
1919 * check_prev_session() will search for s_entry and remove it from
1920 * orig_contents if found
1921 */
1922 retcode = check_prev_session(orig_contents, n_orig, s_entry,
1923 &statbuf, &lstatbuf, NULL);
1924 if (retcode == -1)
1925 return (-1);
1926 /*
1927 * Skip other directory entries for multi-extent files
1928 */
1929 if (s_entry->de_flags & MULTI_EXTENT) {
1930 struct directory_entry *s_e;
1931
1932 for (s_e = s_entry->mxroot;
1933 s_e && s_e->mxroot == s_entry->mxroot;
1934 s_e = s_e->next) {
1935 s_entry = s_e;
1936 ;
1937 }
1938 }
1939 }
1940 merge_remaining_entries(this_dir, orig_contents, n_orig);
1941
1942 /* use new directory */
1943 free_mdinfo(orig_contents, n_orig);
1944 orig_contents = new_orig_contents;
1945 n_orig = new_n_orig;
1946
1947 if (reloc_root && reloc_root[0]) {
1948 /* also decend into new root before searching for files */
1949 this_dir = find_or_create_directory(this_dir, reloc_root, NULL, TRUE);
1950 if (!this_dir) {
1951 return (-1);
1952 }
1953 }
1954 }
1955
1956
1957 /*
1958 * Now we scan the directory itself, and look at what is inside of it.
1959 */
1960 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1961 status = stat_filter(s_entry->whole_name, &statbuf);
1962 lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
1963
1964 /*
1965 * We always should create an entirely new directory tree
1966 * whenever we generate a new session, unless there were
1967 * *no* changes whatsoever to any of the directories, in which
1968 * case it would be kind of pointless to generate a new
1969 * session.
1970 * I believe it is possible to rigorously prove that any change
1971 * anywhere in the filesystem will force the entire tree to be
1972 * regenerated because the modified directory will get a new
1973 * extent number. Since each subdirectory of the changed
1974 * directory has a '..' entry, all of them will need to be
1975 * rewritten too, and since the parent directory of the
1976 * modified directory will have an extent pointer to the
1977 * directory it too will need to be rewritten. Thus we will
1978 * never be able to reuse any directory information when
1979 * writing new sessions.
1980 *
1981 * We still check the previous session so we can mark off the
1982 * equivalent entry in the list we got from the original disc,
1983 * however.
1984 */
1985
1986 /*
1987 * The check_prev_session function looks for an identical
1988 * entry in the previous session. If we see it, then we copy
1989 * the extent number to s_entry, and cross it off the list.
1990 */
1991 retcode = check_prev_session(orig_contents, n_orig, s_entry,
1992 &statbuf, &lstatbuf, &odpnt);
1993 if (retcode == -1)
1994 return (-1);
1995
1996 if (odpnt != NULL &&
1997 (s_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1998 int dflag;
1999
2000 if (strcmp(s_entry->name, ".") != 0 &&
2001 strcmp(s_entry->name, "..") != 0) {
2002 struct directory *child;
2003
2004 /*
2005 * XXX It seems that the tree that has been
2006 * XXX read from the previous session does not
2007 * XXX carry whole_name entries. We provide a
2008 * XXX hack in
2009 * XXX multi.c:find_or_create_directory()
2010 * XXX that should be removed when a
2011 * XXX reasonable method could be found.
2012 */
2013 child = find_or_create_directory(this_dir,
2014 s_entry->whole_name,
2015 s_entry, 1);
2016 dflag = merge_previous_session(child,
2017 &odpnt->isorec,
2018 NULL, reloc_old_root);
2019 if (dflag == -1) {
2020 return (-1);
2021 }
2022 free(odpnt);
2023 odpnt = NULL;
2024 }
2025 }
2026 if (odpnt) {
2027 free(odpnt);
2028 odpnt = NULL;
2029 }
2030 /*
2031 * Skip other directory entries for multi-extent files
2032 */
2033 if (s_entry->de_flags & MULTI_EXTENT) {
2034 struct directory_entry *s_e;
2035
2036 for (s_e = s_entry->mxroot;
2037 s_e && s_e->mxroot == s_entry->mxroot;
2038 s_e = s_e->next) {
2039 s_entry = s_e;
2040 ;
2041 }
2042 }
2043 }
2044
2045 if (!reloc_old_root) {
2046 /*
2047 * Whatever is left over, are things which are no longer in the tree on
2048 * disk. We need to also merge these into the tree.
2049 */
2050 merge_remaining_entries(this_dir, orig_contents, n_orig);
2051 }
2052 free_mdinfo(orig_contents, n_orig);
2053 return (1);
2054 }
2055
2056 /*
2057 * This code deals with relocated directories which may exist
2058 * in the previous session.
2059 */
2060 struct dir_extent_link {
2061 unsigned int extent;
2062 struct directory_entry *de;
2063 struct dir_extent_link *next;
2064 };
2065
2066 static struct dir_extent_link *cl_dirs = NULL;
2067 static struct dir_extent_link *re_dirs = NULL;
2068
2069 LOCAL void
check_rr_relocation(de)2070 check_rr_relocation(de)
2071 struct directory_entry *de;
2072 {
2073 unsigned char sector[SECTOR_SIZE];
2074 unsigned char *pnt = de->rr_attributes;
2075 int len = de->rr_attr_size;
2076 UInt32_t cont_extent = 0,
2077 cont_offset = 0,
2078 cont_size = 0;
2079
2080 pnt = parse_xa(pnt, &len, /* dpnt */ 0);
2081 while (len >= 4) {
2082 if (pnt[3] != 1 && pnt[3] != 2) {
2083 errmsgno(EX_BAD,
2084 _("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
2085 pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
2086 }
2087 if (pnt[2] < 4) {
2088 errmsgno(EX_BAD,
2089 _("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
2090 pnt[2], pnt, pnt[0], pnt[1]);
2091 break;
2092 }
2093 if (strncmp((char *)pnt, "CL", 2) == 0) {
2094 struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
2095
2096 dlink->extent = get_733(pnt + 4);
2097 dlink->de = de;
2098 dlink->next = cl_dirs;
2099 cl_dirs = dlink;
2100
2101 } else if (strncmp((char *)pnt, "RE", 2) == 0) {
2102 struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
2103
2104 dlink->extent = de->starting_block;
2105 dlink->de = de;
2106 dlink->next = re_dirs;
2107 re_dirs = dlink;
2108
2109 } else if (strncmp((char *)pnt, "CE", 2) == 0) {
2110 cont_extent = get_733(pnt + 4);
2111 cont_offset = get_733(pnt + 12);
2112 cont_size = get_733(pnt + 20);
2113
2114 } else if (strncmp((char *)pnt, "ST", 2) == 0) {
2115 len = pnt[2];
2116 }
2117 len -= pnt[2];
2118 pnt += pnt[2];
2119 if (len <= 3 && cont_extent) {
2120 /* ??? What if cont_offset+cont_size > SECTOR_SIZE */
2121 readsecs(cont_extent, sector, 1);
2122 pnt = sector + cont_offset;
2123 len = cont_size;
2124 cont_extent = cont_offset = cont_size = 0;
2125 }
2126 }
2127
2128 }
2129
2130 void
match_cl_re_entries()2131 match_cl_re_entries()
2132 {
2133 struct dir_extent_link *re = re_dirs;
2134
2135 /* for each relocated directory */
2136 for (; re; re = re->next) {
2137 struct dir_extent_link *cl = cl_dirs;
2138
2139 for (; cl; cl = cl->next) {
2140 /* find a place where it was relocated from */
2141 if (cl->extent == re->extent) {
2142 /* set link to that place */
2143 re->de->parent_rec = cl->de;
2144 re->de->filedir = cl->de->filedir;
2145
2146 /*
2147 * see if it is in rr_moved
2148 */
2149 if (reloc_dir != NULL) {
2150 struct directory_entry *rr_moved_e = reloc_dir->contents;
2151
2152 for (; rr_moved_e; rr_moved_e = rr_moved_e->next) {
2153 /* yes it is */
2154 if (re->de == rr_moved_e) {
2155 /* forget it */
2156 re->de = NULL;
2157 }
2158 }
2159 }
2160 break;
2161 }
2162 }
2163 }
2164 }
2165
2166 void
finish_cl_pl_for_prev_session()2167 finish_cl_pl_for_prev_session()
2168 {
2169 struct dir_extent_link *re = re_dirs;
2170
2171 /* for those that were relocated, but NOT to rr_moved */
2172 re = re_dirs;
2173 for (; re; re = re->next) {
2174 if (re->de != NULL) {
2175 /*
2176 * here we have hypothetical case when previous session
2177 * was not created by mkisofs and contains relocations
2178 */
2179 struct directory_entry *s_entry = re->de;
2180 struct directory_entry *s_entry1;
2181 struct directory *d_entry = reloc_dir->subdir;
2182
2183 /* do the same as finish_cl_pl_entries */
2184 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
2185 continue;
2186 }
2187 while (d_entry) {
2188 if (d_entry->self == s_entry)
2189 break;
2190 d_entry = d_entry->next;
2191 }
2192 if (!d_entry) {
2193 comerrno(EX_BAD, _("Unable to locate directory parent\n"));
2194 }
2195
2196 if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
2197 char *rr_attr;
2198
2199 /*
2200 * First fix the PL pointer in the directory in the
2201 * rr_reloc dir
2202 */
2203 s_entry1 = d_entry->contents->next;
2204 rr_attr = find_rr_attribute(s_entry1->rr_attributes,
2205 s_entry1->total_rr_attr_size, "PL");
2206 if (rr_attr != NULL)
2207 set_733(rr_attr + 4, s_entry->filedir->extent);
2208
2209 /* Now fix the CL pointer */
2210 s_entry1 = s_entry->parent_rec;
2211
2212 rr_attr = find_rr_attribute(s_entry1->rr_attributes,
2213 s_entry1->total_rr_attr_size, "CL");
2214 if (rr_attr != NULL)
2215 set_733(rr_attr + 4, d_entry->extent);
2216 }
2217 }
2218 }
2219 /* free memory */
2220 re = re_dirs;
2221 while (re) {
2222 struct dir_extent_link *next = re->next;
2223
2224 free(re);
2225 re = next;
2226 }
2227 re = cl_dirs;
2228 while (re) {
2229 struct dir_extent_link *next = re->next;
2230
2231 free(re);
2232 re = next;
2233 }
2234 }
2235