2 * This file has been modified for the cdrkit suite.
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).
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.
13 /* @(#)multi.c 1.68 05/05/15 joerg */
14 /* Parts from @(#)multi.c 1.88 08/08/28 joerg */
16 * File multi.c - scan existing iso9660 image and merge into
17 * iso9660 filesystem. Used for multisession support.
19 * Written by Eric Youngdale (1996).
20 * Copyright (c) 1999-2003 J. Schilling
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)
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.
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.
38 #include "genisoimage.h"
43 #include <ctype.h> /* Needed for printasc() */
48 #include <vms/fabdef.h>
53 #define howmany(x, y) (((x)+((y)-1))/(y))
56 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
60 * Cannot debug memset() with gdb on Linux, so use fillbytes()
62 /*#define memset(s, c, n) fillbytes(s, n, c)*/
67 #define TF_ATTRIBUTES 8
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);
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,
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,
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));
98 static int merge_old_directory_into_tree(struct directory_entry *,
100 static void check_rr_relocation(struct directory_entry *de);
103 isonum_711(unsigned char *p)
109 isonum_721(unsigned char *p)
111 return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
115 isonum_723(unsigned char *p)
118 if (p[0] != p[3] || p[1] != p[2]) {
120 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
122 fprintf(stderr, "invalid format 7.2.3 number\n");
127 return (isonum_721(p));
131 isonum_731(unsigned char *p)
133 return ((p[0] & 0xff)
134 | ((p[1] & 0xff) << 8)
135 | ((p[2] & 0xff) << 16)
136 | ((p[3] & 0xff) << 24));
140 isonum_733(unsigned char *p)
142 return (isonum_731(p));
145 FILE *in_image = NULL;
149 * Don't define readsecs if genisoimage is linked with
151 * readsecs() will be implemented as SCSI command in this case.
153 * Use global var in_image directly in readsecs()
154 * the SCSI equivalent will not use a FILE* for I/O.
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
163 readsecs(int startsecno, void *buffer, int sectorcount)
165 int f = fileno(in_image);
167 if (lseek(f, (off_t) startsecno * SECTOR_SIZE, SEEK_SET) == (off_t) - 1) {
169 comerr(" Seek error on old image\n");
171 fprintf(stderr, " Seek error on old image\n");
175 if (read(f, buffer, (sectorcount * SECTOR_SIZE))
176 != (sectorcount * SECTOR_SIZE)) {
178 comerr(" Read error on old image\n");
180 fprintf(stderr, " Read error on old image\n");
184 return (sectorcount * SECTOR_SIZE);
190 printasc(char *txt, unsigned char *p, int len)
194 fprintf(stderr, "%s ", txt);
195 for (i = 0; i < len; i++) {
197 fprintf(stderr, "%c", p[i]);
199 fprintf(stderr, ".");
201 fprintf(stderr, "\n");
205 prbytes(char *txt, register Uchar *p, register int len)
207 fprintf(stderr, "%s", txt);
209 fprintf(stderr, " %02X", *p++);
210 fprintf(stderr, "\n");
214 parse_xa(unsigned char *pnt, int *lenp, struct directory_entry *dpnt)
216 struct iso_xa_dir_record *xadp;
218 static int did_xa = 0;
220 /*fprintf(stderr, "len: %d\n", len);*/
223 xadp = (struct iso_xa_dir_record *)pnt;
225 /* if (dpnt) prbytes("XA ", pnt, len);*/
226 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
227 xadp->reserved[0] == '\0') {
233 errmsgno(EX_BAD, "Found XA directory extension record.\n");
235 } else if (pnt[2] == 0) {
239 cp = (char *)&dpnt->isorec;
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);
247 errmsgno(EX_BAD, "Disabling RR / XA / AA.\n");
252 errmsgno(EX_BAD, "Problems with old ISO directory entry for file: '%s'.\n", &cp[33]);
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");
259 if (len >= 4 && pnt[3] != 1 && pnt[3] != 2) {
260 prbytes("BAD RR ATTRIBUTES:", pnt, len);
261 printasc("BAD RR ATTRIBUTES:", pnt, len);
267 find_rr(struct iso_directory_record *idr, Uchar **pntp, int *lenp)
269 struct iso_xa_dir_record *xadp;
274 len = idr->length[0] & 0xff;
275 len -= sizeof (struct iso_directory_record);
276 len += sizeof (idr->name);
277 len -= idr->name_len[0];
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) {
288 xadp = (struct iso_xa_dir_record *)pnt;
290 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
291 xadp->reserved[0] == '\0') {
303 parse_rrflags(Uchar *pnt, int len, int cont_flag)
312 cont_extent = cont_offset = cont_size = 0;
317 if (pnt[3] != 1 && pnt[3] != 2) {
320 "**BAD RRVERSION (%d) for %c%c\n",
321 pnt[3], pnt[0], pnt[1]);
324 "**BAD RRVERSION (%d) for %c%c\n",
325 pnt[3], pnt[0], pnt[1]);
327 return (0); /* JS ??? Is this right ??? */
330 if (pnt[0] == 'R' && pnt[1] == 'R')
331 flag1 = pnt[4] & 0xff;
333 if (strncmp((char *) pnt, "PX", 2) == 0) /* POSIX attributes */
335 if (strncmp((char *) pnt, "PN", 2) == 0) /* POSIX device number */
337 if (strncmp((char *) pnt, "SL", 2) == 0) /* Symlink */
339 if (strncmp((char *) pnt, "NM", 2) == 0) /* Alternate Name */
341 if (strncmp((char *) pnt, "CL", 2) == 0) /* Child link */
343 if (strncmp((char *) pnt, "PL", 2) == 0) /* Parent link */
345 if (strncmp((char *) pnt, "RE", 2) == 0) /* Relocated Direcotry */
347 if (strncmp((char *) pnt, "TF", 2) == 0) /* Time stamp */
349 if (strncmp((char *) pnt, "SP", 2) == 0) { /* SUSP record */
351 /* su_version = pnt[3] & 0xff;*/
353 if (strncmp((char *) pnt, "AA", 2) == 0) { /* Apple Signature record */
355 /* aa_version = pnt[3] & 0xff;*/
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);
366 if (len <= 3 && cont_extent) {
367 unsigned char sector[SECTOR_SIZE];
369 readsecs(cont_extent, sector, 1);
370 flag2 |= parse_rrflags(§or[cont_offset], cont_size, 1);
377 rr_flags(struct iso_directory_record *idr)
383 if (find_rr(idr, &pnt, &len))
385 ret |= parse_rrflags(pnt, len, 0);
390 * Parse the RR attributes so we can find the file name.
393 parse_rr(unsigned char *pnt, int len, struct directory_entry *dpnt)
400 cont_extent = cont_offset = cont_size = 0;
402 pnt = parse_xa(pnt, &len, dpnt /* 0 */);
405 if (pnt[3] != 1 && pnt[3] != 2) {
408 "**BAD RRVERSION (%d) for %c%c\n",
409 pnt[3], pnt[0], pnt[1]);
412 "**BAD RRVERSION (%d) for %c%c\n",
413 pnt[3], pnt[0], pnt[1]);
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;
421 size_t nlen = strlen(dpnt->name);
424 * append to name from previous NM records
426 dpnt->name = realloc(dpnt->name, nlen +
427 strlen(name_buf) + 1);
428 strcpy(dpnt->name + nlen, name_buf);
430 dpnt->name = strdup(name_buf);
431 dpnt->got_rr_name = 1;
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);
442 if (len <= 3 && cont_extent) {
443 unsigned char sector[SECTOR_SIZE];
445 readsecs(cont_extent, sector, 1);
446 if (parse_rr(§or[cont_offset],
447 cont_size, dpnt) == -1)
452 /* Fall back to the iso name if no RR name found */
453 if (dpnt->name == NULL) {
456 strcpy(name_buf, dpnt->isorec.name);
457 cp = strchr(name_buf, ';');
461 dpnt->name = strdup(name_buf);
468 * Returns 1 if the two files are identical
469 * Returns 0 if the two files differ
472 check_rr_dates(struct directory_entry *dpnt,
473 struct directory_entry *current,
474 struct stat *statbuf,
475 struct stat *lstatbuf)
489 cont_extent = cont_offset = cont_size = 0;
493 pnt = dpnt->rr_attributes;
494 len = dpnt->rr_attr_size;
496 * We basically need to parse the rr attributes again, and dig out the
497 * dates and file types.
499 pnt = parse_xa(pnt, &len, /* dpnt */ 0);
501 if (pnt[3] != 1 && pnt[3] != 2) {
504 "**BAD RRVERSION (%d) for %c%c\n",
505 pnt[3], pnt[0], pnt[1]);
508 "**BAD RRVERSION (%d) for %c%c\n",
509 pnt[3], pnt[0], pnt[1]);
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
519 if (strncmp((char *) pnt, "PX", 2) == 0) {
520 mode = isonum_733(pnt + 4);
521 if ((lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT)) {
526 if (strncmp((char *) pnt, "TF", 2) == 0) {
528 if (pnt[4] & TF_CREATE) {
529 iso9660_date((char *) time_buf,
531 if (memcmp(time_buf, pnt + offset, 7) != 0)
535 if (pnt[4] & TF_MODIFY) {
536 iso9660_date((char *) time_buf,
538 if (memcmp(time_buf, pnt + offset, 7) != 0)
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);
551 if (len <= 3 && cont_extent) {
552 unsigned char sector[SECTOR_SIZE];
554 readsecs(cont_extent, sector, 1);
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.
561 pnt = §or[cont_offset];
564 * Clear the "pending extension record" state as
565 * we did already read it now.
567 cont_extent = cont_offset = cont_size = 0;
572 * If we have the same fundamental file type, then it is clearly safe
573 * to reuse the TRANS.TBL entry.
575 if (same_file_type) {
576 current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
581 static struct directory_entry **
582 read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
585 unsigned char *cpnt1;
589 struct iso_directory_record *idr;
593 int nmult; /* # of multi extent root entries */
595 struct directory_entry **pnt;
597 struct directory_entry **rtn;
599 unsigned char *tt_buf;
603 static int warning_given = 0;
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.
610 nbytes = roundup(isonum_733((unsigned char *) mrootp->size),
614 * First, allocate a buffer large enough to read in the entire
617 dirbuff = (char *) e_malloc(nbytes);
619 readsecs(isonum_733((unsigned char *) mrootp->extent), dirbuff,
620 nbytes / SECTOR_SIZE);
623 * Next look over the directory, and count up how many entries we have.
625 len = isonum_733((unsigned char *) mrootp->size);
632 idr = (struct iso_directory_record *) & dirbuff[i];
633 if (idr->length[0] == 0) {
638 if ((mx & ISO_MULTIEXTENT) == 0 &&
639 (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
640 nmult++; /* Need a multi extent root entry */
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.
651 rtn = (struct directory_entry **) e_malloc((nent+nmult) * sizeof (*rtn));
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
665 idr = (struct iso_directory_record *) & dirbuff[i];
666 if (idr->length[0] == 0) {
670 *pnt = (struct directory_entry *) e_malloc(sizeof (**rtn));
673 fprintf(stderr, "IDR name: '%s' ist: %d soll: %d\n",
674 idr->name, strlen(idr->name), idr->name_len[0]);
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;
682 (*pnt)->got_rr_name = 0;
683 (*pnt)->table = NULL;
684 (*pnt)->whole_name = NULL;
685 (*pnt)->filedir = NULL;
686 (*pnt)->parent_rec = NULL;
688 * Set this information so that we correctly cache previous
689 * session bits of information.
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;
698 (*pnt)->assoc = NULL;
699 (*pnt)->hfs_ent = NULL;
700 #endif /* APPLE_HYB */
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
707 rlen = idr->length[0] & 0xff;
708 cpnt = (unsigned char *) idr;
710 rlen -= offsetof(struct iso_directory_record, name[0]);
711 cpnt += offsetof(struct iso_directory_record, name[0]);
713 rlen -= idr->name_len[0];
714 cpnt += idr->name_len[0];
716 if ((idr->name_len[0] & 1) == 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);
731 fprintf(stderr, "INT name: '%s' ist: %d soll: %d\n",
732 (*pnt)->isorec.name, strlen((*pnt)->isorec.name),
736 if (idr->name_len[0] < sizeof ((*pnt)->isorec.name)) {
738 * Now zero out the remainder of the name field.
740 cpnt = (unsigned char *) (*pnt)->isorec.name;
741 cpnt += idr->name_len[0];
743 sizeof ((*pnt)->isorec.name) - idr->name_len[0]);
746 * Simple sanity work to make sure that we have no
747 * illegal data structures in our tree.
749 (*pnt)->isorec.name[MAX_ISONAME] = '\0';
750 (*pnt)->isorec.name_len[0] = MAX_ISONAME;
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....
758 if (idr->name_len[0] > LEN_ISONAME || check_oldnames) {
759 iso9660_check(idr, *pnt);
762 if (parse_rr((*pnt)->rr_attributes, rlen, *pnt) == -1) {
765 "Cannot parse Rock Ridge attributes for '%s'.\n",
769 "Cannot parse Rock Ridge attributes for '%s'.\n",
774 if (((*pnt)->isorec.name_len[0] == 1) &&
775 (((*pnt)->isorec.name[0] == 0) || /* "." entry */
776 ((*pnt)->isorec.name[0] == 1))) { /* ".." entry */
778 if ((*pnt)->name != NULL) {
781 if ((*pnt)->whole_name != NULL) {
782 free((*pnt)->whole_name);
784 if ((*pnt)->isorec.name[0] == 0) {
785 (*pnt)->name = strdup(".");
787 (*pnt)->name = strdup("..");
791 fprintf(stderr, "got DE name: %s\n", (*pnt)->name);
794 if (strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) {
795 if ((*pnt)->name != NULL) {
798 if ((*pnt)->whole_name != NULL) {
799 free((*pnt)->whole_name);
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);
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.
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;
821 * Sum up the total file size for the multi extent file
824 idr2 = (struct iso_directory_record *) &dirbuff[i2];
826 tsize += get_733(idr2->size);
827 if ((idr2->flags[0] & ISO_MULTIEXTENT) == 0)
829 i2 += idr2->length[0];
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;
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. */
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;
858 * If we find an associated file, check if there is a file
859 * with same ISO name and link it to this entry
861 for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
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;
873 * don't want this entry to be
876 (*pnt)->de_flags |= INHIBIT_JOLIET_ENTRY;
878 * XXX Is it correct to exclude UDF too?
880 (*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
883 * as we have associated files, then
884 * assume we are are dealing with
885 * Apple's extensions - if not already
888 if (apple_both == 0) {
889 apple_both = apple_ext = 1;
896 #endif /* APPLE_HYB */
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.
903 * The entries look something like: F ISODUMP.;1 isodump
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);
911 * Loop through the file, examine each entry, and attempt to
912 * attach it to the correct entry.
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) &&
923 /* Zero terminate this particular line. */
924 if (cpnt1 - tt_buf < tt_size) {
928 * Now dig through the actual directories, and try and
929 * find the attachment for this particular filename.
931 for (pnt = rtn, i = 0; i < nent; i++, pnt++) {
932 rlen = isonum_711((*pnt)->isorec.name_len);
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.
939 if (cpnt + 2 + rlen - tt_buf >= tt_size) {
943 * Now actually compare the name, and make sure
944 * that the character at the end is a ' '.
946 if (strncmp((char *) cpnt + 2,
947 (*pnt)->isorec.name, rlen) == 0 &&
948 cpnt[2 + rlen] == ' ' &&
949 (p = strchr((char *)&cpnt[2 + rlen], '\t'))) {
952 * This is a keeper. Now determine the
953 * correct table entry that we will
954 * use on the new image.
958 e_malloc(strlen(p) + 4);
959 sprintf((*pnt)->table,
963 if (!(*pnt)->got_rr_name) {
964 if ((*pnt)->name != NULL) {
967 (*pnt)->name = strdup(p);
977 } else if (!seen_rockridge && !warning_given) {
979 * Warn the user that iso-9660 names were used because neither
980 * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were
984 "Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n");
986 "name translations were found on previous session.\n");
988 "ISO-9660 file names have been used instead.\n");
991 if (dirbuff != NULL) {
994 *nentp = nent + nmult;
996 }/* read_merging_directory */
999 * Free any associated data related to the structures.
1002 free_mdinfo(struct directory_entry **ptr, int len)
1005 struct directory_entry **p;
1008 for (i = 0; i < len; i++, p++) {
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.
1017 free_directory_entry(*p);
1025 free_directory_entry(struct directory_entry *dirp)
1027 if (dirp->name != NULL)
1030 if (dirp->whole_name != NULL)
1031 free(dirp->whole_name);
1033 if (dirp->rr_attributes != NULL)
1034 free(dirp->rr_attributes);
1036 if (dirp->table != NULL)
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.
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)
1056 int retcode = -2; /* Default not found */
1058 for (i = 0; i < len; i++) {
1059 if (ptr[i] == NULL) { /* Used or empty entry skip */
1063 if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1064 ptr[i]->name[0] == '\0') {
1067 if (ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 &&
1068 ptr[i]->name[0] == 1) {
1072 if (ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0) {
1075 if (ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0) {
1080 if (ptr[i]->name != NULL &&
1081 strcmp(ptr[i]->name, curr_entry->name) != 0) {
1082 /* Not the same name continue */
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.
1090 if ((curr_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
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.
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
1106 if (ptr[i]->rr_attributes != NULL) {
1107 if ((rr = check_rr_dates(ptr[i], curr_entry, statbuf,
1111 if (rr == 0) { /* Different files */
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.
1120 if (ptr[i]->size != curr_entry->size) {
1121 /* Different files */
1124 if (memcmp(ptr[i]->isorec.date,
1125 curr_entry->isorec.date, 7) != 0) {
1126 /* Different files */
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;
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]);
1143 if (ptr[i]->mxroot == ptr[i]) { /* Remove all multi ext. entries */
1144 int j = i + 1; /* First one will be removed below */
1146 while (j < len && ptr[j] && ptr[j]->mxroot == ptr[i]) {
1151 if (odpnt != NULL) {
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.
1166 struct directory_entry *de;
1168 struct directory_entry *de2;
1171 if (de->mxroot == NULL)
1174 while (de2 != NULL && de2->mxroot == de->mxroot) {
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.
1192 copy_mult_extent(se1, se2)
1193 struct directory_entry *se1;
1194 struct directory_entry *se2;
1196 struct directory_entry *curr_entry = se1;
1201 len1 = iso_dir_ents(se1);
1202 len2 = iso_dir_ents(se2);
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.
1210 se1->de_flags |= MULTI_EXTENT;
1211 se1->isorec.flags[0] |= ISO_MULTIEXTENT;
1212 se1->mxroot = curr_entry;
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;
1223 while (se2->isorec.flags[0] & ISO_MULTIEXTENT) {
1227 struct directory_entry *sex = dup_directory_entry(se1);
1229 sex->mxroot = curr_entry;
1230 sex->next = se1->next;
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++;
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;
1254 se1->next = sex->next;
1261 * open_merge_image: Open an existing image.
1264 open_merge_image(char *path)
1267 in_image = fopen(path, "rb");
1268 if (in_image == NULL) {
1272 in_image = fopen(path, "rb");
1273 if (in_image == NULL) {
1274 if (scsidev_open(path) < 0)
1282 * close_merge_image: Close an existing image.
1288 return (scsidev_close());
1290 return (fclose(in_image));
1295 * merge_isofs: Scan an existing image, and return a pointer
1296 * to the root directory for this image.
1298 struct iso_directory_record *
1299 merge_isofs(char *path)
1301 char buffer[SECTOR_SIZE];
1304 struct iso_primary_descriptor *pri = NULL;
1305 struct iso_directory_record *rootp;
1306 struct iso_volume_descriptor *vdp;
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).
1313 get_session_start(&file_addr);
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);
1321 fprintf(stderr, " Read error on old image %s\n", path);
1325 vdp = (struct iso_volume_descriptor *) buffer;
1327 if ((strncmp(vdp->id, ISO_STANDARD_ID, sizeof (vdp->id)) == 0) &&
1328 (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY)) {
1337 pri = (struct iso_primary_descriptor *) vdp;
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) {
1342 "Previous session has incompatible sector size %d.\n",
1343 isonum_723((unsigned char *) pri->logical_block_size));
1346 if (isonum_723((unsigned char *) pri->volume_set_size) != 1) {
1348 "Previous session has volume set size %d (must be 1).\n",
1349 isonum_723((unsigned char *) pri->volume_set_size));
1352 /* Get the location and size of the root directory. */
1353 rootp = (struct iso_directory_record *)
1354 e_malloc(sizeof (struct iso_directory_record));
1356 memcpy(rootp, pri->root_directory_record, sizeof (*rootp));
1362 merge_remaining_entries(struct directory *this_dir,
1363 struct directory_entry **pnt, int n_orig)
1366 struct directory_entry *s_entry;
1367 unsigned int ttbl_extent = 0;
1368 unsigned int ttbl_index = 0;
1369 char whole_path[PATH_MAX];
1372 * Whatever is leftover in the list needs to get merged back into the
1375 for (i = 0; i < n_orig; i++) {
1376 if (pnt[i] == NULL) {
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);
1385 pnt[i]->whole_name = strdup(whole_path);
1387 if (pnt[i]->name != NULL &&
1388 /* strcmp(pnt[i]->name, "<translation table>") == 0 )*/
1389 strcmp(pnt[i]->name, trans_tbl) == 0) {
1391 isonum_733((unsigned char *)pnt[i]->isorec.extent);
1397 * Skip directories for now - these need to be treated
1400 if ((pnt[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1402 * FIXME - we need to insert this directory into the
1403 * tree, so that the path tables we generate will be
1406 if ((strcmp(pnt[i]->name, ".") == 0) ||
1407 (strcmp(pnt[i]->name, "..") == 0)) {
1408 free_directory_entry(pnt[i]);
1412 merge_old_directory_into_tree(pnt[i], this_dir);
1415 pnt[i]->next = this_dir->contents;
1416 pnt[i]->filedir = this_dir;
1417 this_dir->contents = pnt[i];
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.
1430 if (ttbl_extent == 0) {
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.
1438 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1440 * Don't care about '.' or '..'. They are never in the table
1443 if (s_entry->name != NULL && strcmp(s_entry->name, ".") == 0) {
1446 if (s_entry->name != NULL && strcmp(s_entry->name, "..") == 0) {
1449 /* if (strcmp(s_entry->name, "<translation table>") == 0)*/
1450 if (strcmp(s_entry->name, trans_tbl) == 0) {
1453 if ((s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0) {
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.
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);
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;
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.
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).
1489 merge_old_directory_into_tree(struct directory_entry *dpnt,
1490 struct directory *parent)
1492 struct directory_entry **contents = NULL;
1495 struct directory *this_dir,
1497 char whole_path[PATH_MAX];
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;
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;
1512 next_brother = parent->subdir;
1513 while (next_brother->next)
1514 next_brother = next_brother->next;
1515 next_brother->next = this_dir;
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);
1526 * Now fill this directory using information from the previous session.
1528 contents = read_merging_directory(&dpnt->isorec, &n_orig);
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
1534 for (i = 0; i < n_orig; i++) {
1536 * We can always reuse the TRANS.TBL in this particular case.
1538 contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
1540 if (((contents[i]->isorec.flags[0] & ISO_DIRECTORY) != 0) &&
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);
1548 if (strcmp(contents[i]->name, ".") == 0)
1549 this_dir->dir_flags |= DIR_HAS_DOT;
1551 if (strcmp(contents[i]->name, "..") == 0)
1552 this_dir->dir_flags |= DIR_HAS_DOTDOT;
1555 * for regilar files, we do it here.
1556 * If it has CL or RE attributes, remember its extent
1558 check_rr_relocation(contents[i]);
1561 * Set the whole name for this file.
1563 strcpy(whole_path, this_dir->whole_name);
1564 strcat(whole_path, SPATH_SEPARATOR);
1565 strcat(whole_path, contents[i]->name);
1567 contents[i]->whole_name = strdup(whole_path);
1569 contents[i]->next = this_dir->contents;
1570 contents[i]->filedir = this_dir;
1571 this_dir->contents = contents[i];
1576 * and for directories, we do it here.
1577 * If it has CL or RE attributes, remember its extent
1579 check_rr_relocation(dpnt);
1582 * Zero the extent number for ourselves.
1584 memset(dpnt->isorec.extent, 0, 8);
1587 * Anything that is left are other subdirectories that need to be
1590 merge_remaining_entries(this_dir, contents, n_orig);
1591 free_mdinfo(contents, n_orig);
1594 * This is no longer required. The post-scan sort will handle all of
1597 sort_n_finish(this_dir);
1604 char *cdrecord_data = NULL;
1607 get_session_start(int *file_addr)
1611 #ifdef CDRECORD_DETERMINES_FIRST_WRITABLE_ADDRESS
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.
1617 if (file_addr != NULL)
1621 * We need to coordinate with cdrecord to get the next writable address
1622 * from the device. Here is where we use it.
1624 session_start = last_extent = last_extent_written = cdrecord_result();
1627 if (file_addr != NULL)
1629 session_start = last_extent = last_extent_written = 0L;
1630 if (check_session && cdrecord_data == NULL)
1633 if (cdrecord_data == NULL) {
1634 #ifdef USE_LIBSCHILY
1636 "Special parameters for cdrecord not specified with -C\n");
1639 "Special parameters for cdrecord not specified with -C\n");
1644 * Next try and find the ',' in there which delimits the two numbers.
1646 pnt = strchr(cdrecord_data, ',');
1648 #ifdef USE_LIBSCHILY
1649 comerrno(EX_BAD, "Malformed cdrecord parameters\n");
1651 fprintf(stderr, "Malformed cdrecord parameters\n");
1657 if (file_addr != NULL) {
1658 *file_addr = atol(cdrecord_data);
1662 session_start = last_extent = last_extent_written = atol(pnt);
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.
1677 merge_previous_session(struct directory *this_dir,
1678 struct iso_directory_record *mrootp,
1680 char *reloc_old_root)
1682 struct directory_entry **orig_contents = NULL;
1683 struct directory_entry *odpnt = NULL;
1685 struct directory_entry *s_entry;
1688 struct stat statbuf,
1692 /* skip leading slash */
1693 while (reloc_old_root && reloc_old_root[0] == PATH_SEPARATOR) {
1696 while (reloc_root && reloc_root[0] == PATH_SEPARATOR) {
1701 * Parse the same directory in the image that we are merging for
1702 * multisession stuff.
1704 orig_contents = read_merging_directory(mrootp, &n_orig);
1705 if (orig_contents == NULL) {
1706 if (reloc_old_root) {
1707 #ifdef USE_LIBSCHILY
1709 "Reading old session failed, cannot execute -old-root.\n");
1712 "Reading old session failed, cannot execute -old-root.\n");
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;
1723 /* decend until we reach the original root */
1724 while (reloc_old_root[0]) {
1729 for (next = reloc_old_root; *next && *next != PATH_SEPARATOR; next++);
1737 while (*next == PATH_SEPARATOR) {
1741 for (i = 0; i < new_n_orig; i++) {
1742 struct iso_directory_record subroot;
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 */
1750 * enter directory, free old one only if not the top level,
1751 * which is still needed
1753 subroot = new_orig_contents[i]->isorec;
1754 if (new_orig_contents != orig_contents) {
1755 free_mdinfo(new_orig_contents, new_n_orig);
1757 new_orig_contents = read_merging_directory(&subroot, &new_n_orig);
1759 if (!new_orig_contents) {
1760 #ifdef USE_LIBSCHILY
1762 "Reading directory %s in old session failed, cannot execute -old-root.\n",
1766 "Reading directory %s in old session failed, cannot execute -old-root.\n",
1775 if (i == new_n_orig) {
1776 #ifdef USE_LIBSCHILY
1778 "-old-root (sub)directory %s not found in old session.\n",
1782 "-old-root (sub)directory %s not found in old session.\n",
1788 /* restore string, proceed to next sub directory */
1790 reloc_old_root[strlen(reloc_old_root)] = PATH_SEPARATOR;
1792 reloc_old_root = next;
1796 * preserve the old session, skipping those dirs/files that are found again
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);
1804 * check_prev_session() will search for s_entry and remove it from
1805 * orig_contents if found
1807 retcode = check_prev_session(orig_contents, n_orig, s_entry,
1808 &statbuf, &lstatbuf, NULL);
1812 * Skip other directory entries for multi-extent files
1814 if (s_entry->de_flags & MULTI_EXTENT) {
1815 struct directory_entry *s_e;
1817 for (s_e = s_entry->mxroot;
1818 s_e && s_e->mxroot == s_entry->mxroot;
1825 merge_remaining_entries(this_dir, orig_contents, n_orig);
1827 /* use new directory */
1828 free_mdinfo(orig_contents, n_orig);
1829 orig_contents = new_orig_contents;
1830 n_orig = new_n_orig;
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);
1843 * Now we scan the directory itself, and look at what is inside of it.
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);
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
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.
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,
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.
1876 retcode = check_prev_session(orig_contents, n_orig, s_entry,
1877 &statbuf, &lstatbuf, &odpnt);
1881 if (odpnt != NULL &&
1882 (s_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
1885 if (strcmp(s_entry->name, ".") != 0 &&
1886 strcmp(s_entry->name, "..") != 0) {
1887 struct directory *child;
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
1894 * XXX multi.c:find_or_create_directory()
1895 * XXX that should be removed when a
1896 * XXX reasonable method could be found.
1898 child = find_or_create_directory(this_dir,
1899 s_entry->whole_name,
1901 dflag = merge_previous_session(child,
1903 NULL, reloc_old_root);
1916 * Skip other directory entries for multi-extent files
1918 if (s_entry->de_flags & MULTI_EXTENT) {
1919 struct directory_entry *s_e;
1921 for (s_e = s_entry->mxroot;
1922 s_e && s_e->mxroot == s_entry->mxroot;
1930 if (!reloc_old_root) {
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.
1935 merge_remaining_entries(this_dir, orig_contents, n_orig);
1937 free_mdinfo(orig_contents, n_orig);
1942 * This code deals with relocated directories which may exist
1943 * in the previous session.
1945 struct dir_extent_link {
1946 unsigned int extent;
1947 struct directory_entry *de;
1948 struct dir_extent_link *next;
1951 static struct dir_extent_link *cl_dirs = NULL;
1952 static struct dir_extent_link *re_dirs = NULL;
1955 check_rr_relocation(struct directory_entry *de)
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,
1964 pnt = parse_xa(pnt, &len, /* dpnt */ 0);
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]);
1970 fprintf(stderr, "**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);
1973 if (strncmp((char *) pnt, "CL", 2) == 0) {
1974 struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
1976 dlink->extent = isonum_733(pnt + 4);
1978 dlink->next = cl_dirs;
1981 } else if (strncmp((char *) pnt, "RE", 2) == 0) {
1982 struct dir_extent_link *dlink = e_malloc(sizeof (*dlink));
1984 dlink->extent = de->starting_block;
1986 dlink->next = re_dirs;
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);
1994 } else if (strncmp((char *) pnt, "ST", 2) == 0) {
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;
2004 cont_extent = cont_offset = cont_size = 0;
2011 match_cl_re_entries()
2013 struct dir_extent_link *re = re_dirs;
2015 /* for each relocated directory */
2016 for (; re; re = re->next) {
2017 struct dir_extent_link *cl = cl_dirs;
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;
2027 * see if it is in rr_moved
2029 if (reloc_dir != NULL) {
2030 struct directory_entry *rr_moved_e = reloc_dir->contents;
2032 for (; rr_moved_e; rr_moved_e = rr_moved_e->next) {
2034 if (re->de == rr_moved_e) {
2047 finish_cl_pl_for_prev_session()
2049 struct dir_extent_link *re = re_dirs;
2051 /* for those that were relocated, but NOT to rr_moved */
2053 for (; re; re = re->next) {
2054 if (re->de != NULL) {
2056 * here we have hypothetical case when previous session
2057 * was not created by genisoimage and contains relocations
2059 struct directory_entry *s_entry = re->de;
2060 struct directory_entry *s_entry1;
2061 struct directory *d_entry = reloc_dir->subdir;
2063 /* do the same as finish_cl_pl_entries */
2064 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
2068 if (d_entry->self == s_entry)
2070 d_entry = d_entry->next;
2073 #ifdef USE_LIBSCHILY
2074 comerrno(EX_BAD, "Unable to locate directory parent\n");
2076 fprintf(stderr, "Unable to locate directory parent\n");
2081 if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
2085 * First fix the PL pointer in the directory in the
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);
2094 /* Now fix the CL pointer */
2095 s_entry1 = s_entry->parent_rec;
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);
2107 struct dir_extent_link *next = re->next;
2114 struct dir_extent_link *next = re->next;