multi.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:33k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*
  2.  * File multi.c - scan existing iso9660 image and merge into 
  3.  * iso9660 filesystem.  Used for multisession support.
  4.  *
  5.  * Written by Eric Youngdale (1996).
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2, or (at your option)
  10.  * any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
  20.  */
  21. static char rcsid[] ="$Id: multi.c,v 1.15 1999/11/22 02:36:28 eric Exp $";
  22. #include "config.h"
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <errno.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #ifndef VMS
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33. #else
  34. #include <sys/file.h>
  35. #include <vms/fabdef.h>
  36. #include "vms.h"
  37. extern char * strdup(const char *);
  38. #endif
  39. #include "mkisofs.h"
  40. #include "iso9660.h"
  41. #ifdef USE_LIBSCHILY
  42. #include <standard.h>
  43. #endif
  44. #ifndef howmany
  45. #define howmany(x, y)   (((x)+((y)-1))/(y))
  46. #endif
  47. #ifndef roundup
  48. #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
  49. #endif
  50. #define TF_CREATE 1
  51. #define TF_MODIFY 2
  52. #define TF_ACCESS 4
  53. #define TF_ATTRIBUTES 8
  54. static int  isonum_711 __PR((unsigned char * p));
  55. static int  isonum_721 __PR((unsigned char * p));
  56. static int  isonum_723 __PR((unsigned char * p));
  57. static int  isonum_731 __PR((unsigned char * p));
  58. static void DECL(free_directory_entry, (struct directory_entry * dirp));
  59. static int  DECL(merge_old_directory_into_tree, (struct directory_entry *,
  60.  struct directory *));
  61. #ifdef __STDC__
  62. static int
  63. isonum_711 (unsigned char * p)
  64. #else
  65. static int
  66. isonum_711 (p)
  67. unsigned char * p;
  68. #endif
  69. {
  70. return (*p & 0xff);
  71. }
  72. #ifdef __STDC__
  73. static int
  74. isonum_721 (unsigned char * p)
  75. #else
  76. static int
  77. isonum_721 (p)
  78. unsigned char * p;
  79. #endif
  80. {
  81. return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
  82. }
  83. #ifdef __STDC__
  84. static int
  85. isonum_723 (unsigned char * p)
  86. #else
  87. static int
  88. isonum_723 (p)
  89. unsigned char * p;
  90. #endif
  91. {
  92. #if 0
  93. if (p[0] != p[3] || p[1] != p[2]) {
  94. #ifdef USE_LIBSCHILY
  95. comerrno(EX_BAD, "invalid format 7.2.3 numbern");
  96. #else
  97. fprintf (stderr, "invalid format 7.2.3 numbern");
  98. exit (1);
  99. #endif
  100. }
  101. #endif
  102. return (isonum_721 (p));
  103. }
  104. #ifdef __STDC__
  105. static int
  106. isonum_731 (unsigned char * p)
  107. #else
  108. static int
  109. isonum_731 (p)
  110. unsigned char * p;
  111. #endif
  112. {
  113. return ((p[0] & 0xff)
  114. | ((p[1] & 0xff) << 8)
  115. | ((p[2] & 0xff) << 16)
  116. | ((p[3] & 0xff) << 24));
  117. }
  118. #ifdef __STDC__
  119. int
  120. isonum_733 (unsigned char * p)
  121. #else
  122. int
  123. isonum_733 (p)
  124. unsigned char * p;
  125. #endif
  126. {
  127. return (isonum_731 (p));
  128. }
  129. FILE * in_image = NULL;
  130. #ifndef USE_SCG
  131. /*
  132.  * Don't define readsecs if mkisofs is linked with
  133.  * the SCSI library.
  134.  * readsecs() will be implemented as SCSI command in this case.
  135.  *
  136.  * Use global var in_image directly in readsecs()
  137.  * the SCSI equivalent will not use a FILE* for I/O.
  138.  *
  139.  * The main point of this pointless abstraction is that Solaris won't let
  140.  * you read 2K sectors from the cdrom driver.  The fact that 99.9% of the
  141.  * discs out there have a 2K sectorsize doesn't seem to matter that much.
  142.  * Anyways, this allows the use of a scsi-generics type of interface on
  143.  * Solaris.
  144.  */
  145. #ifdef __STDC__
  146. static int
  147. readsecs(int startsecno, void *buffer, int sectorcount)
  148. #else
  149. static int
  150. readsecs(startsecno, buffer, sectorcount)
  151. int startsecno;
  152. void *buffer;
  153. int sectorcount;
  154. #endif
  155. {
  156. int f = fileno(in_image);
  157. if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) {
  158. #ifdef USE_LIBSCHILY
  159. comerr(" Seek error on old imagen");
  160. #else
  161. fprintf(stderr," Seek error on old imagen");
  162. exit(10);
  163. #endif
  164. }
  165. if( read(f, buffer, (sectorcount * SECTOR_SIZE))
  166.     != (sectorcount * SECTOR_SIZE) )
  167. {
  168. #ifdef USE_LIBSCHILY
  169. comerr(" Read error on old imagen");
  170. #else
  171. fprintf(stderr," Read error on old imagen");
  172. exit(10);
  173. #endif
  174. }
  175. return sectorcount * SECTOR_SIZE;
  176. }
  177. #endif
  178. /*
  179.  * Parse the RR attributes so we can find the file name.
  180.  */
  181. static int 
  182. FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
  183. {
  184. int cont_extent, cont_offset, cont_size;
  185. char name_buf[256];
  186. cont_extent = cont_offset = cont_size = 0;
  187. while(len >= 4){
  188. if(pnt[3] != 1 && pnt[3] != 2) {
  189. #ifdef USE_LIBSCHILY
  190.   errmsgno(EX_BAD, "**BAD RRVERSION (%d) for %c%cn", pnt[3], pnt[0], pnt[1]);
  191. #else
  192.   fprintf(stderr, "**BAD RRVERSION (%d) for %c%cn", pnt[3], pnt[0], pnt[1]);
  193. #endif
  194.   return -1;
  195. };
  196. if(strncmp((char *) pnt, "NM", 2) == 0) {
  197.   strncpy(name_buf, (char *) pnt+5, pnt[2] - 5);
  198.   name_buf[pnt[2] - 5] = 0;
  199.   dpnt->name = strdup(name_buf);
  200.   dpnt->got_rr_name = 1;
  201.   return 0;
  202. }
  203. if(strncmp((char *) pnt, "CE", 2) == 0) {
  204. cont_extent = isonum_733(pnt+4);
  205. cont_offset = isonum_733(pnt+12);
  206. cont_size = isonum_733(pnt+20);
  207. };
  208. len -= pnt[2];
  209. pnt += pnt[2];
  210. if(len <= 3 && cont_extent) {
  211.   unsigned char sector[SECTOR_SIZE];
  212.   readsecs(cont_extent, sector, 1);
  213.   if (parse_rr(&sector[cont_offset], cont_size, dpnt) == -1)
  214. return (-1);
  215. };
  216. };
  217. /* Fall back to the iso name if no RR name found */
  218. if (dpnt->name == NULL) {
  219.   char *cp;
  220.   strcpy(name_buf, dpnt->isorec.name);
  221.   cp = strchr(name_buf, ';');
  222.   if (cp != NULL) {
  223.     *cp = '';
  224.   }
  225.   dpnt->name = strdup(name_buf);
  226. }
  227. return 0;
  228. } /* parse_rr */
  229. /*
  230.  * Returns 1 if the two files are identical
  231.  * Returns 0 if the two files differ
  232.  */
  233. static int 
  234. FDECL4(check_rr_dates, struct directory_entry *, dpnt, 
  235.        struct directory_entry *, current, 
  236.        struct stat *, statbuf, 
  237.        struct stat *,lstatbuf)
  238. {
  239. int cont_extent, cont_offset, cont_size;
  240. int offset;
  241. unsigned char * pnt;
  242. int len;
  243. int same_file;
  244. int same_file_type;
  245. mode_t mode;
  246. char time_buf[7];
  247. cont_extent = cont_offset = cont_size = 0;
  248. same_file = 1;
  249. same_file_type = 1;
  250. pnt = dpnt->rr_attributes;
  251. len = dpnt->rr_attr_size;
  252. /*
  253.  * We basically need to parse the rr attributes again, and
  254.  * dig out the dates and file types.
  255.  */
  256. while(len >= 4){
  257. if(pnt[3] != 1 && pnt[3] != 2) {
  258. #ifdef USE_LIBSCHILY
  259.   errmsgno(EX_BAD, "**BAD RRVERSION (%d) for %c%cn", pnt[3], pnt[0], pnt[1]);
  260. #else
  261.   fprintf(stderr, "**BAD RRVERSION (%d) for %c%cn", pnt[3], pnt[0], pnt[1]);
  262. #endif
  263.   return -1;
  264. };
  265. /*
  266.  * If we have POSIX file modes, make sure that the file type
  267.  * is the same.  If it isn't, then we must always
  268.  * write the new file.
  269.  */
  270. if(strncmp((char *) pnt, "PX", 2) == 0) {
  271.   mode = isonum_733(pnt + 4);
  272.   if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) )
  273.     {
  274.       same_file_type = 0;
  275.       same_file = 0;
  276.     }
  277. }
  278. if(strncmp((char *) pnt, "TF", 2) == 0) {
  279.   offset = 5;
  280.   if( pnt[4] & TF_CREATE )
  281.     {
  282.       iso9660_date((char *) time_buf, lstatbuf->st_ctime);
  283.       if(memcmp(time_buf, pnt+offset, 7) != 0) 
  284. same_file = 0;
  285.       offset += 7;
  286.     }
  287.   if( pnt[4] & TF_MODIFY )
  288.     {
  289.       iso9660_date((char *) time_buf, lstatbuf->st_mtime);
  290.       if(memcmp(time_buf, pnt+offset, 7) != 0) 
  291. same_file = 0;
  292.       offset += 7;
  293.     }
  294. }
  295. if(strncmp((char *) pnt, "CE", 2) == 0) {
  296. cont_extent = isonum_733(pnt+4);
  297. cont_offset = isonum_733(pnt+12);
  298. cont_size = isonum_733(pnt+20);
  299. };
  300. len -= pnt[2];
  301. pnt += pnt[2];
  302. if(len <= 3 && cont_extent) {
  303.   unsigned char sector[SECTOR_SIZE];
  304.   readsecs(cont_extent, sector, 1);
  305.   if (parse_rr(&sector[cont_offset], cont_size, dpnt) == -1)
  306. return (-1);
  307. };
  308. };
  309. /*
  310.  * If we have the same fundamental file type, then it is clearly
  311.  * safe to reuse the TRANS.TBL entry.
  312.  */
  313. if( same_file_type )
  314.   {
  315.     current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
  316.   }
  317. return same_file;
  318. }
  319. struct directory_entry **
  320. FDECL2(read_merging_directory, struct iso_directory_record *, mrootp,
  321.        int *, nent)
  322. {
  323.   unsigned char * cpnt;
  324.   unsigned char * cpnt1;
  325.   char * dirbuff;
  326.   int   i;
  327.   struct iso_directory_record * idr;
  328.   int   len;
  329.   int   nbytes;
  330.   struct directory_entry **pnt;
  331.   int   rlen;
  332.   struct directory_entry **rtn;
  333.   int   seen_rockridge;
  334.   unsigned char * tt_buf;
  335.   int   tt_extent;
  336.   int   tt_size;
  337.   static int warning_given = 0;
  338.   /*
  339.    * This is the number of sectors we will need to read.  We need to
  340.    * round up to get the last fractional sector - we are asking for
  341.    * the data in terms of a number of sectors.
  342.    */
  343.   nbytes = roundup(isonum_733((unsigned char *)mrootp->size), SECTOR_SIZE);
  344.   /*
  345.    * First, allocate a buffer large enough to read in the entire
  346.    * directory.
  347.    */
  348.   dirbuff = (char *) e_malloc(nbytes);
  349.   readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff,
  350.    nbytes / SECTOR_SIZE);
  351.   /*
  352.    * Next look over the directory, and count up how many entries we
  353.    * have.
  354.    */
  355.   len = isonum_733((unsigned char *)mrootp->size);
  356.   i = 0;
  357.   *nent = 0;
  358.   while(i < len )
  359.     {
  360.       idr = (struct iso_directory_record *) &dirbuff[i];
  361.       if(idr->length[0] == 0) 
  362. {
  363.   i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
  364.   continue;
  365. }
  366.       (*nent)++;
  367.       i += idr->length[0];
  368.     }
  369.   /*
  370.    * Now allocate the buffer which will hold the array we are
  371.    * about to return.
  372.    */
  373.   rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn));
  374.   /*
  375.    * Finally, scan the directory one last time, and pick out the
  376.    * relevant bits of information, and store it in the relevant
  377.    * bits of the structure.
  378.    */
  379.   i = 0;
  380.   pnt = rtn;
  381.   tt_extent = 0;
  382.   seen_rockridge = 0;
  383.   tt_size = 0;
  384.   while(i < len )
  385.     {
  386.       idr = (struct iso_directory_record *) &dirbuff[i];
  387.       if(idr->length[0] == 0) 
  388. {
  389.   i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
  390.   continue;
  391. }
  392.       *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn));
  393.       (*pnt)->next = NULL;
  394.       (*pnt)->isorec = *idr;
  395.       (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent);
  396.       (*pnt)->size = isonum_733((unsigned char *)idr->size);
  397.       (*pnt)->priority = 0;
  398.       (*pnt)->name = NULL;
  399.       (*pnt)->got_rr_name = 0;
  400.       (*pnt)->table = NULL;
  401.       (*pnt)->whole_name = NULL;
  402.       (*pnt)->filedir = NULL;
  403.       (*pnt)->parent_rec = NULL;
  404.       /*
  405.        * Set this information so that we correctly cache previous
  406.        * session bits of information.
  407.        */
  408.       (*pnt)->inode = (*pnt)->starting_block;
  409.       (*pnt)->dev = PREV_SESS_DEV;
  410.       (*pnt)->rr_attributes = NULL;
  411.       (*pnt)->rr_attr_size = 0;
  412.       (*pnt)->total_rr_attr_size = 0;
  413.       (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
  414.       /*
  415.        * Check for and parse any RR attributes for the file.
  416.        * All we are really looking for here is the original name
  417.        * of the file.
  418.        */
  419.       rlen = idr->length[0] & 0xff;
  420.       cpnt = (unsigned char *) idr;
  421.       
  422.       rlen -= offsetof(struct iso_directory_record, name[0]);
  423.       cpnt += offsetof(struct iso_directory_record, name[0]);
  424.       
  425.       rlen -= idr->name_len[0];
  426.       cpnt += idr->name_len[0];
  427.       
  428.       if((idr->name_len[0] & 1) == 0){
  429. cpnt++;
  430. rlen--;
  431.       };
  432.       if (no_rr)
  433. rlen = 0;
  434.       if( rlen != 0 )
  435. {
  436.   (*pnt)->total_rr_attr_size =  (*pnt)->rr_attr_size = rlen;
  437.   (*pnt)->rr_attributes = e_malloc(rlen);
  438.   memcpy((*pnt)->rr_attributes,  cpnt, rlen);
  439.   seen_rockridge = 1;
  440. }
  441.       /*
  442.        * Now zero out the remainder of the name field.
  443.        */
  444.       cpnt = (unsigned char *)(*pnt)->isorec.name;
  445.       cpnt += idr->name_len[0];
  446.       memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]);
  447.       if (parse_rr((*pnt)->rr_attributes, rlen, *pnt) == -1) {
  448. #ifdef USE_LIBSCHILY
  449. comerrno(EX_BAD, "Cannot parse Rock Ridge attributes for '%s'.n", idr->name);
  450. #else
  451. fprintf(stderr, "Cannot parse Rock Ridge attributes for '%s'.n", idr->name);
  452. exit(1);
  453. #endif
  454.       }
  455.       
  456.       if(    ((*pnt)->isorec.name_len[0] == 1)
  457.   && (    ((*pnt)->isorec.name[0] == 0) /* "."  entry */
  458.        || ((*pnt)->isorec.name[0] == 1)) ) /* ".." entry */
  459. {
  460.   if( (*pnt)->name != NULL )
  461.     {
  462.       free((*pnt)->name);
  463.     }
  464.   if( (*pnt)->whole_name != NULL )
  465.     {
  466.       free((*pnt)->whole_name);
  467.     }
  468.   if( (*pnt)->isorec.name[0] == 0 )
  469.     {
  470.       (*pnt)->name = strdup(".");
  471.     }
  472.   else
  473.     {
  474.       (*pnt)->name = strdup("..");
  475.     }
  476. }
  477. #ifdef DEBUG
  478.       fprintf(stderr, "got DE name: %sn", (*pnt)->name);
  479. #endif
  480.       if( strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0)
  481. {
  482.   if( (*pnt)->name != NULL )
  483.     {
  484.       free((*pnt)->name);
  485.     }
  486.   if( (*pnt)->whole_name != NULL )
  487.     {
  488.       free((*pnt)->whole_name);
  489.     }
  490. /*   (*pnt)->name = strdup("<translation table>");*/
  491.   (*pnt)->name = strdup(trans_tbl);
  492.   tt_extent = isonum_733((unsigned char *)idr->extent);
  493.   tt_size = isonum_733((unsigned char *)idr->size);
  494.   if (tt_extent == 0)
  495. tt_size = 0;
  496. }
  497.       
  498.       pnt++;
  499.       i += idr->length[0];
  500.     }
  501.   /*
  502.    * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
  503.    * to get the filenames of the files.  Also, save the table info, just
  504.    * in case we need to use it.
  505.    *
  506.    * The entries look something like:
  507.    * F ISODUMP.;1                         isodump
  508.    */
  509.   if( tt_extent != 0 && tt_size != 0 )
  510.   {
  511.       nbytes = roundup(tt_size, SECTOR_SIZE);
  512.       tt_buf = (unsigned char *) e_malloc(nbytes);
  513.       readsecs(tt_extent, tt_buf, nbytes / SECTOR_SIZE);
  514.       /*
  515.        * Loop through the file, examine each entry, and attempt to
  516.        * attach it to the correct entry.
  517.        */
  518.       cpnt = tt_buf;
  519.       cpnt1 = tt_buf;
  520.       while( cpnt - tt_buf < tt_size )
  521.       {
  522.   /*
  523.    * Skip to a line terminator, or end of the file.
  524.    */
  525.   while( (cpnt1 - tt_buf < tt_size) 
  526.  && (*cpnt1 != 'n') 
  527.  && (*cpnt1 != '') )
  528.   {
  529.     cpnt1++;
  530.   }
  531.   /*
  532.    * Zero terminate this particular line.
  533.    */
  534.   if (cpnt1 - tt_buf < tt_size)
  535.   {
  536.     *cpnt1 = '';
  537.   }
  538.   /*
  539.    * Now dig through the actual directories, and
  540.    * try and find the attachment for this particular
  541.    * filename.
  542.    */
  543.   for(pnt = rtn, i = 0; i <*nent; i++, pnt++)
  544.   {
  545.       rlen = isonum_711((*pnt)->isorec.name_len);
  546.       /*
  547.        * If this filename is so long that it would
  548.        * extend past the end of the file, it cannot
  549.        * be the one we want.
  550.        */
  551.       if( cpnt + 2 + rlen - tt_buf >= tt_size)
  552.       {
  553.   continue;
  554.       }
  555.       /*
  556.        * Now actually compare the name, and make sure that
  557.        * the character at the end is a ' '.
  558.        */
  559.       if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, rlen) == 0 
  560.   && cpnt[2+rlen] == ' ')
  561.       {
  562.   /*
  563.    * This is a keeper. Now determine the correct table
  564.    * entry that we will use on the new image.
  565.    */
  566.   if( strlen((char*)cpnt) > 33)
  567.   {
  568.       (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33);
  569.       sprintf((*pnt)->table, "%ct%sn",
  570.       *cpnt, cpnt+37);
  571.   }
  572.   if( !(*pnt)->got_rr_name )
  573.   {
  574.       if ((*pnt)->name != NULL) 
  575.       {
  576.   free((*pnt)->name);
  577.       }
  578.       (*pnt)->name = strdup((char *) cpnt+37);
  579.   }
  580.   break;
  581.       }
  582.   }
  583.   cpnt = cpnt1 + 1;
  584.   cpnt1 = cpnt;
  585.       }
  586.       
  587.       free(tt_buf);
  588.   }
  589.   else if( !seen_rockridge && !warning_given )
  590.     {
  591.       /*
  592.        * Warn the user that iso (8.3) names were used because neither
  593.        * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found.
  594.        */
  595.       fprintf(stderr,"Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) n");
  596.       fprintf(stderr,"name translations were found on previous session.n");
  597.       fprintf(stderr,"ISO (8.3) file names have been used instead.n");
  598.       warning_given = 1;
  599.     }
  600.   if( dirbuff != NULL )
  601.     {
  602.       free(dirbuff);
  603.     }
  604.   
  605.   return rtn;
  606. } /* read_merging_directory */
  607. /*
  608.  * Free any associated data related to the structures.
  609.  */
  610. int 
  611. FDECL2(free_mdinfo, struct directory_entry **  , ptr, int, len )
  612. {
  613.   int i;
  614.   struct directory_entry **p;
  615.   p = ptr;
  616.   for(i=0; i<len; i++, p++)
  617.     {
  618.       /*
  619.        * If the tree-handling code decided that it needed an entry,
  620.        * it will have removed it from the list.  Thus we must allow
  621.        * for null pointers here.
  622.        */
  623.       if( *p == NULL )
  624. {
  625.   continue;
  626. }
  627.       free_directory_entry(*p);
  628.     }
  629.   free(ptr);
  630.   return 0;
  631. }
  632. static void
  633. FDECL1(free_directory_entry, struct directory_entry *, dirp)
  634. {
  635.       if(dirp->name != NULL)
  636.   free(dirp->name);
  637.       if(dirp->whole_name != NULL)
  638.   free(dirp->whole_name);
  639.       if(dirp->rr_attributes != NULL)
  640.   free(dirp->rr_attributes);
  641.       if(dirp->table != NULL)
  642.   free(dirp->table);
  643.       free(dirp);
  644. }
  645. /*
  646.  * Search the list to see if we have any entries from the previous
  647.  * session that match this entry.  If so, copy the extent number
  648.  * over so we don't bother to write it out to the new session.
  649.  */
  650. int
  651. FDECL6(check_prev_session, struct directory_entry **  , ptr, int, len,
  652.        struct directory_entry *, curr_entry,
  653.        struct stat *, statbuf, struct stat *, lstatbuf,
  654.        struct directory_entry **, odpnt)
  655. {
  656.   int i;
  657.   int rr;
  658.   int retcode = 0; /* Default not found */
  659.   for( i=0; i < len; i++ )
  660.     {
  661.       if( ptr[i] == NULL ) /* Used or empty entry skip */
  662. {
  663.   continue;
  664. }
  665. #if 0
  666.       if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
  667.   && ptr[i]->name[0] == '' )
  668. {
  669.   continue;
  670. }
  671.       if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
  672.   && ptr[i]->name[0] == 1)
  673. {
  674.   continue;
  675. }
  676. #else
  677.       if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 )
  678. {
  679.   continue;
  680. }
  681.       if( ptr[i]->name != NULL  && strcmp(ptr[i]->name, "..") == 0 )
  682. {
  683.   continue;
  684. }
  685. #endif
  686.       if(    ptr[i]->name != NULL
  687.   && strcmp(ptr[i]->name, curr_entry->name) != 0 ) /* Not the same name continue */
  688. {
  689.   continue;
  690. }
  691.       /*
  692.        * It's a directory so we must always merge it
  693.        * with the new session.
  694.        * Never ever reuse directory extents.  See comments in
  695.        * tree.c for an explaination of why this must be the case.
  696.        */
  697.       if( (curr_entry->isorec.flags[0] & 2) != 0 )
  698. {
  699.   retcode = 2; /* Flag directory case */
  700.   goto found_it;
  701. }
  702.       /*
  703.        * We know that the files have the same name.  If they also have
  704.        * the same file type (i.e. file, dir, block, etc), then we
  705.        * can safely reuse the TRANS.TBL entry for this file.
  706.        * The check_rr_dates function will do this for us.
  707.        *
  708.        * Verify that the file type and dates are consistent.
  709.        * If not, we probably have a different file, and we need
  710.        * to write it out again.
  711.        */
  712.       retcode = 1;   /* We found a non directory */
  713.       if (ptr[i]->rr_attributes != NULL) {
  714.   if ((rr = check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) == -1)
  715. return (-1);
  716.       if (rr==0) { /* Different files */
  717.   goto found_it;
  718.       }
  719.       }
  720.       /*
  721.        * Verify size and timestamp.  If rock ridge is in use, we need
  722.        * to compare dates from RR too.  Directories are special, we
  723.        * calculate their size later.
  724.        */
  725.       if (ptr[i]->size != curr_entry->size )
  726.       {
  727. /* Different files */
  728.   goto found_it;
  729.       }
  730.       if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 )
  731. {
  732. /* Different files */
  733.   goto found_it;
  734. }
  735.       /*
  736.        * We found it and we can reuse the extent
  737.        */
  738.       memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
  739.       curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
  740.       goto found_it;
  741.     }
  742.   return retcode;
  743. found_it:
  744.   if( odpnt != NULL )
  745.     {
  746.       *odpnt = ptr[i];
  747.     }
  748.   else
  749.     {
  750.       free(ptr[i]);
  751.     }
  752.   ptr[i] = NULL;
  753.   return retcode;
  754. }
  755. /*
  756.  * open_merge_image:  Open an existing image.
  757.  */
  758. int FDECL1(open_merge_image, char *, path)
  759. {
  760. #ifndef USE_SCG
  761.   in_image = fopen(path, "rb");
  762.   if( in_image == NULL )
  763.     {
  764.       return -1;
  765.     }
  766. #else
  767.   in_image = fopen(path, "rb");
  768.   if( in_image == NULL )
  769.     {
  770. if (scsidev_open(path) < 0)
  771. return -1;
  772.     }
  773. #endif
  774.   return 0;
  775. }
  776. /*
  777.  * merge_isofs:  Scan an existing image, and return a pointer
  778.  * to the root directory for this image.
  779.  */
  780. struct iso_directory_record * FDECL1(merge_isofs, char *, path)
  781. {
  782.   char   buffer[SECTOR_SIZE];
  783.   int   file_addr;
  784.   int   i;
  785.   struct iso_primary_descriptor * pri = NULL;
  786.   struct iso_directory_record   * rootp;
  787.   struct iso_volume_descriptor  * vdp;
  788.   /*
  789.    * Start by searching for the volume header.
  790.    * Ultimately, we need to search for volume headers in multiple places
  791.    * because we might be starting with a multisession image.
  792.    * FIXME(eric).
  793.    */
  794.   get_session_start(&file_addr);
  795.   for(i = 0; i< 100; i++)
  796.     {
  797.       if (readsecs(file_addr/SECTOR_SIZE, buffer,
  798.    sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer))
  799. {
  800. #ifdef USE_LIBSCHILY
  801.   comerr(" Read error on old image %sn", path);
  802. #else
  803.   fprintf(stderr," Read error on old image %sn", path);
  804.   exit(10);
  805. #endif
  806. }
  807.       vdp = (struct iso_volume_descriptor *)buffer;
  808.       if(    (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0)
  809.   && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) )
  810. {
  811.   break;
  812. }
  813.       file_addr += SECTOR_SIZE;
  814.     }
  815.   if( i == 100 )
  816.     {
  817.       return NULL;
  818.     }
  819.   pri = (struct iso_primary_descriptor *)vdp;
  820.   /*
  821.    * Check the blocksize of the image to make sure it is compatible.
  822.    */
  823.   if(    (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE)
  824.       || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) )
  825.     {
  826.       return NULL;
  827.     }
  828.   /*
  829.    * Get the location and size of the root directory.
  830.    */
  831.   rootp = (struct iso_directory_record *) 
  832.     malloc(sizeof(struct iso_directory_record));
  833.   memcpy(rootp, pri->root_directory_record, sizeof(*rootp));
  834.   return rootp;
  835. }
  836. void FDECL3(merge_remaining_entries, struct directory *, this_dir,
  837.     struct directory_entry **, pnt,
  838.     int, n_orig)
  839. {
  840.   int i;
  841.   struct directory_entry * s_entry;
  842.   unsigned int ttbl_extent = 0;
  843.   unsigned int ttbl_index  = 0;
  844.   char whole_path[1024];
  845.   /*
  846.    * Whatever is leftover in the list needs to get merged back
  847.    * into the directory.
  848.    */
  849.   for( i=0; i < n_orig; i++ )
  850.     {
  851.       if( pnt[i] == NULL )
  852. {
  853.   continue;
  854. }
  855.       
  856.       if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL)
  857.        {
  858.          /*
  859.           * Set the name for this directory.
  860.           */
  861.          strcpy(whole_path, this_dir->de_name);
  862.          strcat(whole_path, SPATH_SEPARATOR);
  863.          strcat(whole_path, pnt[i]->name);
  864.          pnt[i]->whole_name = strdup(whole_path);
  865.        }
  866.       if( pnt[i]->name != NULL
  867. /*   && strcmp(pnt[i]->name, "<translation table>") == 0 )*/
  868.   && strcmp(pnt[i]->name, trans_tbl) == 0 )
  869. {
  870.   ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent);
  871.   ttbl_index = i;
  872.   continue;
  873. }
  874.       /*
  875.        * Skip directories for now - these need to be treated
  876.        * differently.
  877.        */
  878.       if( (pnt[i]->isorec.flags[0] & 2) != 0 )
  879. {
  880.   /*
  881.    * FIXME - we need to insert this directory into the
  882.    * tree, so that the path tables we generate will
  883.    * be correct.
  884.    */
  885.   if(    (strcmp(pnt[i]->name, ".") == 0)
  886.       || (strcmp(pnt[i]->name, "..") == 0) )
  887.     {
  888.       free_directory_entry(pnt[i]);
  889.       pnt[i] = NULL;
  890.       continue;
  891.     }
  892.   else
  893.     {
  894.       merge_old_directory_into_tree(pnt[i], this_dir);
  895.     }
  896. }
  897.       pnt[i]->next = this_dir->contents;
  898.       pnt[i]->filedir = this_dir;
  899.       this_dir->contents = pnt[i];
  900.       pnt[i] = NULL;
  901.     }
  902.   
  903.   /*
  904.    * If we don't have an entry for the translation table, then
  905.    * don't bother trying to copy the starting extent over.
  906.    * Note that it is possible that if we are copying the entire
  907.    * directory, the entry for the translation table will have already
  908.    * been inserted into the linked list and removed from the old
  909.    * entries list, in which case we want to leave the extent number
  910.    * as it was before.
  911.    */
  912.   if( ttbl_extent == 0 )
  913.     {
  914.       return;
  915.     }
  916.   /*
  917.    * Finally, check the directory we are creating to see whether
  918.    * there are any new entries in it.  If there are not, we can
  919.    * reuse the same translation table.
  920.    */
  921.   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  922.     {
  923.       /*
  924.        * Don't care about '.' or '..'.  They are never in the table
  925.        * anyways.
  926.        */
  927.       if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 )
  928. {
  929.   continue;
  930. }
  931.       if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 )
  932. {
  933.   continue;
  934. }
  935. /*      if( strcmp(s_entry->name, "<translation table>") == 0)*/
  936.       if( strcmp(s_entry->name, trans_tbl) == 0)
  937. {
  938.   continue;
  939. }
  940.       if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 )
  941. {
  942.   return;
  943. }
  944.     }
  945.   /*
  946.    * Locate the translation table, and re-use the same extent.
  947.    * It isn't clear that there should ever be one in there already
  948.    * so for now we try and muddle through the best we can.
  949.    */
  950.   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  951.     {
  952. /*      if( strcmp(s_entry->name, "<translation table>") == 0)*/
  953.       if( strcmp(s_entry->name, trans_tbl) == 0)
  954. {
  955.   fprintf(stderr,"Should never get heren");
  956.   set_733(s_entry->isorec.extent, ttbl_extent);
  957.   return;
  958. }
  959.     }
  960.   pnt[ttbl_index]->next = this_dir->contents;
  961.   pnt[ttbl_index]->filedir = this_dir;
  962.   this_dir->contents = pnt[ttbl_index];
  963.   pnt[ttbl_index] = NULL;
  964. }
  965. /*
  966.  * Here we have a case of a directory that has completely disappeared from
  967.  * the face of the earth on the tree we are mastering from.  Go through and
  968.  * merge it into the tree, as well as everything beneath it.
  969.  *
  970.  * Note that if a directory has been moved for some reason, this will
  971.  * incorrectly pick it up and attempt to merge it back into the old
  972.  * location.  FIXME(eric).
  973.  */
  974. static int
  975. FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, 
  976.        struct directory *, parent)
  977. {
  978.   struct directory_entry **contents = NULL;
  979.   int   i;
  980.   int   n_orig;
  981.   struct directory * this_dir, *next_brother;
  982.   char   whole_path[1024];
  983.   this_dir = (struct directory *) e_malloc(sizeof(struct directory));
  984.   memset(this_dir, 0, sizeof(struct directory));
  985.   this_dir->next = NULL;
  986.   this_dir->subdir = NULL;
  987.   this_dir->self = dpnt;
  988.   this_dir->contents = NULL;
  989.   this_dir->size = 0;
  990.   this_dir->extent = 0;
  991.   this_dir->depth = parent->depth + 1;
  992.   this_dir->parent = parent;
  993.   if(!parent->subdir)
  994.     parent->subdir = this_dir;
  995.   else {
  996.     next_brother = parent->subdir;
  997.     while(next_brother->next) next_brother = next_brother->next;
  998.     next_brother->next = this_dir;
  999.   }
  1000.   /*
  1001.    * Set the name for this directory.
  1002.    */
  1003.   strcpy(whole_path, parent->de_name);
  1004.   strcat(whole_path, SPATH_SEPARATOR);
  1005.   strcat(whole_path, dpnt->name);
  1006.   this_dir->de_name = strdup(whole_path);
  1007.   this_dir->whole_name = strdup(whole_path);
  1008.   /*
  1009.    * Now fill this directory using information from the previous
  1010.    * session.
  1011.    */
  1012.   contents = read_merging_directory(&dpnt->isorec, &n_orig);
  1013.   /*
  1014.    * Start by simply copying the '.', '..' and non-directory
  1015.    * entries to this directory.  Technically we could let
  1016.    * merge_remaining_entries handle this, but it gets rather confused
  1017.    * by the '.' and '..' entries.
  1018.    */
  1019.   for(i=0; i < n_orig; i ++ )
  1020.     {
  1021.       /*
  1022.        * We can always reuse the TRANS.TBL in this particular case.
  1023.        */
  1024.       contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
  1025.       if(    ((contents[i]->isorec.flags[0] & 2) != 0)
  1026.   && (i >= 2) )
  1027. {
  1028.   continue;
  1029. }
  1030.       /*
  1031.        * If we have a directory, don't reuse the extent number.
  1032.        */
  1033.       if( (contents[i]->isorec.flags[0] & 2) != 0 )
  1034. {
  1035.   memset(contents[i]->isorec.extent, 0, 8);
  1036.   if( strcmp(contents[i]->name, ".") == 0 )
  1037.       this_dir->dir_flags |= DIR_HAS_DOT;
  1038.   if( strcmp(contents[i]->name, "..") == 0 )
  1039.       this_dir->dir_flags |= DIR_HAS_DOTDOT;
  1040. }
  1041.       /*
  1042.        * Set the whole name for this file.
  1043.        */
  1044.       strcpy(whole_path, this_dir->whole_name);
  1045.       strcat(whole_path, SPATH_SEPARATOR);
  1046.       strcat(whole_path, contents[i]->name);
  1047.       contents[i]->whole_name = strdup(whole_path);
  1048.       contents[i]->next = this_dir->contents;
  1049.       contents[i]->filedir = this_dir;
  1050.       this_dir->contents = contents[i];
  1051.       contents[i] = NULL;
  1052.     }
  1053.   /*
  1054.    * Zero the extent number for ourselves.
  1055.    */
  1056.   memset(dpnt->isorec.extent, 0, 8);
  1057.   /*
  1058.    * Anything that is left are other subdirectories that need to be merged.
  1059.    */
  1060.   merge_remaining_entries(this_dir, contents, n_orig);
  1061.   free_mdinfo(contents, n_orig);
  1062. #if 0
  1063.   /*
  1064.    * This is no longer required.  The post-scan sort will handle
  1065.    * all of this for us.
  1066.    */
  1067.   sort_n_finish(this_dir);
  1068. #endif
  1069.   return 0;
  1070. }
  1071. char * cdrecord_data = NULL;
  1072. int
  1073. FDECL1(get_session_start, int *, file_addr) 
  1074. {
  1075.   char * pnt;
  1076. #ifdef CDRECORD_DETERMINES_FIRST_WRITABLE_ADDRESS
  1077.   /*
  1078.    * FIXME(eric).  We need to coordinate with cdrecord to obtain
  1079.    * the parameters.  For now, we assume we are writing the 2nd session,
  1080.    * so we start from the session that starts at 0.
  1081.    */
  1082.   *file_addr = (16 << 11);
  1083.   /*
  1084.    * We need to coordinate with cdrecord to get the next writable address
  1085.    * from the device.  Here is where we use it.
  1086.    */
  1087.   session_start = last_extent = last_extent_written = cdrecord_result();
  1088. #else
  1089.   if( cdrecord_data == NULL )
  1090.     {
  1091. #ifdef USE_LIBSCHILY
  1092.       comerrno(EX_BAD, "Special parameters for cdrecord not specified with -Cn");
  1093. #else
  1094.       fprintf(stderr,"Special parameters for cdrecord not specified with -Cn");
  1095.       exit(1);
  1096. #endif
  1097.     }
  1098.   /*
  1099.    * Next try and find the ',' in there which delimits the two numbers.
  1100.    */
  1101.   pnt = strchr(cdrecord_data, ',');
  1102.   if( pnt == NULL )
  1103.     {
  1104. #ifdef USE_LIBSCHILY
  1105.       comerrno(EX_BAD, "Malformed cdrecord parametersn");
  1106. #else
  1107.       fprintf(stderr, "Malformed cdrecord parametersn");
  1108.       exit(1);
  1109. #endif
  1110.     }
  1111.   *pnt = '';
  1112.   if (file_addr != NULL) {
  1113.     *file_addr = atol(cdrecord_data) * SECTOR_SIZE;
  1114.   }
  1115.   pnt++;
  1116.   session_start = last_extent = last_extent_written = atol(pnt);
  1117.   pnt--;
  1118.   *pnt = ',';
  1119. #endif
  1120.   return 0;
  1121. }
  1122. /*
  1123.  * This function scans the directory tree, looking for files, and it makes
  1124.  * note of everything that is found.  We also begin to construct the ISO9660
  1125.  * directory entries, so that we can determine how large each directory is.
  1126.  */
  1127. int
  1128. FDECL2(merge_previous_session,struct directory *, this_dir,
  1129.        struct iso_directory_record *, mrootp)
  1130. {
  1131.   struct directory_entry **orig_contents = NULL;
  1132.   struct directory_entry        * odpnt = NULL;
  1133.   int   n_orig;
  1134.   struct directory_entry * s_entry;
  1135.   int   status, lstatus;
  1136.   struct stat   statbuf, lstatbuf;
  1137.   int    retcode;
  1138.   /*
  1139.    * Parse the same directory in the image that we are merging
  1140.    * for multisession stuff.
  1141.    */
  1142.   orig_contents = read_merging_directory(mrootp, &n_orig);
  1143.   if( orig_contents == NULL )
  1144.     {
  1145.       return 0;
  1146.     }
  1147. /* Now we scan the directory itself, and look at what is inside of it. */
  1148.   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  1149.     {
  1150.       status  =  stat_filter(s_entry->whole_name, &statbuf);
  1151.       lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
  1152.       /*
  1153.        * We always should create an entirely new directory tree whenever
  1154.        * we generate a new session, unless there were *no* changes whatsoever
  1155.        * to any of the directories, in which case it would be kind of pointless
  1156.        * to generate a new session.
  1157.        *
  1158.        * I believe it is possible to rigorously prove that any change anywhere
  1159.        * in the filesystem will force the entire tree to be regenerated
  1160.        * because the modified directory will get a new extent number.  Since
  1161.        * each subdirectory of the changed directory has a '..' entry, all of
  1162.        * them will need to be rewritten too, and since the parent directory
  1163.        * of the modified directory will have an extent pointer to the directory
  1164.        * it too will need to be rewritten.  Thus we will never be able to reuse
  1165.        * any directory information when writing new sessions.
  1166.        *
  1167.        * We still check the previous session so we can mark off the equivalent
  1168.        * entry in the list we got from the original disc, however.
  1169.        */
  1170.       /*
  1171.        * The check_prev_session function looks for an identical entry in
  1172.        * the previous session.  If we see it, then we copy the extent
  1173.        * number to s_entry, and cross it off the list. It returns 2 if it's a directory
  1174.        */
  1175.       retcode = check_prev_session(orig_contents, n_orig, s_entry,
  1176.  &statbuf, &lstatbuf, &odpnt);
  1177.       if (retcode == -1)
  1178. return (-1);
  1179.       if(retcode==2 && odpnt != NULL)
  1180. {
  1181.   int dflag;
  1182.   if (strcmp(s_entry->name,".") != 0 && strcmp(s_entry->name,"..") != 0)
  1183.     {
  1184.       struct directory * child;
  1185. /*
  1186.  * XXX It seems that the tree that has been read from the
  1187.  * XXX previous session does not carry whole_name entries.
  1188.  * XXX We provide a hack in multi.c:find_or_create_directory()
  1189.  * XXX that should be removed when a reasonable method could
  1190.  * XXX be found.
  1191.  */
  1192.       child = find_or_create_directory(this_dir, 
  1193.        s_entry->whole_name, 
  1194.        s_entry, 1);
  1195.       dflag = merge_previous_session(child, 
  1196.      &odpnt->isorec);
  1197.       if (dflag == -1)
  1198. return (-1);
  1199.       free(odpnt);
  1200.       odpnt = NULL;
  1201.     }
  1202. }
  1203.     }
  1204.   
  1205.   /*
  1206.    * Whatever is left over, are things which are no longer in the tree
  1207.    * on disk.  We need to also merge these into the tree.
  1208.    */
  1209.    merge_remaining_entries(this_dir, orig_contents, n_orig);
  1210.    free_mdinfo(orig_contents, n_orig);
  1211.   
  1212.   return 1;
  1213. }