home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / mkisofs-1.11-MIHS / write.c < prev   
Encoding:
C/C++ Source or Header  |  1997-04-09  |  29.2 KB  |  1,140 lines

  1. /*
  2.  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
  3.  
  4.    Written by Eric Youngdale (1993).
  5.  
  6.    Copyright 1993 Yggdrasil Computing, Incorporated
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. static char rcsid[] ="$Id: write.c,v 1.4 1997/04/10 03:33:25 eric Rel $";
  23.  
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include "mkisofs.h"
  27. #include "iso9660.h"
  28. #include <time.h>
  29. #include <errno.h>
  30.  
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <fcntl.h>
  34.  
  35. #ifdef HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38.  
  39. #ifdef __svr4__
  40. extern char * strdup(const char *);
  41. #endif
  42.  
  43. #ifdef VMS
  44. extern char * strdup(const char *);
  45. #endif
  46.  
  47.  
  48. /* Max number of sectors we will write at  one time */
  49. #define NSECT 16
  50.  
  51. /* Counters for statistics */
  52.  
  53. static int table_size = 0;
  54. static int total_dir_size = 0;
  55. static int rockridge_size = 0;
  56. static struct directory ** pathlist;
  57. static next_path_index = 1;
  58.  
  59. /* Used to fill in some  of the information in the volume descriptor. */
  60. static struct tm *local;
  61.  
  62. /* Routines to actually write the disc.  We write sequentially so that
  63.    we could write a tape, or write the disc directly */
  64.  
  65.  
  66. #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
  67.  
  68. void FDECL2(set_721, char *, pnt, unsigned int, i)
  69. {
  70.      pnt[0] = i & 0xff;
  71.      pnt[1] = (i >> 8) &  0xff;
  72. }
  73.  
  74. void FDECL2(set_722, char *, pnt, unsigned int, i)
  75. {
  76.      pnt[0] = (i >> 8) &  0xff;
  77.      pnt[1] = i & 0xff;
  78. }
  79.  
  80. void FDECL2(set_723, char *, pnt, unsigned int, i)
  81. {
  82.      pnt[3] = pnt[0] = i & 0xff;
  83.      pnt[2] = pnt[1] = (i >> 8) &  0xff;
  84. }
  85.  
  86. void FDECL2(set_731, char *, pnt, unsigned int, i)
  87. {
  88.      pnt[0] = i & 0xff;
  89.      pnt[1] = (i >> 8) &  0xff;
  90.      pnt[2] = (i >> 16) &  0xff;
  91.      pnt[3] = (i >> 24) &  0xff;
  92. }
  93.  
  94. void FDECL2(set_732, char *, pnt, unsigned int, i)
  95. {
  96.      pnt[3] = i & 0xff;
  97.      pnt[2] = (i >> 8) &  0xff;
  98.      pnt[1] = (i >> 16) &  0xff;
  99.      pnt[0] = (i >> 24) &  0xff;
  100. }
  101.  
  102. int FDECL1(get_733, char *, p)
  103. {
  104.      return ((p[0] & 0xff)
  105.          | ((p[1] & 0xff) << 8)
  106.          | ((p[2] & 0xff) << 16)
  107.          | ((p[3] & 0xff) << 24));
  108. }
  109.  
  110. void FDECL2(set_733, char *, pnt, unsigned int, i)
  111. {
  112.      pnt[7] = pnt[0] = i & 0xff;
  113.      pnt[6] = pnt[1] = (i >> 8) &  0xff;
  114.      pnt[5] = pnt[2] = (i >> 16) &  0xff;
  115.      pnt[4] = pnt[3] = (i >> 24) &  0xff;
  116. }
  117.  
  118. void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
  119. {
  120.      while(count) 
  121.      {
  122.       int got = fwrite(buffer,size,count,file);
  123.  
  124.       if(got<=0) 
  125.       {
  126.            fprintf(stderr,"cannot fwrite %d*%d\n",size,count);
  127.            exit(1);
  128.       }
  129.       count-=got,*(char**)&buffer+=size*got;
  130.      }
  131. }
  132.  
  133. struct deferred_write
  134. {
  135.   struct deferred_write * next;
  136.   char            * table;
  137.   unsigned int          extent;
  138.   unsigned int          size;
  139.   char            * name;
  140. };
  141.  
  142. static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
  143.  
  144. static struct directory_entry * sort_dir;
  145. static struct eltorito_boot_descriptor boot_desc;
  146.  
  147. unsigned int last_extent_written  =0;
  148. static struct iso_primary_descriptor vol_desc;
  149. static path_table_index;
  150. static time_t begun;
  151.  
  152. /* We recursively walk through all of the directories and assign extent
  153.    numbers to them.  We have already assigned extent numbers to everything that
  154.    goes in front of them */
  155.  
  156. void FDECL1(assign_directory_addresses, struct directory *, node)
  157. {
  158.      int        dir_size;
  159.      struct directory * dpnt;
  160.  
  161.      dpnt = node;
  162.      
  163.      while (dpnt)
  164.      {
  165.       /*
  166.        * If we already have an extent for this (i.e. it came from
  167.        * a multisession disc), then don't reassign a new extent.
  168.        */
  169.       dpnt->path_index = next_path_index++;
  170.       if( dpnt->extent == 0 )
  171.       {
  172.            dpnt->extent = last_extent;
  173.            dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
  174.            
  175.            last_extent += dir_size;
  176.            
  177.            /* 
  178.         * Leave room for the CE entries for this directory.  Keep them
  179.         * close to the reference directory so that access will be 
  180.         * quick. 
  181.         */
  182.            if(dpnt->ce_bytes)
  183.            {
  184.             last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
  185.            }
  186.       }
  187.  
  188.       if(dpnt->subdir) 
  189.       {
  190.            assign_directory_addresses(dpnt->subdir);
  191.       }
  192.  
  193.       dpnt = dpnt->next;
  194.      }
  195. }
  196.  
  197. static void FDECL3(write_one_file, char *, filename, 
  198.            unsigned int, size, FILE *, outfile)
  199. {
  200.      char          buffer[SECTOR_SIZE * NSECT];
  201.      FILE        * infile;
  202.      int          remain;
  203.      int          use;
  204.  
  205.  
  206.      if ((infile = fopen(filename, "rb")) == NULL) 
  207.      {
  208. #if defined(sun) || defined(_AUX_SOURCE)
  209.       fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
  210. #else
  211.       fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
  212. #endif
  213.       exit(1);
  214.      }
  215.      remain = size;
  216.  
  217.      while(remain > 0)
  218.      {
  219.       use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
  220.       use = ROUND_UP(use); /* Round up to nearest sector boundary */
  221.       memset(buffer, 0, use);
  222.       if (fread(buffer, 1, use, infile) == 0) 
  223.       {
  224.            fprintf(stderr,"cannot read from %s\n",filename); 
  225.            exit(1);
  226.       }
  227.       xfwrite(buffer, 1, use, outfile);
  228.       last_extent_written += use/SECTOR_SIZE;
  229. #if 0
  230.       if((last_extent_written % 1000) < use/SECTOR_SIZE) 
  231.       {
  232.            fprintf(stderr,"%d..", last_extent_written);
  233.       }
  234. #else
  235.       if((last_extent_written % 5000) < use/SECTOR_SIZE)
  236.       {
  237.            time_t now;
  238.            time_t the_end;
  239.            double frac;
  240.            
  241.            time(&now);
  242.            frac = last_extent_written / (double)last_extent;
  243.            the_end = begun + (now - begun) / frac;
  244.            fprintf(stderr, "%6.2f%% done, estimate finish %s",
  245.                frac * 100., ctime(&the_end));
  246.       }
  247. #endif
  248.       remain -= use;
  249.      }
  250.      fclose(infile);
  251. } /* write_one_file(... */
  252.  
  253. static void FDECL1(write_files, FILE *, outfile)
  254. {
  255.      struct deferred_write * dwpnt, *dwnext;
  256.      dwpnt = dw_head;
  257.      while(dwpnt)
  258.      {
  259.       if(dwpnt->table) 
  260.       {
  261.            xfwrite(dwpnt->table,  1, ROUND_UP(dwpnt->size), outfile);
  262.            last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
  263.            table_size += dwpnt->size;
  264. /*          fprintf(stderr,"Size %d ", dwpnt->size); */
  265.            free(dwpnt->table);
  266.       } 
  267.       else 
  268.       {
  269.  
  270. #ifdef VMS
  271.            vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
  272. #else
  273.            write_one_file(dwpnt->name, dwpnt->size, outfile);
  274. #endif
  275.            free(dwpnt->name);
  276.       }
  277.  
  278.       dwnext = dwpnt;
  279.       dwpnt = dwpnt->next;
  280.       free(dwnext);
  281.      }
  282. } /* write_files(... */
  283.  
  284. #if 0
  285. static void dump_filelist()
  286. {
  287.      struct deferred_write * dwpnt;
  288.      dwpnt = dw_head;
  289.      while(dwpnt)
  290.      {
  291.       fprintf(stderr, "File %s\n",dwpnt->name);
  292.       dwpnt = dwpnt->next;
  293.      }
  294.      fprintf(stderr,"\n");
  295. }
  296. #endif
  297.  
  298. int FDECL2(compare_dirs, const void *, rr, const void *, ll) 
  299. {
  300.      char * rpnt, *lpnt;
  301.      struct directory_entry ** r, **l;
  302.      
  303.      r = (struct directory_entry **) rr;
  304.      l = (struct directory_entry **) ll;
  305.      rpnt = (*r)->isorec.name;
  306.      lpnt = (*l)->isorec.name;
  307.      
  308.      /*
  309.       *  Put the '.' and '..' entries on the head of the sorted list.
  310.       *  For normal ASCII, this always happens to be the case, but out of
  311.       *  band characters cause this not to be the case sometimes.
  312.       */
  313.      if( strcmp(rpnt, ".") == 0 ) return -1;
  314.      if( strcmp(lpnt, ".") == 0 ) return  1;
  315.  
  316.      if( strcmp(rpnt, "..") == 0 ) return -1;
  317.      if( strcmp(lpnt, "..") == 0 ) return  1;
  318.  
  319.      while(*rpnt && *lpnt) 
  320.      {
  321.       if(*rpnt == ';' && *lpnt != ';') return -1;
  322.       if(*rpnt != ';' && *lpnt == ';') return 1;
  323.       
  324.       if(*rpnt == ';' && *lpnt == ';') return 0;
  325.       
  326.       if(*rpnt == '.' && *lpnt != '.') return -1;
  327.       if(*rpnt != '.' && *lpnt == '.') return 1;
  328.       
  329.       if(*rpnt < *lpnt) return -1;
  330.       if(*rpnt > *lpnt) return 1;
  331.       rpnt++;  lpnt++;
  332.      }
  333.      if(*rpnt) return 1;
  334.      if(*lpnt) return -1;
  335.      return 0;
  336. }
  337.  
  338. void FDECL1(sort_directory, struct directory_entry **, sort_dir)
  339. {
  340.      int dcount = 0;
  341.      int i, len;
  342.      struct directory_entry * s_entry;
  343.      struct directory_entry ** sortlist;
  344.      
  345.      s_entry = *sort_dir;
  346.      while(s_entry)
  347.      {
  348.       dcount++;
  349.       s_entry = s_entry->next;
  350.      }
  351.  
  352.      /*
  353.       * OK, now we know how many there are.  Build a vector for sorting. 
  354.       */
  355.      sortlist =   (struct directory_entry **) 
  356.       e_malloc(sizeof(struct directory_entry *) * dcount);
  357.  
  358.      dcount = 0;
  359.      s_entry = *sort_dir;
  360.      while(s_entry)
  361.      {
  362.       sortlist[dcount] = s_entry;
  363.       len = s_entry->isorec.name_len[0];
  364.       s_entry->isorec.name[len] = 0;
  365.       dcount++;
  366.       s_entry = s_entry->next;
  367.      }
  368.   
  369.      qsort(sortlist, dcount, sizeof(struct directory_entry *), 
  370.        (int (*)(const void *, const void *))compare_dirs);
  371.      
  372.      /* 
  373.       * Now reassemble the linked list in the proper sorted order 
  374.       */
  375.      for(i=0; i<dcount-1; i++)
  376.      {
  377.       sortlist[i]->next = sortlist[i+1];
  378.      }
  379.  
  380.      sortlist[dcount-1]->next = NULL;
  381.      *sort_dir = sortlist[0];
  382.      
  383.      free(sortlist);
  384.      
  385. }
  386.  
  387. void generate_root_record()
  388. {
  389.      time_t ctime;
  390.      
  391.      time (&ctime);
  392.      local = localtime(&ctime);
  393.      
  394.      root_record.length[0] = 1 + sizeof(struct iso_directory_record)
  395.       - sizeof(root_record.name);
  396.      root_record.ext_attr_length[0] = 0;
  397.      set_733((char *) root_record.extent, root->extent);
  398.      set_733((char *) root_record.size, ROUND_UP(root->size));
  399.      iso9660_date(root_record.date, ctime);
  400.      root_record.flags[0] = 2;
  401.      root_record.file_unit_size[0] = 0;
  402.      root_record.interleave[0] = 0;
  403.      set_723(root_record.volume_sequence_number, DEF_VSN);
  404.      root_record.name_len[0] = 1;
  405. }
  406.  
  407. static void FDECL1(assign_file_addresses, struct directory *, dpnt)
  408. {
  409.      struct directory * finddir;
  410.      struct directory_entry * s_entry;
  411.      struct file_hash *s_hash;
  412.      struct deferred_write * dwpnt;
  413.      char whole_path[1024];
  414.      
  415.      while (dpnt)
  416.      {
  417.       s_entry = dpnt->contents;
  418.       for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
  419.       {
  420.            
  421.            /*
  422.         * If we already have an  extent for this entry,
  423.         * then don't assign a new one.  It must have come
  424.         * from a previous session on the disc.  Note that
  425.         * we don't end up scheduling the thing for writing
  426.         * either.
  427.         */
  428.            if( isonum_733(s_entry->isorec.extent) != 0 )
  429.            {
  430.             continue;
  431.            }
  432.            
  433.            /* 
  434.         * This saves some space if there are symlinks present 
  435.         */
  436.            s_hash = find_hash(s_entry->dev, s_entry->inode);
  437.            if(s_hash)
  438.            {
  439.             if(verbose)
  440.             {
  441.              fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, 
  442.                  SPATH_SEPARATOR, s_entry->name);
  443.             }
  444.             set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
  445.             set_733((char *) s_entry->isorec.size, s_hash->size);
  446.             continue;
  447.            }
  448.  
  449.            /*
  450.         * If this is for a directory that is not a . or a .. entry, 
  451.         * then look up the information for the entry.  We have already
  452.         * assigned extents for directories, so we just need to
  453.         * fill in the blanks here.
  454.         */
  455.            if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && 
  456.            s_entry->isorec.flags[0] == 2)
  457.            {
  458.             finddir = dpnt->subdir;
  459.             while(1==1)
  460.             {
  461.              if(finddir->self == s_entry) break;
  462.              finddir = finddir->next;
  463.              if(!finddir) 
  464.              {
  465.                   fprintf(stderr,"Fatal goof\n"); exit(1);
  466.              }
  467.             }
  468.             set_733((char *) s_entry->isorec.extent, finddir->extent);
  469.             s_entry->starting_block = finddir->extent;
  470.             s_entry->size = ROUND_UP(finddir->size);
  471.             total_dir_size += s_entry->size;
  472.             add_hash(s_entry);
  473.             set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size));
  474.             continue;
  475.            }
  476.  
  477.  
  478.            /*
  479.         * If this is . or .., then look up the relevant info from the
  480.         * tables.
  481.         */
  482.            if(strcmp(s_entry->name,".") == 0) 
  483.            {
  484.             set_733((char *) s_entry->isorec.extent, dpnt->extent);
  485.             
  486.             /* 
  487.              * Set these so that the hash table has the
  488.              * correct information
  489.              */
  490.             s_entry->starting_block = dpnt->extent;
  491.             s_entry->size = ROUND_UP(dpnt->size);
  492.             
  493.             add_hash(s_entry);
  494.             s_entry->starting_block = dpnt->extent;
  495.             set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size));
  496.             continue;
  497.            }
  498.  
  499.            if(strcmp(s_entry->name,"..") == 0) 
  500.            {
  501.             if(dpnt == root)
  502.             { 
  503.              total_dir_size += root->size;
  504.             }
  505.             set_733((char *) s_entry->isorec.extent, dpnt->parent->extent);
  506.             
  507.             /* 
  508.              * Set these so that the hash table has the
  509.              * correct information
  510.              */
  511.             s_entry->starting_block = dpnt->parent->extent;
  512.             s_entry->size = ROUND_UP(dpnt->parent->size);
  513.             
  514.             add_hash(s_entry);
  515.             s_entry->starting_block = dpnt->parent->extent;
  516.             set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
  517.             continue;
  518.            }
  519.  
  520.            /* 
  521.         * Some ordinary non-directory file.  Just schedule the
  522.         * file to be written.  This is all quite
  523.         * straightforward, just make a list and assign extents
  524.         * as we go.  Once we get through writing all of the
  525.         * directories, we should be ready write out these
  526.         * files
  527.         */
  528.            if(s_entry->size) 
  529.            {
  530.             dwpnt = (struct deferred_write *) 
  531.              e_malloc(sizeof(struct deferred_write));
  532.             if(dw_tail)
  533.             {
  534.              dw_tail->next = dwpnt;
  535.              dw_tail = dwpnt;
  536.             } 
  537.             else 
  538.             {
  539.              dw_head = dwpnt;
  540.              dw_tail = dwpnt;
  541.             }
  542.             if(s_entry->inode  ==  TABLE_INODE) 
  543.             {
  544.              dwpnt->table = s_entry->table;
  545.              dwpnt->name = NULL;
  546.              sprintf(whole_path,"%s%sTRANS.TBL",
  547.                  s_entry->filedir->whole_name, SPATH_SEPARATOR);
  548.             } 
  549.             else 
  550.             {
  551.              dwpnt->table = NULL;
  552.              strcpy(whole_path, s_entry->whole_name);
  553.              dwpnt->name = strdup(whole_path);
  554.             }
  555.             dwpnt->next = NULL;
  556.             dwpnt->size = s_entry->size;
  557.             dwpnt->extent = last_extent;
  558.             set_733((char *) s_entry->isorec.extent, last_extent);
  559.             s_entry->starting_block = last_extent;
  560.             add_hash(s_entry);
  561.             last_extent += ROUND_UP(s_entry->size) >> 11;
  562.             if(verbose)
  563.             {
  564.              fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
  565.                  last_extent-1, whole_path);
  566.             }
  567. #ifdef DBG_ISO
  568.             if((ROUND_UP(s_entry->size) >> 11) > 500)
  569.             {
  570.              fprintf(stderr,"Warning: large file %s\n", whole_path);
  571.              fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  572.              fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  573.              
  574.             }
  575. #endif
  576.             if(last_extent > (800000000 >> 11)) 
  577.             { 
  578.              /*
  579.               * More than 800Mb? Punt 
  580.               */
  581.              fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
  582.              fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  583.              fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  584.              exit(1);
  585.             }
  586.             continue;
  587.            }
  588.  
  589.            /*
  590.         * This is for zero-length files.  If we leave the extent 0,
  591.         * then we get screwed, because many readers simply drop files
  592.         * that have an extent of zero.  Thus we leave the size 0,
  593.         * and just assign the extent number.
  594.         */
  595.            set_733((char *) s_entry->isorec.extent, last_extent);
  596.       }
  597.       if(dpnt->subdir) 
  598.       {
  599.            assign_file_addresses(dpnt->subdir);
  600.       }
  601.       dpnt = dpnt->next;
  602.      }
  603. } /* assign_file_addresses(... */
  604.  
  605. void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
  606. {
  607.      unsigned int              ce_address = 0;
  608.      char                * ce_buffer;
  609.      unsigned int              ce_index = 0;
  610.      unsigned int              ce_size;
  611.      unsigned int              dir_index;
  612.      char                * directory_buffer;
  613.      int                  new_reclen;
  614.      struct directory_entry        * s_entry;
  615.      struct directory_entry        * s_entry_d;
  616.      unsigned int              total_size;
  617.      
  618.      total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
  619.      directory_buffer = (char *) e_malloc(total_size);
  620.      memset(directory_buffer, 0, total_size);
  621.      dir_index = 0;
  622.      
  623.      ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
  624.      ce_buffer = NULL;
  625.      
  626.      if(ce_size) 
  627.      {
  628.       ce_buffer = (char *) e_malloc(ce_size);
  629.       memset(ce_buffer, 0, ce_size);
  630.       
  631.       ce_index = 0;
  632.       
  633.       /*
  634.        * Absolute byte address of CE entries for this directory 
  635.        */
  636.       ce_address = last_extent_written + (total_size >> 11);
  637.       ce_address = ce_address << 11;
  638.      }
  639.      
  640.      s_entry = dpnt->contents;
  641.      while(s_entry) 
  642.      {
  643.  
  644.       /* 
  645.        * We do not allow directory entries to cross sector boundaries.  
  646.        * Simply pad, and then start the next entry at the next sector 
  647.        */
  648.       new_reclen = s_entry->isorec.length[0];
  649.       if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
  650.       {
  651.            dir_index = (dir_index + (SECTOR_SIZE - 1)) & 
  652.             ~(SECTOR_SIZE - 1);
  653.       }
  654.  
  655.       memcpy(directory_buffer + dir_index, &s_entry->isorec, 
  656.          sizeof(struct iso_directory_record) -
  657.          sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
  658.       dir_index += sizeof(struct iso_directory_record) - 
  659.            sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
  660.  
  661.       /*
  662.        * Add the Rock Ridge attributes, if present 
  663.        */
  664.       if(s_entry->rr_attr_size)
  665.       {
  666.            if(dir_index & 1)
  667.            {
  668.             directory_buffer[dir_index++] = 0;
  669.            }
  670.  
  671.            /* 
  672.         * If the RR attributes were too long, then write the
  673.         * CE records, as required.
  674.         */
  675.            if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) 
  676.            {
  677.             unsigned char * pnt;
  678.             int len, nbytes;
  679.             
  680.             /* 
  681.              * Go through the entire record and fix up the CE entries
  682.              * so that the extent and offset are correct 
  683.              */
  684.             
  685.             pnt = s_entry->rr_attributes;
  686.             len = s_entry->total_rr_attr_size;
  687.             while(len > 3)
  688.             {
  689. #ifdef DEBUG
  690.              if (!ce_size)
  691.              {
  692.                   fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n",
  693.                       ce_index, ce_address);
  694.              }
  695. #endif
  696.              
  697.              if(pnt[0] == 'C' && pnt[1] == 'E') 
  698.              {
  699.                   nbytes = get_733( (char *) pnt+20);
  700.                   
  701.                   if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
  702.                  SECTOR_SIZE) 
  703.                   {
  704.                    ce_index = ROUND_UP(ce_index);
  705.                   }
  706.                   
  707.                   set_733( (char *) pnt+4, 
  708.                        (ce_address + ce_index) >> 11);
  709.                   set_733( (char *) pnt+12, 
  710.                        (ce_address + ce_index) & (SECTOR_SIZE - 1));
  711.                   
  712.                   
  713.                   /* 
  714.                    * Now store the block in the ce buffer 
  715.                    */
  716.                   memcpy(ce_buffer + ce_index, 
  717.                      pnt + pnt[2], nbytes);
  718.                   ce_index += nbytes;
  719.                   if(ce_index & 1) 
  720.                   {
  721.                    ce_index++;
  722.                   }
  723.              }
  724.              len -= pnt[2];
  725.              pnt += pnt[2];
  726.             }
  727.             
  728.            }
  729.  
  730.            rockridge_size += s_entry->total_rr_attr_size;
  731.            memcpy(directory_buffer + dir_index, s_entry->rr_attributes, 
  732.               s_entry->rr_attr_size);
  733.            dir_index += s_entry->rr_attr_size;
  734.       }
  735.       if(dir_index & 1)
  736.       {
  737.            directory_buffer[dir_index++] = 0;
  738.       }
  739.       
  740.       s_entry_d = s_entry;
  741.       s_entry = s_entry->next;
  742.       
  743.       if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes);
  744.       free (s_entry_d->name);
  745.       free (s_entry_d);
  746.      }
  747.      sort_dir = NULL;
  748.  
  749.      if(dpnt->size != dir_index)
  750.      {
  751.       fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, 
  752.         dir_index, dpnt->de_name);
  753.      }
  754.  
  755.      xfwrite(directory_buffer, 1, total_size, outfile);
  756.      last_extent_written += total_size >> 11;
  757.      free(directory_buffer);
  758.  
  759.      if(ce_size)
  760.      {
  761.       if(ce_index != dpnt->ce_bytes)
  762.       {
  763.            fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
  764.                ce_index, dpnt->ce_bytes);
  765.       }
  766.       xfwrite(ce_buffer, 1, ce_size, outfile);
  767.       last_extent_written += ce_size >> 11;
  768.       free(ce_buffer);
  769.      }
  770.      
  771. } /* generate_one_directory(... */
  772.  
  773. static 
  774. void FDECL1(build_pathlist, struct directory *, node)
  775. {
  776.      struct directory * dpnt;
  777.      
  778.      dpnt = node;
  779.      
  780.      while (dpnt)
  781.      {
  782.       pathlist[dpnt->path_index] = dpnt;
  783.       if(dpnt->subdir) build_pathlist(dpnt->subdir);
  784.       dpnt = dpnt->next;
  785.      }
  786. } /* build_pathlist(... */
  787.  
  788. int FDECL2(compare_paths, void const *, r, void const *, l) 
  789. {
  790.   struct directory const *ll = *(struct directory * const *)l;
  791.   struct directory const *rr = *(struct directory * const *)r;
  792.  
  793.   if (rr->parent->path_index < ll->parent->path_index)
  794.   {
  795.        return -1;
  796.   }
  797.  
  798.   if (rr->parent->path_index > ll->parent->path_index) 
  799.   {
  800.        return 1;
  801.   }
  802.  
  803.   return strcmp(rr->self->isorec.name, ll->self->isorec.name);
  804.   
  805. } /* compare_paths(... */
  806.  
  807. void generate_path_tables()
  808. {
  809.   struct directory_entry * de;
  810.   struct directory     * dpnt;
  811.   int               fix;
  812.   int               i;
  813.   int               j;
  814.   int               namelen;
  815.   char             * npnt;
  816.   char             * npnt1;
  817.   int               tablesize;
  818.  
  819.   /*
  820.    * First allocate memory for the tables and initialize the memory 
  821.    */
  822.   tablesize = path_blocks << 11;
  823.   path_table_m = (char *) e_malloc(tablesize);
  824.   path_table_l = (char *) e_malloc(tablesize);
  825.   memset(path_table_l, 0, tablesize);
  826.   memset(path_table_m, 0, tablesize);
  827.  
  828.   /*
  829.    * Now start filling in the path tables.  Start with root directory 
  830.    */
  831.   path_table_index = 0;
  832.   pathlist = (struct directory **) e_malloc(sizeof(struct directory *) 
  833.                         * next_path_index);
  834.   memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
  835.   build_pathlist(root);
  836.  
  837.   do
  838.   {
  839.        fix = 0;
  840.        qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), 
  841.          (int (*)(const void *, const void *))compare_paths);
  842.  
  843.        for(j=1; j<next_path_index; j++)
  844.        {
  845.         if(pathlist[j]->path_index != j)
  846.         {
  847.          pathlist[j]->path_index = j;
  848.          fix++;
  849.         }
  850.        }
  851.   } while(fix);
  852.  
  853.   for(j=1; j<next_path_index; j++)
  854.   {
  855.        dpnt = pathlist[j];
  856.        if(!dpnt)
  857.        {
  858.         fprintf(stderr,"Entry %d not in path tables\n", j);
  859.         exit(1);
  860.        }
  861.        npnt = dpnt->de_name;
  862.        
  863.        /* 
  864.     * So the root comes out OK 
  865.     */
  866.        if( (*npnt == 0) || (dpnt == root) ) 
  867.        {
  868.         npnt = ".";  
  869.        }
  870.        npnt1 = strrchr(npnt, PATH_SEPARATOR);
  871.        if(npnt1) 
  872.        { 
  873.         npnt = npnt1 + 1;
  874.        }
  875.        
  876.        de = dpnt->self;
  877.        if(!de) 
  878.        {
  879.         fprintf(stderr,"Fatal goof\n"); 
  880.         exit(1);
  881.        }
  882.        
  883.        
  884.        namelen = de->isorec.name_len[0];
  885.        
  886.        path_table_l[path_table_index] = namelen;
  887.        path_table_m[path_table_index] = namelen;
  888.        path_table_index += 2;
  889.        
  890.        set_731(path_table_l + path_table_index, dpnt->extent); 
  891.        set_732(path_table_m + path_table_index, dpnt->extent); 
  892.        path_table_index += 4;
  893.        
  894.        set_721(path_table_l + path_table_index, 
  895.            dpnt->parent->path_index); 
  896.        set_722(path_table_m + path_table_index, 
  897.            dpnt->parent->path_index); 
  898.        path_table_index += 2;
  899.        
  900.        for(i =0; i<namelen; i++)
  901.        {
  902.         path_table_l[path_table_index] = de->isorec.name[i];
  903.         path_table_m[path_table_index] = de->isorec.name[i];
  904.         path_table_index++;
  905.        }
  906.        if(path_table_index & 1) 
  907.        {
  908.         path_table_index++;  /* For odd lengths we pad */
  909.        }
  910.   }
  911.   
  912.   free(pathlist);
  913.   if(path_table_index != path_table_size)
  914.   {
  915.        fprintf(stderr,"Path table lengths do not match %d %d\n",
  916.            path_table_index,
  917.            path_table_size);
  918.   }
  919. } /* generate_path_tables(... */
  920.  
  921. void
  922. FDECL3(memcpy_max, char *, to, char *, from, int, max)
  923. {
  924.   int n = strlen(from);
  925.   if (n > max)
  926.   {
  927.        n = max;
  928.   }
  929.   memcpy(to, from, n);
  930.  
  931. } /* memcpy_max(... */
  932.  
  933. int FDECL1(iso_write, FILE *, outfile)
  934. {
  935.   char                buffer[2048];
  936.   int                i;
  937.   char                iso_time[17];
  938.   int                should_write;
  939.  
  940.   time(&begun);
  941.   assign_file_addresses(root);
  942.  
  943.   memset(buffer, 0, sizeof(buffer));
  944.  
  945.   /*
  946.    * This will break  in the year  2000, I supose, but there is no good way
  947.    * to get the top two digits of the year. 
  948.    */
  949.   sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local->tm_year,
  950.       local->tm_mon+1, local->tm_mday,
  951.       local->tm_hour, local->tm_min, local->tm_sec);
  952.  
  953.   /*
  954.    * First, we output 16 sectors of all zero 
  955.    */
  956.  
  957.   for(i=0; i<16; i++)
  958.     {
  959.       xfwrite(buffer, 1, sizeof(buffer), outfile);
  960.     }
  961.  
  962.   last_extent_written += 16;
  963.  
  964.   /*
  965.    * Next we write out the primary descriptor for the disc 
  966.    */
  967.   memset(&vol_desc, 0, sizeof(vol_desc));
  968.   vol_desc.type[0] = ISO_VD_PRIMARY;
  969.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  970.   vol_desc.version[0] = 1;
  971.   
  972.   memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
  973.   memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
  974.   
  975.   memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
  976.   memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
  977.   
  978.   should_write = last_extent - session_start;
  979.   set_733((char *) vol_desc.volume_space_size, should_write);
  980.   set_723(vol_desc.volume_set_size, 1);
  981.   set_723(vol_desc.volume_sequence_number, DEF_VSN);
  982.   set_723(vol_desc.logical_block_size, 2048);
  983.   
  984.   /*
  985.    * The path tables are used by DOS based machines to cache directory
  986.    * locations 
  987.    */
  988.  
  989.   set_733((char *) vol_desc.path_table_size, path_table_size);
  990.   set_731(vol_desc.type_l_path_table, path_table[0]);
  991.   set_731(vol_desc.opt_type_l_path_table, path_table[1]);
  992.   set_732(vol_desc.type_m_path_table, path_table[2]);
  993.   set_732(vol_desc.opt_type_m_path_table, path_table[3]);
  994.  
  995.   /*
  996.    * Now we copy the actual root directory record 
  997.    */
  998.   memcpy(vol_desc.root_directory_record, &root_record, 
  999.      sizeof(struct iso_directory_record) + 1);
  1000.  
  1001.   /*
  1002.    * The rest is just fluff.  It looks nice to fill in many of these fields,
  1003.    * though.
  1004.    */
  1005.   FILL_SPACE(volume_set_id);
  1006.   if(volset_id)  memcpy_max(vol_desc.volume_set_id,  volset_id, strlen(volset_id));
  1007.  
  1008.   FILL_SPACE(publisher_id);
  1009.   if(publisher)  memcpy_max(vol_desc.publisher_id,  publisher, strlen(publisher));
  1010.  
  1011.   FILL_SPACE(preparer_id);
  1012.   if(preparer)  memcpy_max(vol_desc.preparer_id,  preparer, strlen(preparer));
  1013.  
  1014.   FILL_SPACE(application_id);
  1015.   if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
  1016.  
  1017.   FILL_SPACE(copyright_file_id);
  1018.   if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, 
  1019.                strlen(copyright));
  1020.  
  1021.   FILL_SPACE(abstract_file_id);
  1022.   if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, 
  1023.               strlen(abstract));
  1024.  
  1025.   FILL_SPACE(bibliographic_file_id);
  1026.   if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, 
  1027.                strlen(biblio));
  1028.  
  1029.   FILL_SPACE(creation_date);
  1030.   FILL_SPACE(modification_date);
  1031.   FILL_SPACE(expiration_date);
  1032.   FILL_SPACE(effective_date);
  1033.   vol_desc.file_structure_version[0] = 1;
  1034.   FILL_SPACE(application_data);
  1035.  
  1036.   memcpy(vol_desc.creation_date,  iso_time, 17);
  1037.   memcpy(vol_desc.modification_date,  iso_time, 17);
  1038.   memcpy(vol_desc.expiration_date, "0000000000000000", 17);
  1039.   memcpy(vol_desc.effective_date,  iso_time,  17);
  1040.  
  1041.   /*
  1042.    * if not a bootable cd do it the old way 
  1043.    */
  1044.   xfwrite(&vol_desc, 1, 2048, outfile);
  1045.   if (!use_eltorito) 
  1046.     {
  1047.       /*
  1048.        * For some reason, Young Minds writes this twice.  Aw, what the heck 
  1049.        */
  1050.       xfwrite(&vol_desc, 1, 2048, outfile);
  1051.     }
  1052.   else
  1053.     {
  1054.       /*
  1055.        * Next we write out the boot volume descriptor for the disc 
  1056.        */
  1057.       get_torito_desc(&boot_desc);
  1058.       xfwrite(&boot_desc, 1, 2048, outfile);
  1059.     }
  1060.   
  1061.   /* 
  1062.    * either way, we've written two more 
  1063.    */
  1064.  
  1065.   last_extent_written += 2;
  1066.  
  1067.   /*
  1068.    * Now write the end volume descriptor.  Much simpler than the other one 
  1069.    */
  1070.   memset(&vol_desc, 0, sizeof(vol_desc));
  1071.   vol_desc.type[0] = ISO_VD_END;
  1072.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  1073.   vol_desc.version[0] = 1;
  1074.   xfwrite(&vol_desc, 1, 2048, outfile);
  1075.   xfwrite(&vol_desc, 1, 2048, outfile);
  1076.   last_extent_written += 2;
  1077.  
  1078.   /*
  1079.    * Next we write the path tables 
  1080.    */
  1081.   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
  1082.   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
  1083.   last_extent_written += 2*path_blocks;
  1084.   free(path_table_l);
  1085.   free(path_table_m);
  1086.   path_table_l = NULL;
  1087.   path_table_m = NULL;
  1088.  
  1089.   /*
  1090.    * OK, all done with that crap.  Now write out the directories.
  1091.    * This is where the fur starts to fly, because we need to keep track of
  1092.    * each file as we find it and keep track of where we put it. 
  1093.    */
  1094.  
  1095. #ifdef DBG_ISO
  1096.   fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
  1097. #endif
  1098. #if 0 
  1099.  generate_one_directory(root, outfile);
  1100. #endif
  1101.   generate_iso9660_directories(root, outfile);
  1102.  
  1103.   if(extension_record) 
  1104.     {
  1105.       xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
  1106.       last_extent_written++;
  1107.     }
  1108.  
  1109.   /* 
  1110.    * Now write all of the files that we need. 
  1111.    */
  1112.   fprintf(stderr,"Total extents scheduled to be written = %d\n", 
  1113.       last_extent - session_start);
  1114.   write_files(outfile);
  1115.   
  1116.   fprintf(stderr,"Total extents actually written = %d\n", 
  1117.       last_extent_written - session_start);
  1118.   /* 
  1119.    * Hard links throw us off here 
  1120.    */
  1121.   if(should_write != last_extent - session_start)
  1122.     {
  1123.       fprintf(stderr,"Number of extents written not what was predicted.  Please fix.\n");
  1124.       fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
  1125.     }
  1126.  
  1127.   fprintf(stderr,"Total translation table size: %d\n", table_size);
  1128.   fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
  1129.   fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
  1130.   fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
  1131.  
  1132. #ifdef DEBUG
  1133.   fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
  1134.       next_extent, last_extent, last_extent_written);
  1135. #endif
  1136.  
  1137.   return 0;
  1138.  
  1139. } /* iso_write(... */
  1140.