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