home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / mkisofs.105 / source / write.c.orig < prev   
Text File  |  1977-12-31  |  25KB  |  813 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. #include <string.h>
  23. #include <stdlib.h>
  24. #include "mkisofs.h"
  25. #include "iso9660.h"
  26. #include <time.h>
  27. #include <errno.h>
  28.  
  29. #ifdef __svr4__
  30. extern char * strdup(const char *);
  31. #endif
  32.  
  33. #ifdef VMS
  34. extern char * strdup(const char *);
  35. #endif
  36.  
  37.  
  38. /* Max number of sectors we will write at  one time */
  39. #define NSECT 16
  40.  
  41. /* Counters for statistics */
  42.  
  43. static int table_size = 0;
  44. static int total_dir_size = 0;
  45. static int rockridge_size = 0;
  46. static struct directory ** pathlist;
  47. static next_path_index = 1;
  48.  
  49. /* Used to fill in some  of the information in the volume descriptor. */
  50. static struct tm *local;
  51.  
  52. /* Routines to actually write the disc.  We write sequentially so that
  53.    we could write a tape, or write the disc directly */
  54.  
  55.  
  56. #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
  57.  
  58. void FDECL2(set_721, char *, pnt, unsigned int, i){
  59.      pnt[0] = i & 0xff;
  60.     pnt[1] = (i >> 8) &  0xff;
  61. }
  62.  
  63. void FDECL2(set_722, char *, pnt, unsigned int, i){
  64.     pnt[0] = (i >> 8) &  0xff;
  65.      pnt[1] = i & 0xff;
  66. }
  67.  
  68. void FDECL2(set_723, char *, pnt, unsigned int, i){
  69.      pnt[3] = pnt[0] = i & 0xff;
  70.     pnt[2] = pnt[1] = (i >> 8) &  0xff;
  71. }
  72.  
  73. void FDECL2(set_731, char *, pnt, unsigned int, i){
  74.      pnt[0] = i & 0xff;
  75.     pnt[1] = (i >> 8) &  0xff;
  76.     pnt[2] = (i >> 16) &  0xff;
  77.     pnt[3] = (i >> 24) &  0xff;
  78. }
  79.  
  80. void FDECL2(set_732, char *, pnt, unsigned int, i){
  81.      pnt[3] = i & 0xff;
  82.     pnt[2] = (i >> 8) &  0xff;
  83.     pnt[1] = (i >> 16) &  0xff;
  84.     pnt[0] = (i >> 24) &  0xff;
  85. }
  86.  
  87. int FDECL1(get_733, char *, p){
  88.     return ((p[0] & 0xff)
  89.         | ((p[1] & 0xff) << 8)
  90.         | ((p[2] & 0xff) << 16)
  91.         | ((p[3] & 0xff) << 24));
  92. }
  93.  
  94. void FDECL2(set_733, char *, pnt, unsigned int, i){
  95.      pnt[7] = pnt[0] = i & 0xff;
  96.     pnt[6] = pnt[1] = (i >> 8) &  0xff;
  97.     pnt[5] = pnt[2] = (i >> 16) &  0xff;
  98.     pnt[4] = pnt[3] = (i >> 24) &  0xff;
  99. }
  100.  
  101. static FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
  102. {
  103.   while(count) {
  104.     int got=fwrite(buffer,size,count,file);
  105.     if(got<=0) fprintf(stderr,"cannot fwrite %d*%d\n",size,count),exit(1);
  106.     count-=got,*(char**)&buffer+=size*got;
  107.   }
  108. }
  109.  
  110. struct deferred_write{
  111.   struct deferred_write * next;
  112.   char * table;
  113.   unsigned int extent;
  114.   unsigned int size;
  115.   char * name;
  116. };
  117.  
  118. static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
  119.  
  120. static struct directory_entry * sort_dir;
  121.  
  122. unsigned int last_extent_written  =0;
  123. static struct iso_primary_descriptor vol_desc;
  124. static path_table_index;
  125. static time_t begun;
  126.  
  127. /* We recursively walk through all of the directories and assign extent
  128.    numbers to them.  We have already assigned extent numbers to everything that
  129.    goes in front of them */
  130.  
  131. void FDECL1(assign_directory_addresses, struct directory *, node){
  132.   struct directory * dpnt;
  133.   int dir_size;
  134.  
  135.   dpnt = node;
  136.  
  137.   while (dpnt){
  138.     dpnt->extent = last_extent;
  139.     dpnt->path_index = next_path_index++;
  140.     dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
  141.  
  142.     last_extent += dir_size;
  143.  
  144.     /* Leave room for the CE entries for this directory.  Keep them
  145.        close to the reference directory so that access will be quick. */
  146.     if(dpnt->ce_bytes)
  147.       last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
  148.  
  149.     if(dpnt->subdir) assign_directory_addresses(dpnt->subdir);
  150.     dpnt = dpnt->next;
  151.   };
  152. }
  153.  
  154. static void FDECL3(write_one_file, char *, filename, unsigned int, size, FILE *, outfile){
  155.   FILE * infile;
  156.   char buffer[SECTOR_SIZE * NSECT];
  157.   int use;
  158.   int remain;
  159.   if ((infile = fopen(filename, "rb")) == NULL) {
  160. #ifdef sun
  161.       fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
  162. #else
  163.       fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
  164. #endif
  165.       exit(1);
  166.   }
  167.   remain = size;
  168.  
  169.   while(remain > 0){
  170.       use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
  171.       use = ROUND_UP(use); /* Round up to nearest sector boundary */
  172.       memset(buffer, 0, use);
  173.       if (fread(buffer, 1, use, infile) == 0) {
  174.         fprintf(stderr,"cannot read from %s\n",filename); 
  175.         exit(1);
  176.       }
  177.       xfwrite(buffer, 1, use, outfile);
  178.       last_extent_written += use/SECTOR_SIZE;
  179. #if 0
  180.       if((last_extent_written % 1000) < use/SECTOR_SIZE) fprintf(stderr,"%d..", last_extent_written);
  181. #else
  182.       if((last_extent_written % 5000) < use/SECTOR_SIZE)
  183.       {
  184.          time_t now;
  185.          time_t the_end;
  186.          double frac;
  187.          !          time(&now);
  188.          frac = last_extent_written / (double)last_extent;
  189.          the_end = begun + (now - begun) / frac;
  190.          fprintf(stderr, "%6.2f%% done, estimate finish %s",
  191.              frac * 100., ctime(&the_end));
  192.        }
  193. #endif
  194.       remain -= use;
  195.   };
  196.   fclose(infile);
  197. }
  198.  
  199. static void FDECL1(write_files, FILE *, outfile){
  200.   struct deferred_write * dwpnt, *dwnext;
  201.   dwpnt = dw_head;
  202.   while(dwpnt){
  203.       if(dwpnt->table) {
  204.           xfwrite(dwpnt->table,  1, ROUND_UP(dwpnt->size), outfile);
  205.           last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
  206.           table_size += dwpnt->size;
  207. /*          fprintf(stderr,"Size %d ", dwpnt->size); */
  208.           free(dwpnt->table);
  209.       } else {
  210.  
  211. #ifdef VMS
  212.           vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
  213. #else
  214.           write_one_file(dwpnt->name, dwpnt->size, outfile);
  215. #endif
  216.           free(dwpnt->name);
  217.       };
  218.  
  219.           dwnext = dwpnt;
  220.           dwpnt = dwpnt->next;
  221.           free(dwnext);
  222.   };
  223. }
  224.  
  225. #if 0
  226. static void dump_filelist(){
  227.   struct deferred_write * dwpnt;
  228.   dwpnt = dw_head;
  229.   while(dwpnt){
  230.     fprintf(stderr, "File %s\n",dwpnt->name);
  231.     dwpnt = dwpnt->next;
  232.   };
  233.   fprintf(stderr,"\n");
  234. };
  235. #endif
  236.  
  237. int FDECL2(compare_dirs, const void *, rr, const void *, ll) {
  238.   char * rpnt, *lpnt;
  239.   struct directory_entry ** r, **l;
  240.  
  241.   r = (struct directory_entry **) rr;
  242.   l = (struct directory_entry **) ll;
  243.   rpnt = (*r)->isorec.name;
  244.   lpnt = (*l)->isorec.name;
  245.  
  246.   while(*rpnt && *lpnt) {
  247.     if(*rpnt == ';' && *lpnt != ';') return -1;
  248.     if(*rpnt != ';' && *lpnt == ';') return 1;
  249.     if(*rpnt == ';' && *lpnt == ';') return 0;
  250.     if(*rpnt < *lpnt) return -1;
  251.     if(*rpnt > *lpnt) return 1;
  252.     rpnt++;  lpnt++;
  253.   }
  254.   if(*rpnt) return 1;
  255.   if(*lpnt) return -1;
  256.   return 0;
  257. }
  258.  
  259. void FDECL1(sort_directory, struct directory_entry **, sort_dir){
  260.   int dcount = 0;
  261.   int i, len;
  262.   struct directory_entry * s_entry;
  263.   struct directory_entry ** sortlist;
  264.  
  265.   s_entry = *sort_dir;
  266.   while(s_entry){
  267.     dcount++;
  268.     s_entry = s_entry->next;
  269.   };
  270.   /* OK, now we know how many there are.  Build a vector for sorting. */
  271.  
  272.   sortlist =   (struct directory_entry **) 
  273.     e_malloc(sizeof(struct directory_entry *) * dcount);
  274.  
  275.   dcount = 0;
  276.   s_entry = *sort_dir;
  277.   while(s_entry){
  278.     sortlist[dcount] = s_entry;
  279.     len = s_entry->isorec.name_len[0];
  280.     s_entry->isorec.name[len] = 0;
  281.     dcount++;
  282.     s_entry = s_entry->next;
  283.   };
  284.   
  285.   qsort(sortlist, dcount, sizeof(struct directory_entry *), compare_dirs);
  286.  
  287.   /* Now reassemble the linked list in the proper sorted order */
  288.   for(i=0; i<dcount-1; i++)
  289.     sortlist[i]->next = sortlist[i+1];
  290.  
  291.   sortlist[dcount-1]->next = NULL;
  292.   *sort_dir = sortlist[0];
  293.  
  294.   free(sortlist);
  295.  
  296. }
  297.  
  298. void generate_root_record(){
  299.   time_t ctime;
  300.  
  301.   time (&ctime);
  302.   local = localtime(&ctime);
  303.  
  304.   root_record.length[0] = 1 + sizeof(struct iso_directory_record);
  305.   root_record.ext_attr_length[0] = 0;
  306.   set_733(root_record.extent, root->extent);
  307.   set_733(root_record.size, ROUND_UP(root->size));
  308.   iso9660_date(root_record.date, ctime);
  309.   root_record.flags[0] = 2;
  310.   root_record.file_unit_size[0] = 0;
  311.   root_record.interleave[0] = 0;
  312.   set_723(root_record.volume_sequence_number, 1);
  313.   root_record.name_len[0] = 1;
  314. }
  315.  
  316. static void FDECL1(assign_file_addresses, struct directory *, dpnt){
  317.   struct directory * finddir;
  318.   struct directory_entry * s_entry;
  319.   struct file_hash *s_hash;
  320.   struct deferred_write * dwpnt;
  321.   char whole_path[1024];
  322.  
  323.   while (dpnt){
  324.     s_entry = dpnt->contents;
  325.     for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next){
  326.       
  327.       /* This saves some space if there are symlinks present */
  328.       s_hash = find_hash(s_entry->dev, s_entry->inode);
  329.       if(s_hash){
  330.         if(verbose)
  331.       fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, 
  332.           SPATH_SEPARATOR, s_entry->name);
  333.         set_733(s_entry->isorec.extent, s_hash->starting_block);
  334.         set_733(s_entry->isorec.size, s_hash->size);
  335.         continue;
  336.       };
  337.       if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && 
  338.       s_entry->isorec.flags[0] == 2){
  339.     finddir = dpnt->subdir;
  340.     while(1==1){
  341.       if(finddir->self == s_entry) break;
  342.       finddir = finddir->next;
  343.       if(!finddir) {fprintf(stderr,"Fatal goof\n"); exit(1);};
  344.     };
  345.     set_733(s_entry->isorec.extent, finddir->extent);
  346.     s_entry->starting_block = finddir->extent;
  347.     s_entry->size = ROUND_UP(finddir->size);
  348.     total_dir_size += s_entry->size;
  349.     add_hash(s_entry);
  350.     set_733(s_entry->isorec.size, ROUND_UP(finddir->size));
  351.       } else {
  352.         if(strcmp(s_entry->name,".") ==0 || strcmp(s_entry->name,"..") == 0) {
  353.       if(strcmp(s_entry->name,".") == 0) {
  354.         set_733(s_entry->isorec.extent, dpnt->extent);
  355.         
  356.         /* Set these so that the hash table has the correct information */
  357.         s_entry->starting_block = dpnt->extent;
  358.         s_entry->size = ROUND_UP(dpnt->size);
  359.         
  360.         add_hash(s_entry);
  361.         s_entry->starting_block = dpnt->extent;
  362.         set_733(s_entry->isorec.size, ROUND_UP(dpnt->size));
  363.       } else {
  364.         if(dpnt == root) total_dir_size += root->size;
  365.         set_733(s_entry->isorec.extent, dpnt->parent->extent);
  366.         
  367.         /* Set these so that the hash table has the correct information */
  368.         s_entry->starting_block = dpnt->parent->extent;
  369.         s_entry->size = ROUND_UP(dpnt->parent->size);
  370.         
  371.         add_hash(s_entry);
  372.         s_entry->starting_block = dpnt->parent->extent;
  373.         set_733(s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
  374.       };
  375.         } else {
  376.       /* Now we schedule the file to be written.  This is all quite
  377.          straightforward, just make a list and assign extents as we go.
  378.          Once we get through writing all of the directories, we should
  379.          be ready write out these files */
  380.     
  381.       if(s_entry->size) {
  382.         dwpnt = (struct deferred_write *) 
  383.           e_malloc(sizeof(struct deferred_write));
  384.         if(dw_tail){
  385.           dw_tail->next = dwpnt;
  386.           dw_tail = dwpnt;
  387.         } else {
  388.           dw_head = dwpnt;
  389.           dw_tail = dwpnt;
  390.         };
  391.          if(s_entry->inode  ==  TABLE_INODE) {
  392.           dwpnt->table = s_entry->table;
  393.           dwpnt->name = NULL;
  394.         } else {
  395.           dwpnt->table = NULL;
  396.           strcpy(whole_path, s_entry->whole_name);
  397.           dwpnt->name = strdup(whole_path);
  398.         };
  399.         dwpnt->next = NULL;
  400.         dwpnt->size = s_entry->size;
  401.         dwpnt->extent = last_extent;
  402.         set_733(s_entry->isorec.extent, last_extent);
  403.         s_entry->starting_block = last_extent;
  404.         add_hash(s_entry);
  405.         last_extent += ROUND_UP(s_entry->size) >> 11;
  406.         if(verbose)
  407.           fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
  408.               last_extent-1, whole_path);
  409. #ifdef DBG_ISO
  410.         if((ROUND_UP(s_entry->size) >> 11) > 500){
  411.           fprintf(stderr,"Warning: large file %s\n", whole_path);
  412.           fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  413.           fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  414.           
  415.         };
  416. #endif
  417.         if(last_extent > (700000000 >> 11)) {  /* More than 700Mb? Punt */
  418.           fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
  419.           fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  420.           fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  421.           exit(1);
  422.         };
  423.       } else {
  424.         /*
  425.          * This is for zero-length files.  If we leave the extent 0,
  426.          * then we get screwed, because many readers simply drop files
  427.          * that have an extent of zero.  Thus we leave the size 0,
  428.          * and just assign the extent number.
  429.          */
  430.         set_733(s_entry->isorec.extent, last_extent);
  431.       }
  432.     };
  433.       };
  434.     };
  435.     if(dpnt->subdir) assign_file_addresses(dpnt->subdir);
  436.     dpnt = dpnt->next;
  437.   };
  438. }
  439.  
  440. void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile){
  441.   unsigned int total_size, ce_size;
  442.   char * directory_buffer;
  443.   char * ce_buffer;
  444.   unsigned int ce_address;
  445.   struct directory_entry * s_entry, *s_entry_d;
  446.   int new_reclen;
  447.   unsigned int dir_index, ce_index;
  448.  
  449.   total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
  450.   directory_buffer = (char *) e_malloc(total_size);
  451.   memset(directory_buffer, 0, total_size);
  452.   dir_index = 0;
  453.  
  454.   ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
  455.   ce_buffer = NULL;
  456.  
  457.   if(ce_size) {
  458.     ce_buffer = (char *) e_malloc(ce_size);
  459.     memset(ce_buffer, 0, ce_size);
  460.     
  461.     ce_index = 0;
  462.     
  463.     /* Absolute byte address of CE entries for this directory */
  464.     ce_address = last_extent_written + (total_size >> 11);
  465.     ce_address = ce_address << 11;
  466.   }
  467.  
  468.   s_entry = dpnt->contents;
  469.   while(s_entry) {
  470.  
  471.     /* We do not allow directory entries to cross sector boundaries.  Simply
  472.        pad, and then start the next entry at the next sector */
  473.     new_reclen = s_entry->isorec.length[0];
  474.     if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
  475.       dir_index = (dir_index + (SECTOR_SIZE - 1)) & 
  476.     ~(SECTOR_SIZE - 1);
  477.  
  478.     memcpy(directory_buffer + dir_index, &s_entry->isorec, 
  479.        sizeof(struct iso_directory_record) -
  480.        sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
  481.      dir_index += sizeof(struct iso_directory_record) - 
  482.       sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
  483.  
  484.     /* Add the Rock Ridge attributes, if present */
  485.     if(s_entry->rr_attr_size){
  486.       if(dir_index & 1)
  487.     directory_buffer[dir_index++] = 0;
  488.  
  489.       /* If the RR attributes were too long, then write the CE records,
  490.      as required. */
  491.       if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
  492.     unsigned char * pnt;
  493.     int len, nbytes;
  494.  
  495.     /* Go through the entire record and fix up the CE entries
  496.        so that the extent and offset are correct */
  497.  
  498.     pnt = s_entry->rr_attributes;
  499.     len = s_entry->total_rr_attr_size;
  500.     while(len > 3){
  501.       if(pnt[0] == 'C' && pnt[1] == 'E') {
  502.         nbytes = get_733(pnt+20);
  503.  
  504.         if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
  505.            SECTOR_SIZE) ce_index = ROUND_UP(ce_index);
  506.  
  507.         set_733(pnt+4, (ce_address + ce_index) >> 11);
  508.         set_733(pnt+12, (ce_address + ce_index) & (SECTOR_SIZE - 1));
  509.         
  510.  
  511.         /* Now store the block in the ce buffer */
  512.         memcpy(ce_buffer + ce_index, 
  513.            pnt + pnt[2], nbytes);
  514.         ce_index += nbytes;
  515.         if(ce_index & 1) ce_index++;
  516.       };
  517.       len -= pnt[2];
  518.       pnt += pnt[2];
  519.     };
  520.  
  521.       }
  522.  
  523.       rockridge_size += s_entry->total_rr_attr_size;
  524.       memcpy(directory_buffer + dir_index, s_entry->rr_attributes, 
  525.          s_entry->rr_attr_size);
  526.       dir_index += s_entry->rr_attr_size;
  527.     };
  528.     if(dir_index & 1)
  529.         directory_buffer[dir_index++] = 0;
  530.  
  531.     s_entry_d = s_entry;
  532.     s_entry = s_entry->next;
  533.  
  534.     if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes);
  535.     free (s_entry_d->name);
  536.     free (s_entry_d);
  537.   };
  538.   sort_dir = NULL;
  539.  
  540.   if(dpnt->size != dir_index)
  541.     fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, 
  542.         dir_index, dpnt->de_name);
  543.   xfwrite(directory_buffer, 1, total_size, outfile);
  544.   last_extent_written += total_size >> 11;
  545.   free(directory_buffer);
  546.  
  547.   if(ce_size){
  548.     if(ce_index != dpnt->ce_bytes)
  549.       fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
  550.           ce_index, dpnt->ce_bytes);
  551.     xfwrite(ce_buffer, 1, ce_size, outfile);
  552.     last_extent_written += ce_size >> 11;
  553.     free(ce_buffer);
  554.   }
  555.  
  556. }
  557.  
  558. static void FDECL1(build_pathlist, struct directory *, node){
  559.   struct directory * dpnt;
  560.  
  561.   dpnt = node;
  562.  
  563.   while (dpnt){
  564.     pathlist[dpnt->path_index] = dpnt;
  565.     if(dpnt->subdir) build_pathlist(dpnt->subdir);
  566.     dpnt = dpnt->next;
  567.   };
  568. }
  569.  
  570. int FDECL2(compare_paths, const struct directory **, r, const struct directory **, l) {
  571.   if((*r)->parent->path_index < (*l)->parent->path_index) return -1;
  572.   if((*r)->parent->path_index > (*l)->parent->path_index) return 1;
  573.   return strcmp((*r)->self->isorec.name, (*l)->self->isorec.name);
  574.   
  575. }
  576.  
  577. void generate_path_tables(){
  578.   struct directory * dpnt;
  579.   char * npnt, *npnt1;
  580.   int namelen;
  581.   struct directory_entry * de;
  582.   int fix;
  583.   int tablesize;
  584.   int i,j;
  585.   /* First allocate memory for the tables and initialize the memory */
  586.  
  587.   tablesize = path_blocks << 11;
  588.   path_table_m = (char *) e_malloc(tablesize);
  589.   path_table_l = (char *) e_malloc(tablesize);
  590.   memset(path_table_l, 0, tablesize);
  591.   memset(path_table_m, 0, tablesize);
  592.  
  593.   /* Now start filling in the path tables.  Start with root directory */
  594.   path_table_index = 0;
  595.   pathlist = (struct directory **) e_malloc(sizeof(struct directory *) * next_path_index);
  596.   memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
  597.   build_pathlist(root);
  598.  
  599.   do{
  600.     fix = 0;
  601.     qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), compare_paths);
  602.  
  603.     for(j=1; j<next_path_index; j++)
  604.       if(pathlist[j]->path_index != j){
  605.     pathlist[j]->path_index = j;
  606.     fix++;
  607.       };
  608.   } while(fix);
  609.  
  610.   for(j=1; j<next_path_index; j++){
  611.     dpnt = pathlist[j];
  612.     if(!dpnt){
  613.       fprintf(stderr,"Entry %d not in path tables\n", j);
  614.       exit(1);
  615.     };
  616.     npnt = dpnt->de_name;
  617.     if(*npnt == 0 || dpnt == root) npnt = ".";  /* So the root comes out OK */
  618.     npnt1 = strrchr(npnt, PATH_SEPARATOR);
  619.     if(npnt1) npnt = npnt1 + 1;
  620.         
  621.     de = dpnt->self;
  622.     if(!de) {fprintf(stderr,"Fatal goof\n"); exit(1);};
  623.  
  624.  
  625.     namelen = de->isorec.name_len[0];
  626.  
  627.     path_table_l[path_table_index] = namelen;
  628.     path_table_m[path_table_index] = namelen;
  629.     path_table_index += 2;
  630.     set_731(path_table_l + path_table_index, dpnt->extent); 
  631.     set_732(path_table_m + path_table_index, dpnt->extent); 
  632.     path_table_index += 4;
  633.     set_721(path_table_l + path_table_index, dpnt->parent->path_index); 
  634.     set_722(path_table_m + path_table_index, dpnt->parent->path_index); 
  635.     path_table_index += 2;
  636.     for(i =0; i<namelen; i++){
  637.       path_table_l[path_table_index] = de->isorec.name[i];
  638.       path_table_m[path_table_index] = de->isorec.name[i];
  639.       path_table_index++;
  640.     };
  641.     if(path_table_index & 1) path_table_index++;  /* For odd lengths we pad */
  642.   };
  643.   free(pathlist);
  644.   if(path_table_index != path_table_size)
  645.     fprintf(stderr,"Path table lengths do not match %d %d\n",path_table_index,
  646.         path_table_size);
  647. }
  648.  
  649. static void
  650. FDECL3(memcpy_max, char *, to, char *, from, int, max)
  651. {
  652.   int n = strlen(from);
  653.   if (n > max)
  654.     n = max;
  655.   memcpy(to, from, n);
  656. }
  657.  
  658. int FDECL1(iso_write, FILE *, outfile){
  659.   char buffer[2048];
  660.   char iso_time[17];
  661.   int should_write;
  662.   int i;
  663.  
  664.   time(&begun);
  665.   assign_file_addresses(root);
  666.  
  667.   memset(buffer, 0, sizeof(buffer));
  668.  
  669.   /* This will break  in the year  2000, I supose, but there is no good way
  670.      to get the top two digits of the year. */
  671.   sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local->tm_year,
  672.       local->tm_mon+1, local->tm_mday,
  673.       local->tm_hour, local->tm_min, local->tm_sec);
  674.  
  675.   /* First, we output 16 sectors of all zero */
  676.  
  677.   for(i=0; i<16; i++)
  678.     xfwrite(buffer, 1, sizeof(buffer), outfile);
  679.  
  680.   last_extent_written += 16;
  681.  
  682.   /* Next we write out the primary descriptor for the disc */
  683.   memset(&vol_desc, 0, sizeof(vol_desc));
  684.   vol_desc.type[0] = ISO_VD_PRIMARY;
  685.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  686.   vol_desc.version[0] = 1;
  687.  
  688.   memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
  689.   memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
  690.  
  691.   memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
  692.   memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
  693.  
  694.   should_write = last_extent;
  695.   set_733(vol_desc.volume_space_size, last_extent);
  696.   set_723(vol_desc.volume_set_size, 1);
  697.   set_723(vol_desc.volume_sequence_number, 1);
  698.   set_723(vol_desc.logical_block_size, 2048);
  699.  
  700.   /* The path tables are used by DOS based machines to cache directory
  701.      locations */
  702.  
  703.   set_733(vol_desc.path_table_size, path_table_size);
  704.   set_731(vol_desc.type_l_path_table, path_table[0]);
  705.   set_731(vol_desc.opt_type_l_path_table, path_table[1]);
  706.   set_732(vol_desc.type_m_path_table, path_table[2]);
  707.   set_732(vol_desc.opt_type_m_path_table, path_table[3]);
  708.  
  709.   /* Now we copy the actual root directory record */
  710.  
  711.   memcpy(vol_desc.root_directory_record, &root_record, 
  712.      sizeof(struct iso_directory_record) + 1);
  713.  
  714.   /* The rest is just fluff.  It looks nice to fill in many of these fields,
  715.      though */
  716.  
  717.   FILL_SPACE(volume_set_id);
  718.   if(volset_id)  memcpy_max(vol_desc.volume_set_id,  volset_id, strlen(volset_id));
  719.  
  720.   FILL_SPACE(publisher_id);
  721.   if(publisher)  memcpy_max(vol_desc.publisher_id,  publisher, strlen(publisher));
  722.  
  723.   FILL_SPACE(preparer_id);
  724.   if(preparer)  memcpy_max(vol_desc.preparer_id,  preparer, strlen(preparer));
  725.  
  726.   FILL_SPACE(application_id);
  727.   if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
  728.  
  729.   FILL_SPACE(copyright_file_id);
  730.   if(appid) memcpy_max(vol_desc.copyright_file_id, appid, strlen(appid));
  731.  
  732.   FILL_SPACE(abstract_file_id);
  733.   if(appid) memcpy_max(vol_desc.abstract_file_id, appid, strlen(appid));
  734.  
  735.   FILL_SPACE(bibliographic_file_id);
  736.   if(appid) memcpy_max(vol_desc.bibliographic_file_id, appid, strlen(appid));
  737.  
  738.   FILL_SPACE(creation_date);
  739.   FILL_SPACE(modification_date);
  740.   FILL_SPACE(expiration_date);
  741.   FILL_SPACE(effective_date);
  742.   vol_desc.file_structure_version[0] = 1;
  743.   FILL_SPACE(application_data);
  744.  
  745.   memcpy(vol_desc.creation_date,  iso_time, 17);
  746.   memcpy(vol_desc.modification_date,  iso_time, 17);
  747.   memcpy(vol_desc.expiration_date, "0000000000000000", 17);
  748.   memcpy(vol_desc.effective_date,  iso_time,  17);
  749.  
  750.   /* For some reason, Young Minds writes this twice.  Aw, what the heck */
  751.   xfwrite(&vol_desc, 1, 2048, outfile);
  752.   xfwrite(&vol_desc, 1, 2048, outfile);
  753.   last_extent_written += 2;
  754.  
  755.   /* Now write the end volume descriptor.  Much simpler than the other one */
  756.   memset(&vol_desc, 0, sizeof(vol_desc));
  757.   vol_desc.type[0] = ISO_VD_END;
  758.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  759.   vol_desc.version[0] = 1;
  760.   xfwrite(&vol_desc, 1, 2048, outfile);
  761.   xfwrite(&vol_desc, 1, 2048, outfile);
  762.   last_extent_written += 2;
  763.  
  764.   /* Next we write the path tables */
  765.   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
  766.   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
  767.   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
  768.   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
  769.   last_extent_written += 4*path_blocks;
  770.   free(path_table_l);
  771.   free(path_table_m);
  772.   path_table_l = NULL;
  773.   path_table_m = NULL;
  774.  
  775.   /* OK, all done with that crap.  Now write out the directories.
  776.      This is where the fur starts to fly, because we need to keep track of
  777.      each file as we find it and keep track of where we put it. */
  778.  
  779. #ifdef DBG_ISO
  780.   fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
  781. #endif
  782. #if 0 
  783.  generate_one_directory(root, outfile);
  784. #endif
  785.   generate_iso9660_directories(root, outfile);
  786.  
  787.   if(extension_record) {
  788.     xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
  789.     last_extent_written++;
  790.   }
  791.  
  792.   /* Now write all of the files that we need. */
  793.   fprintf(stderr,"Total extents scheduled to be written = %d\n", last_extent);
  794.   write_files(outfile);
  795.  
  796.   fprintf(stderr,"Total extents actually written = %d\n", last_extent_written);
  797.   /* Hard links throw us off here */
  798.   if(should_write != last_extent){
  799.     fprintf(stderr,"Number of extents written not what was predicted.  Please fix.\n");
  800.     fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
  801.   };
  802.  
  803.   fprintf(stderr,"Total translation table size: %d\n", table_size);
  804.   fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
  805.   fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
  806.   fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
  807. #ifdef DEBUG
  808.   fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
  809.       next_extent, last_extent, last_extent_written);
  810. #endif
  811.   return 0;
  812. }
  813.