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