home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / mkisofs.105 / source / write.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  31KB  |  914 lines

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