summaryrefslogtreecommitdiff
path: root/gnu/usr.sbin/mkisofs/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.sbin/mkisofs/multi.c')
-rw-r--r--gnu/usr.sbin/mkisofs/multi.c989
1 files changed, 989 insertions, 0 deletions
diff --git a/gnu/usr.sbin/mkisofs/multi.c b/gnu/usr.sbin/mkisofs/multi.c
new file mode 100644
index 00000000000..e7af4bba399
--- /dev/null
+++ b/gnu/usr.sbin/mkisofs/multi.c
@@ -0,0 +1,989 @@
+/* $OpenBSD: multi.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */
+/*
+ * File multi.c - scan existing iso9660 image and merge into
+ * iso9660 filesystem. Used for multisession support.
+ *
+ * Written by Eric Youngdale (1996).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static char rcsid[] ="$From: multi.c,v 1.4 1997/03/08 17:08:53 eric Rel $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifndef VMS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#define TF_CREATE 1
+#define TF_MODIFY 2
+#define TF_ACCESS 4
+#define TF_ATTRIBUTES 8
+
+static int DECL(get_session_start, (int *));
+static int DECL(merge_old_directory_into_tree, (struct directory_entry *,
+ struct directory *));
+
+static int
+isonum_711 (unsigned char * p)
+{
+ return (*p & 0xff);
+}
+
+int
+isonum_721 (unsigned char * p)
+{
+ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
+}
+
+static int
+isonum_723 (unsigned char * p)
+{
+#if 0
+ if (p[0] != p[3] || p[1] != p[2]) {
+ fprintf (stderr, "invalid format 7.2.3 number\n");
+ exit (1);
+ }
+#endif
+ return (isonum_721 (p));
+}
+
+int
+isonum_731 (unsigned char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+int
+isonum_733 (unsigned char * p)
+{
+ return (isonum_731 (p));
+}
+
+FILE * in_image = NULL;
+
+#ifndef USE_SCG
+/*
+ * Don't define readsecs if mkisofs is linked with
+ * the SCSI library.
+ * readsecs() will be implemented as SCSI command in this case.
+ *
+ * Use global var in_image directly in readsecs()
+ * the SCSI equivalent will not use a FILE* for I/O.
+ *
+ * The main point of this pointless abstraction is that Solaris won't let
+ * you read 2K sectors from the cdrom driver. The fact that 99.9% of the
+ * discs out there have a 2K sectorsize doesn't seem to matter that much.
+ * Anyways, this allows the use of a scsi-generics type of interface on
+ * Solaris.
+ */
+static int
+readsecs(int startsecno, void *buffer, int sectorcount)
+{
+ int f = fileno(in_image);
+
+ if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) {
+ fprintf(stderr," Seek error on old image\n");
+ exit(10);
+ }
+ return (read(f, buffer, sectorcount * SECTOR_SIZE));
+}
+#endif
+
+/*
+ * Parse the RR attributes so we can find the file name.
+ */
+static int
+FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
+{
+ int cont_extent, cont_offset, cont_size;
+ char name_buf[256];
+
+ cont_extent = cont_offset = cont_size = 0;
+
+ while(len >= 4){
+ if(pnt[3] != 1) {
+ printf("**BAD RRVERSION");
+ return -1;
+ };
+ if(strncmp((char *) pnt, "NM", 2) == 0) {
+ strncpy(name_buf, (char *) pnt+5, pnt[2] - 5);
+ name_buf[pnt[2] - 5] = 0;
+ dpnt->name = strdup(name_buf);
+ return 0;
+ }
+
+ if(strncmp((char *) pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[SECTOR_SIZE];
+ readsecs(cont_extent, sector, 1);
+ parse_rr(&sector[cont_offset], cont_size, dpnt);
+ };
+ };
+ return 0;
+}
+
+
+static int
+FDECL4(check_rr_dates, struct directory_entry *, dpnt,
+ struct directory_entry *, current,
+ struct stat *, statbuf,
+ struct stat *,lstatbuf)
+{
+ int cont_extent, cont_offset, cont_size;
+ int offset;
+ unsigned char * pnt;
+ int len;
+ int same_file;
+ int same_file_type;
+ mode_t mode;
+ char time_buf[7];
+
+
+ cont_extent = cont_offset = cont_size = 0;
+ same_file = 1;
+ same_file_type = 1;
+
+ pnt = dpnt->rr_attributes;
+ len = dpnt->rr_attr_size;
+ /*
+ * We basically need to parse the rr attributes again, and
+ * dig out the dates and file types.
+ */
+ while(len >= 4){
+ if(pnt[3] != 1) {
+ printf("**BAD RRVERSION");
+ return -1;
+ };
+
+ /*
+ * If we have POSIX file modes, make sure that the file type
+ * is the same. If it isn't, then we must always
+ * write the new file.
+ */
+ if(strncmp((char *) pnt, "PX", 2) == 0) {
+ mode = isonum_733(pnt + 4);
+ if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) )
+ {
+ same_file_type = 0;
+ same_file = 0;
+ }
+ }
+
+ if(strncmp((char *) pnt, "TF", 2) == 0) {
+ offset = 5;
+ if( pnt[4] & TF_CREATE )
+ {
+ iso9660_date((char *) time_buf, lstatbuf->st_ctime);
+ if(memcmp(time_buf, pnt+offset, 7) == 0)
+ same_file = 0;
+ offset += 7;
+ }
+ if( pnt[4] & TF_MODIFY )
+ {
+ iso9660_date((char *) time_buf, lstatbuf->st_mtime);
+ if(memcmp(time_buf, pnt+offset, 7) == 0)
+ same_file = 0;
+ offset += 7;
+ }
+ }
+
+ if(strncmp((char *) pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[SECTOR_SIZE];
+
+ readsecs(cont_extent, sector, 1);
+ parse_rr(&sector[cont_offset], cont_size, dpnt);
+ };
+ };
+
+ /*
+ * If we have the same fundamental file type, then it is clearly
+ * safe to reuse the TRANS.TBL entry.
+ */
+ if( same_file_type )
+ {
+ current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+ }
+
+ return same_file;
+}
+
+struct directory_entry **
+FDECL2(read_merging_directory, struct iso_directory_record *, mrootp,
+ int *, nent)
+{
+ unsigned char * cpnt;
+ unsigned char * cpnt1;
+ char * dirbuff;
+ int i;
+ struct iso_directory_record * idr;
+ int len;
+ struct directory_entry **pnt;
+ int rlen;
+ struct directory_entry **rtn;
+ int seen_rockridge;
+ unsigned char * tt_buf;
+ int tt_extent;
+ int tt_size;
+
+ /*
+ * First, allocate a buffer large enough to read in the entire
+ * directory.
+ */
+ dirbuff = (char *) e_malloc(isonum_733(mrootp->size));
+
+ readsecs(isonum_733(mrootp->extent), dirbuff,
+ isonum_733(mrootp->size)/SECTOR_SIZE);
+
+ /*
+ * Next look over the directory, and count up how many entries we
+ * have.
+ */
+ len = isonum_733(mrootp->size);
+ i = 0;
+ *nent = 0;
+ while(i < len )
+ {
+ idr = (struct iso_directory_record *) &dirbuff[i];
+ if(idr->length[0] == 0)
+ {
+ i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
+ continue;
+ }
+ (*nent)++;
+ i += idr->length[0];
+ }
+
+ /*
+ * Now allocate the buffer which will hold the array we are
+ * about to return.
+ */
+ rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn));
+
+ /*
+ * Finally, scan the directory one last time, and pick out the
+ * relevant bits of information, and store it in the relevant
+ * bits of the structure.
+ */
+ i = 0;
+ pnt = rtn;
+ tt_extent = 0;
+ seen_rockridge = 0;
+ tt_size = 0;
+ while(i < len )
+ {
+ idr = (struct iso_directory_record *) &dirbuff[i];
+ if(idr->length[0] == 0)
+ {
+ i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
+ continue;
+ }
+ *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn));
+ (*pnt)->next = NULL;
+ (*pnt)->isorec = *idr;
+ (*pnt)->starting_block = isonum_733(idr->extent);
+ (*pnt)->size = isonum_733(idr->size);
+ (*pnt)->priority = 0;
+ (*pnt)->name = NULL;
+ (*pnt)->table = NULL;
+ (*pnt)->whole_name = NULL;
+ (*pnt)->filedir = NULL;
+ (*pnt)->parent_rec = NULL;
+ /*
+ * Set this information so that we correctly cache previous
+ * session bits of information.
+ */
+ (*pnt)->inode = (*pnt)->starting_block;
+ (*pnt)->dev = PREV_SESS_DEV;
+ (*pnt)->rr_attributes = NULL;
+ (*pnt)->rr_attr_size = 0;
+ (*pnt)->total_rr_attr_size = 0;
+ (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
+
+ /*
+ * Check for and parse any RR attributes for the file.
+ * All we are really looking for here is the original name
+ * of the file.
+ */
+ rlen = idr->length[0] & 0xff;
+ cpnt = (unsigned char *) idr;
+
+ rlen -= sizeof(struct iso_directory_record);
+ cpnt += sizeof(struct iso_directory_record);
+
+ rlen += sizeof(idr->name);
+ cpnt -= sizeof(idr->name);
+
+ rlen -= idr->name_len[0];
+ cpnt += idr->name_len[0];
+
+ if((idr->name_len[0] & 1) == 0){
+ cpnt++;
+ rlen--;
+ };
+
+ if( rlen != 0 )
+ {
+ (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen;
+ (*pnt)->rr_attributes = e_malloc(rlen);
+ memcpy((*pnt)->rr_attributes, cpnt, rlen);
+ seen_rockridge = 1;
+ }
+
+ /*
+ * Now zero out the remainder of the name field.
+ */
+ cpnt = (unsigned char *) &(*pnt)->isorec.name;
+ cpnt += idr->name_len[0];
+ memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]);
+
+ parse_rr((*pnt)->rr_attributes, rlen, *pnt);
+
+ if( ((*pnt)->isorec.name_len[0] == 1)
+ && ( ((*pnt)->isorec.name[0] == 0)
+ || ((*pnt)->isorec.name[0] == 1)) )
+ {
+ if( (*pnt)->name != NULL )
+ {
+ free((*pnt)->name);
+ }
+ if( (*pnt)->isorec.name[0] == 0 )
+ {
+ (*pnt)->name = strdup(".");
+ }
+ else
+ {
+ (*pnt)->name = strdup("..");
+ }
+ }
+
+ if( strncmp(idr->name, "TRANS.TBL", 9) == 0)
+ {
+ if( (*pnt)->name != NULL )
+ {
+ free((*pnt)->name);
+ }
+ (*pnt)->name = strdup("<translation table>");
+ tt_extent = isonum_733(idr->extent);
+ tt_size = isonum_733(idr->size);
+ }
+
+ pnt++;
+ i += idr->length[0];
+ }
+
+ /*
+ * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
+ * to get the filenames of the files. Also, save the table info, just
+ * in case we need to use it.
+ */
+ if( tt_extent != 0 && tt_size != 0 )
+ {
+ tt_buf = (unsigned char *) e_malloc(tt_size);
+ readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE);
+
+ /*
+ * Loop through the file, examine each entry, and attempt to
+ * attach it to the correct entry.
+ */
+ cpnt = tt_buf;
+ cpnt1 = tt_buf;
+ while( cpnt - tt_buf < tt_size )
+ {
+ while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++;
+ *cpnt1 = '\0';
+
+ for(pnt = rtn, i = 0; i <*nent; i++, pnt++)
+ {
+ rlen = isonum_711((*pnt)->isorec.name_len);
+ if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name,
+ rlen) == 0
+ && cpnt[2+rlen] == ' ')
+ {
+ (*pnt)->table = strdup((char *) cpnt);
+ if( (*pnt)->name == NULL )
+ {
+ (*pnt)->name = strdup((char *) cpnt+37);
+ }
+ break;
+ }
+ }
+ cpnt = cpnt1 + 1;
+ cpnt1 = cpnt;
+ }
+
+ free(tt_buf);
+ }
+ else if( !seen_rockridge )
+ {
+ /*
+ * This is a fatal error right now because we must have some mechanism
+ * for taking the 8.3 names back to the original unix names.
+ * In principle we could do this the hard way, and try and translate
+ * the unix names that we have seen forwards, but this would be
+ * a real pain in the butt.
+ */
+ fprintf(stderr,"Previous session must have either Rock Ridge (-R) or\n");
+ fprintf(stderr,"TRANS.TBL (-T) for mkisofs to be able to correctly\n");
+ fprintf(stderr,"generate additional sessions.\n");
+ exit(3);
+ }
+
+ if( dirbuff != NULL )
+ {
+ free(dirbuff);
+ }
+
+ return rtn;
+}
+
+/*
+ * Free any associated data related to the structures.
+ */
+int
+FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len )
+{
+ int i;
+ struct directory_entry **p;
+
+ p = ptr;
+ for(i=0; i<len; i++, p++)
+ {
+ /*
+ * If the tree-handling code decided that it needed an entry,
+ * it will have removed it from the list. Thus we must allow
+ * for null pointers here.
+ */
+ if( *p == NULL )
+ {
+ continue;
+ }
+
+ if( (*p)->name != NULL )
+ {
+ free((*p)->name);
+ }
+
+ if( (*p)->rr_attributes != NULL )
+ {
+ free((*p)->rr_attributes);
+ }
+
+ if( (*p)->table != NULL )
+ {
+ free((*p)->table);
+ }
+
+ free(*p);
+
+ }
+
+ free(ptr);
+ return 0;
+}
+
+/*
+ * Search the list to see if we have any entries from the previous
+ * session that match this entry. If so, copy the extent number
+ * over so we don't bother to write it out to the new session.
+ */
+
+int
+FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len,
+ struct directory_entry *, curr_entry,
+ struct stat *, statbuf, struct stat *, lstatbuf,
+ struct directory_entry **, odpnt)
+{
+ int i;
+
+ for( i=0; i < len; i++ )
+ {
+ if( ptr[i] == NULL )
+ {
+ continue;
+ }
+
+#if 0
+ if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+ && ptr[i]->name[0] == '\0' )
+ {
+ continue;
+ }
+ if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+ && ptr[i]->name[0] == 1)
+ {
+ continue;
+ }
+#else
+ if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 )
+ {
+ continue;
+ }
+ if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 )
+ {
+ continue;
+ }
+#endif
+
+ if( ptr[i]->name != NULL
+ && strcmp(ptr[i]->name, curr_entry->name) != 0 )
+ {
+ continue;
+ }
+
+ /*
+ * We know that the files have the same name. If they also have
+ * the same file type (i.e. file, dir, block, etc), then we
+ * can safely reuse the TRANS.TBL entry for this file.
+ * The check_rr_dates function will do this for us.
+ *
+ * Verify that the file type and dates are consistent.
+ * If not, we probably have a different file, and we need
+ * to write it out again.
+ */
+ if( (ptr[i]->rr_attributes != NULL)
+ && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) )
+ {
+ goto found_it;
+ }
+
+
+ /*
+ * Verify size and timestamp. If rock ridge is in use, we need
+ * to compare dates from RR too. Directories are special, we
+ * calculate their size later.
+ */
+ if( (curr_entry->isorec.flags[0] & 2) == 0
+ && ptr[i]->size != curr_entry->size )
+ {
+ goto found_it;
+ }
+
+ if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 )
+ {
+ goto found_it;
+ }
+
+ /*
+ * Never ever reuse directory extents. See comments in
+ * tree.c for an explaination of why this must be the case.
+ */
+ if( (curr_entry->isorec.flags[0] & 2) != 0 )
+ {
+ goto found_it;
+ }
+
+ memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
+ curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+ goto found_it;
+ }
+ return 0;
+
+found_it:
+ if( odpnt != NULL )
+ {
+ *odpnt = ptr[i];
+ }
+ else
+ {
+ free(ptr[i]);
+ }
+ ptr[i] = NULL;
+ return 0;
+}
+
+/*
+ * merge_isofs: Scan an existing image, and return a pointer
+ * to the root directory for this image.
+ */
+struct iso_directory_record * FDECL1(merge_isofs, char *, path)
+{
+ char buffer[SECTOR_SIZE];
+ int file_addr;
+ int i;
+ struct iso_primary_descriptor * pri = NULL;
+ struct iso_directory_record * rootp;
+ struct iso_volume_descriptor * vdp;
+
+ /*
+ * Start by opening up the image and searching for the volume header.
+ * Ultimately, we need to search for volume headers in multiple places
+ * because we might be starting with a multisession image.
+ * FIXME(eric).
+ */
+
+ in_image = fopen(path, "rb");
+ if( in_image == NULL )
+ {
+ return NULL;
+ }
+
+ get_session_start(&file_addr);
+
+ for(i = 0; i< 100; i++)
+ {
+ if (readsecs(file_addr/SECTOR_SIZE, &buffer,
+ sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer))
+ {
+ fprintf(stderr," Read error on old image %s\n", path);
+ exit(10);
+ }
+
+ vdp = (struct iso_volume_descriptor *)buffer;
+
+ if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0)
+ && (isonum_711(vdp->type) == ISO_VD_PRIMARY) )
+ {
+ break;
+ }
+ file_addr += SECTOR_SIZE;
+ }
+
+ if( i == 100 )
+ {
+ return NULL;
+ }
+
+ pri = (struct iso_primary_descriptor *)vdp;
+
+ /*
+ * Check the blocksize of the image to make sure it is compatible.
+ */
+ if( (isonum_723 (pri->logical_block_size) != SECTOR_SIZE)
+ || (isonum_723 (pri->volume_set_size) != 1) )
+ {
+ return NULL;
+ }
+
+ /*
+ * Get the location and size of the root directory.
+ */
+ rootp = (struct iso_directory_record *)
+ malloc(sizeof(struct iso_directory_record));
+
+ memcpy(rootp, pri->root_directory_record, sizeof(*rootp));
+
+ return rootp;
+}
+
+void FDECL3(merge_remaining_entries, struct directory *, this_dir,
+ struct directory_entry **, pnt,
+ int, n_orig)
+{
+ int i;
+ struct directory_entry * s_entry;
+ unsigned int ttbl_extent = 0;
+ unsigned int ttbl_index = 0;
+
+ /*
+ * Whatever is leftover in the list needs to get merged back
+ * into the directory.
+ */
+ for( i=0; i < n_orig; i++ )
+ {
+ if( pnt[i] == NULL )
+ {
+ continue;
+ }
+
+ if( pnt[i]->name != NULL
+ && strcmp(pnt[i]->name, "<translation table>") == 0 )
+ {
+ ttbl_extent = isonum_733(pnt[i]->isorec.extent);
+ ttbl_index = i;
+ continue;
+ }
+ /*
+ * Skip directories for now - these need to be treated
+ * differently.
+ */
+ if( (pnt[i]->isorec.flags[0] & 2) != 0 )
+ {
+ /*
+ * FIXME - we need to insert this directory into the
+ * tree, so that the path tables we generate will
+ * be correct.
+ */
+ if( (strcmp(pnt[i]->name, ".") == 0)
+ || (strcmp(pnt[i]->name, "..") == 0) )
+ {
+ free(pnt[i]);
+ pnt[i] = NULL;
+ continue;
+ }
+ else
+ {
+ merge_old_directory_into_tree(pnt[i], this_dir);
+ }
+ }
+ pnt[i]->next = this_dir->contents;
+ pnt[i]->filedir = this_dir;
+ this_dir->contents = pnt[i];
+ pnt[i] = NULL;
+ }
+
+
+ /*
+ * If we don't have an entry for the translation table, then
+ * don't bother trying to copy the starting extent over.
+ * Note that it is possible that if we are copying the entire
+ * directory, the entry for the translation table will have already
+ * been inserted into the linked list and removed from the old
+ * entries list, in which case we want to leave the extent number
+ * as it was before.
+ */
+ if( ttbl_extent == 0 )
+ {
+ return;
+ }
+
+ /*
+ * Finally, check the directory we are creating to see whether
+ * there are any new entries in it. If there are not, we can
+ * reuse the same translation table.
+ */
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+ {
+ /*
+ * Don't care about '.' or '..'. They are never in the table
+ * anyways.
+ */
+ if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 )
+ {
+ continue;
+ }
+ if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 )
+ {
+ continue;
+ }
+ if( strcmp(s_entry->name, "<translation table>") == 0)
+ {
+ continue;
+ }
+ if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 )
+ {
+ return;
+ }
+ }
+
+ /*
+ * Locate the translation table, and re-use the same extent.
+ * It isn't clear that there should ever be one in there already
+ * so for now we try and muddle through the best we can.
+ */
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+ {
+ if( strcmp(s_entry->name, "<translation table>") == 0)
+ {
+ fprintf(stderr,"Should never get here\n");
+ set_733(s_entry->isorec.extent, ttbl_extent);
+ return;
+ }
+ }
+
+ pnt[ttbl_index]->next = this_dir->contents;
+ pnt[ttbl_index]->filedir = this_dir;
+ this_dir->contents = pnt[ttbl_index];
+ pnt[ttbl_index] = NULL;
+}
+
+
+/*
+ * Here we have a case of a directory that has completely disappeared from
+ * the face of the earth on the tree we are mastering from. Go through and
+ * merge it into the tree, as well as everything beneath it.
+ *
+ * Note that if a directory has been moved for some reason, this will
+ * incorrectly pick it up and attempt to merge it back into the old
+ * location. FIXME(eric).
+ */
+static int
+FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
+ struct directory *, parent)
+{
+ struct directory_entry **contents = NULL;
+ int i;
+ int n_orig;
+ struct directory * this_dir, *next_brother;
+ char whole_path[1024];
+
+ this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+ this_dir->next = NULL;
+ this_dir->subdir = NULL;
+ this_dir->self = dpnt;
+ this_dir->contents = NULL;
+ this_dir->size = 0;
+ this_dir->extent = 0;
+ this_dir->depth = parent->depth + 1;
+ this_dir->parent = parent;
+ if(!parent->subdir)
+ parent->subdir = this_dir;
+ else {
+ next_brother = parent->subdir;
+ while(next_brother->next) next_brother = next_brother->next;
+ next_brother->next = this_dir;
+ }
+
+ /*
+ * Set the name for this directory.
+ */
+ strcpy(whole_path, parent->de_name);
+ strcat(whole_path, SPATH_SEPARATOR);
+ strcat(whole_path, dpnt->name);
+ this_dir->de_name = strdup(whole_path);
+
+ /*
+ * Now fill this directory using information from the previous
+ * session.
+ */
+ contents = read_merging_directory(&dpnt->isorec, &n_orig);
+ /*
+ * Start by simply copying the '.', '..' and non-directory
+ * entries to this directory. Technically we could let
+ * merge_remaining_entries handle this, but it gets rather confused
+ * by the '.' and '..' entries.
+ */
+ for(i=0; i < n_orig; i ++ )
+ {
+ /*
+ * We can always reuse the TRANS.TBL in this particular case.
+ */
+ contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+
+ if( ((contents[i]->isorec.flags[0] & 2) != 0)
+ && (i >= 2) )
+ {
+ continue;
+ }
+
+ /*
+ * If we have a directory, don't reuse the extent number.
+ */
+ if( (contents[i]->isorec.flags[0] & 2) != 0 )
+ {
+ memset(contents[i]->isorec.extent, 0, 8);
+ }
+
+ contents[i]->next = this_dir->contents;
+ contents[i]->filedir = this_dir;
+ this_dir->contents = contents[i];
+ contents[i] = NULL;
+ }
+
+ /*
+ * Zero the extent number for ourselves.
+ */
+ memset(dpnt->isorec.extent, 0, 8);
+
+ /*
+ * Anything that is left are other subdirectories that need to be merged.
+ */
+ merge_remaining_entries(this_dir, contents, n_orig);
+ free_mdinfo(contents, n_orig);
+ sort_n_finish(this_dir);
+
+ return 0;
+}
+
+
+char * cdwrite_data = NULL;
+
+static int
+FDECL1(get_session_start, int *, file_addr)
+{
+ char * pnt;
+
+#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS
+ /*
+ * FIXME(eric). We need to coordinate with cdwrite to obtain
+ * the parameters. For now, we assume we are writing the 2nd session,
+ * so we start from the session that starts at 0.
+ */
+
+ *file_addr = (16 << 11);
+
+ /*
+ * We need to coordinate with cdwrite to get the next writable address
+ * from the device. Here is where we use it.
+ */
+ session_start = last_extent = last_extent_written = cdwrite_result();
+
+#else
+
+ if( cdwrite_data == NULL )
+ {
+ fprintf(stderr,"Special parameters for cdwrite not specified with -C\n");
+ exit(1);
+ }
+
+ /*
+ * Next try and find the ',' in there which delimits the two numbers.
+ */
+ pnt = strchr(cdwrite_data, ',');
+ if( pnt == NULL )
+ {
+ fprintf(stderr, "Malformed cdwrite parameters\n");
+ exit(1);
+ }
+
+ *pnt = '\0';
+ *file_addr = atol(cdwrite_data) * SECTOR_SIZE;
+ pnt++;
+
+ session_start = last_extent = last_extent_written = atol(pnt);
+
+ pnt--;
+ *pnt = ',';
+
+#endif
+ return 0;
+}