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