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