home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / cdrom / Misc / mkisofs / write.c < prev   
C/C++ Source or Header  |  1994-12-18  |  27KB  |  920 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.   static char left[40];
  274.   static char right[40];
  275.   char *cp;
  276.   strcpy (left, (*l)->isorec.iso_name);
  277.   strcpy (right, (*r)->isorec.iso_name);
  278.   if (((*l)->isorec.flags[0] & 2) == 0) {
  279.     if ((cp = strrchr (left, ';')) != 0) {
  280.       *cp = 0;
  281.     }
  282.   }
  283.   if (((*r)->isorec.flags[0] & 2) == 0) {
  284.     if ((cp = strrchr (right, ';')) != 0) {
  285.       *cp = 0;
  286.     }
  287.   }
  288. #ifdef AMIGA
  289.   return stringcmp(right, left);
  290. #else
  291.   return strcmp(right, left);
  292. #endif
  293. }
  294.  
  295. void FDECL1(sort_directory, struct directory_entry **, sort_dir){
  296.   int dcount = 0;
  297.   int i, len;
  298.   struct directory_entry * s_entry;
  299.   struct directory_entry ** sortlist;
  300.  
  301.   s_entry = *sort_dir;
  302.   while(s_entry){
  303.     dcount++;
  304.     s_entry = s_entry->next;
  305.   };
  306.   /* OK, now we know how many there are.  Build a vector for sorting. */
  307.  
  308.   sortlist =   (struct directory_entry **) 
  309.     malloc(sizeof(struct directory_entry *) * dcount);
  310.  
  311.   dcount = 0;
  312.   s_entry = *sort_dir;
  313.   while(s_entry){
  314.     sortlist[dcount] = s_entry;
  315.     len = s_entry->isorec.name_len[0];
  316.     /* s_entry->isorec.name[len] = 0; */
  317.     dcount++;
  318.     s_entry = s_entry->next;
  319.   };
  320.   
  321.   qsort(sortlist, dcount, sizeof(struct directory_entry *),
  322.     (int(*)(const void*, const void*)) compare_dirs);
  323.  
  324.   /* Now reassemble the linked list in the proper sorted order */
  325.   for(i=0; i<dcount-1; i++)
  326.     sortlist[i]->next = sortlist[i+1];
  327.  
  328.   sortlist[dcount-1]->next = NULL;
  329.   *sort_dir = sortlist[0];
  330.  
  331.   free(sortlist);
  332.  
  333. }
  334.  
  335. void generate_root_record(){
  336.   time_t ctime;
  337.  
  338.   time (&ctime);
  339.   local = localtime(&ctime);
  340.  
  341.   root_record.length[0] = 1 + sizeof(struct iso_directory_record);
  342.   root_record.ext_attr_length[0] = 0;
  343.   set_733(root_record.extent, root->extent);
  344.   set_733(root_record.size, ROUND_UP(root->size));
  345.   iso9660_date(root_record.date, ctime);
  346.   root_record.flags[0] = 2;
  347.   root_record.file_unit_size[0] = 0;
  348.   root_record.interleave[0] = 0;
  349.   set_723(root_record.volume_sequence_number, 1);
  350.   root_record.name_len[0] = 1;
  351. }
  352.  
  353. static int compare_extension (const struct directory_entry **e1,
  354.                   const struct directory_entry **e2)
  355. {
  356.   char *ext1, *ext2;
  357.   int res;
  358.  
  359.   if ((*e1)->isorec.iso_name[0] < 2 || (*e2)->isorec.iso_name[0] < 2)
  360.     return (*e1)->isorec.iso_name[0] - (*e2)->isorec.iso_name[0];
  361.  
  362.   ext1 = strrchr ((*e1)->isorec.iso_name, '.');
  363.   ext2 = strrchr ((*e2)->isorec.iso_name, '.');
  364.  
  365.   if (ext1 && !ext2)
  366.     return 1;
  367.   if (!ext1 && ext2)
  368.     return -1;
  369.   if (ext1 && ext2) {
  370. #ifdef AMIGA
  371.     if (res = stringcmp ((UChar*) ext1+1, (UChar*) ext2+1))
  372. #else
  373.     if ((res = strcmp (ext1+1, ext2+1)))
  374. #endif
  375.       return res;
  376.   }
  377. #ifdef AMIGA
  378.   return stringcmp ((UChar*) (*e1)->isorec.iso_name,
  379.                 (UChar*) (*e2)->isorec.iso_name);
  380. #else
  381.   return strcmp ((*e1)->isorec.iso_name,
  382.          (*e2)->isorec.iso_name);
  383. #endif
  384. }
  385.  
  386. static void FDECL1(assign_file_addresses, struct directory *, dpnt){
  387.   struct directory * finddir;
  388.   struct directory_entry * s_entry;
  389. #ifndef AMIGA
  390.   struct file_hash *s_hash;
  391. #endif
  392.   char whole_path[1024];
  393.   int entries;
  394.   struct directory_entry **entry_array;
  395.   int i;
  396. #ifdef AMIGA
  397.   static unsigned long cnt = 1;
  398. #endif
  399.  
  400.   while (dpnt){
  401.     /* compute number of entries: */
  402.     for (entries=0, s_entry=dpnt->contents; s_entry; s_entry=s_entry->next)
  403.       entries++;
  404.  
  405.     entry_array = (struct directory_entry **)
  406.       malloc (sizeof (struct directory_entry *) * entries);
  407.     for (i=0, s_entry=dpnt->contents; s_entry; s_entry=s_entry->next)
  408.       entry_array[i++] = s_entry;
  409.  
  410.     if (sort_extents)
  411.       qsort (entry_array, entries, sizeof (struct directory_entry *),
  412.              (int(*)(const void*, const void*)) compare_extension);
  413.  
  414.     for (i=0; i<entries; i++) {
  415.       s_entry = entry_array[i];
  416.  
  417. #ifndef AMIGA
  418.       /* This saves some space if there are symlinks present */
  419.       s_hash = find_hash(s_entry->dev, s_entry->inode);
  420.       if(s_hash){
  421.         if(verbose)
  422.       fprintf(stderr, "Cache hit for %s/%s\n",s_entry->filedir->de_name, 
  423.           s_entry->name);
  424.         set_733(s_entry->isorec.extent, s_hash->starting_block);
  425.         set_733(s_entry->isorec.size, s_hash->size);
  426.         continue;
  427.       };
  428. #endif
  429.       if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && 
  430.       s_entry->isorec.flags[0] == 2){
  431.     finddir = dpnt->subdir;
  432.     while(1==1){
  433.       if(finddir->self == s_entry) break;
  434.       finddir = finddir->next;
  435.       if(!finddir) {fprintf(stderr,"Fatal goof\n"); exit(1);};
  436.     };
  437.     set_733(s_entry->isorec.extent, finddir->extent);
  438.     s_entry->size = ROUND_UP(finddir->size);
  439. #ifndef AMIGA
  440.     s_entry->starting_block = finddir->extent;
  441.     add_hash(s_entry);
  442. #endif
  443.     total_dir_size += s_entry->size;
  444.     set_733(s_entry->isorec.size, ROUND_UP(finddir->size));
  445.       } else {
  446.         if(strcmp(s_entry->name,".") ==0 || strcmp(s_entry->name,"..") == 0) {
  447.       if(strcmp(s_entry->name,".") == 0) {
  448.         set_733(s_entry->isorec.extent, dpnt->extent);
  449.         
  450.         s_entry->size = ROUND_UP(dpnt->size);
  451. #ifndef AMIGA
  452.         /* Set these so that the hash table has the correct information */
  453.         s_entry->starting_block = dpnt->extent;
  454.         add_hash(s_entry);
  455.         s_entry->starting_block = dpnt->extent;
  456. #endif
  457.         set_733(s_entry->isorec.size, ROUND_UP(dpnt->size));
  458.       } else {
  459.         if(dpnt == root) total_dir_size += root->size;
  460.         set_733(s_entry->isorec.extent, dpnt->parent->extent);
  461.         
  462.         s_entry->size = ROUND_UP(dpnt->parent->size);
  463. #ifndef AMIGA        
  464.         /* Set these so that the hash table has the correct information */
  465.         s_entry->starting_block = dpnt->parent->extent;
  466.         add_hash(s_entry);        
  467.         s_entry->starting_block = dpnt->parent->extent;
  468. #endif
  469.         set_733(s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
  470.       };
  471.         } else {
  472.       /* Now we schedule the file to be written.  This is all quite
  473.          straightforward, just make a list and assign extents as we go.
  474.          Once we get through writing all of the directories, we should
  475.          be ready write out these files */
  476.     
  477. #ifdef AMIGA
  478.       if (progress_indicator) {
  479.         if ((cnt & 31) == 0 || cnt == pr_file_count) {
  480.           printf ("Assigning addresses for files (%d%% complete);"
  481.                   " free mem: %lu   \r",
  482.                     pr_file_count ? (int) ((100*cnt)/pr_file_count) : 100,
  483.               AvailMem (MEMF_ANY));
  484.           fflush (stdout);
  485.         }
  486.         cnt++;
  487.       }
  488. #endif
  489.  
  490.       if(s_entry->size) {
  491.         if (deferred_count == deferred_size) {
  492.           deferred_size += DEFERRED_CHUNK_SIZE;
  493.           if (deferred)
  494.             deferred =
  495.            realloc (deferred,
  496.                 deferred_size * sizeof (struct directory_entry*));
  497.           else
  498.             deferred =
  499.            malloc (deferred_size * sizeof (struct directory_entry*));
  500.           if (!deferred) {
  501.             fprintf (stderr, "cannot allocate file table - out of memory!\n");
  502.         exit (1);
  503.           }
  504.         }
  505.         deferred[deferred_count++] = s_entry;
  506.         set_733(s_entry->isorec.extent, last_extent);
  507. #ifndef AMIGA
  508.         s_entry->starting_block = last_extent;
  509.         add_hash(s_entry);
  510. #endif
  511. #ifdef AMIGA
  512.         if (dpnt == root &&
  513.             Stricmp ((UBYTE*) s_entry->name, (UBYTE*) "cdtv.tm") == 0) {
  514.           cdtv_trademark_extent = last_extent;
  515.           cdtv_trademark_length = s_entry->size;
  516.         }
  517. #endif
  518.  
  519.         last_extent += ROUND_UP(s_entry->size) >> 11;
  520.         if (verbose >= 2) {
  521.           char *whole = s_entry->filedir->whole_name;
  522.           char last = whole[0] ? whole[strlen(whole)-1] : 0;
  523.           fprintf(stderr,"%d %d %s%s%s\n", last_extent,
  524.               last_extent-1,
  525.               whole, (last == ':' || last == '/') ? "" : "/",
  526.               s_entry->name);
  527.         }
  528. #ifdef DBG_ISO
  529.         if((ROUND_UP(s_entry->size) >> 11) > 500){
  530.           fprintf(stderr,"Warning: large file %s\n", whole_path);
  531.           fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  532.           fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  533.           
  534.         };
  535. #endif
  536.         if(last_extent > (700000000 >> 11)) {  /* More than 700Mb? Punt */
  537.           fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
  538. #ifndef AMIGA
  539.           fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
  540. #endif
  541.           fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
  542.           exit(1);
  543.         };
  544.       } else
  545.         set_733(s_entry->isorec.extent, 0);
  546.     };
  547.       };
  548.     };
  549.     free (entry_array);
  550.     if(dpnt->subdir) assign_file_addresses(dpnt->subdir);
  551.     dpnt = dpnt->next;
  552.   };
  553. }
  554.  
  555. void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile){
  556.   unsigned int total_size;
  557.   char * directory_buffer;
  558.   struct directory_entry * s_entry, *s_entry_d;
  559.   int new_reclen;
  560.   unsigned int dir_index;
  561. #ifdef AMIGA
  562.   static unsigned long cnt = 1;
  563. #endif
  564.  
  565. #ifdef AMIGA
  566.   if (progress_indicator) {
  567.     printf ("Generate directory %lu; free mem: %lu   \r",
  568.               cnt, AvailMem (MEMF_ANY));
  569.     Delay (5);
  570.     fflush (stdout);
  571.   }
  572.   cnt++;
  573. #endif
  574.  
  575.   total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
  576.   directory_buffer = (char *) malloc(total_size);
  577.   memset(directory_buffer, 0, total_size);
  578.   dir_index = 0;
  579.  
  580.   s_entry = dpnt->contents;
  581.   while(s_entry) {
  582.  
  583.     /* We do not allow directory entries to cross sector boundaries.  Simply
  584.        pad, and then start the next entry at the next sector */
  585.     new_reclen = s_entry->isorec.length[0];
  586.     if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
  587.       dir_index = (dir_index + (SECTOR_SIZE - 1)) & 
  588.     ~(SECTOR_SIZE - 1);
  589.  
  590.     memcpy (directory_buffer + dir_index, &s_entry->isorec, ISO_REC_SIZE);
  591.     memcpy (directory_buffer + dir_index + ISO_REC_SIZE,
  592.         s_entry->isorec.iso_name,
  593.         s_entry->isorec.name_len[0]);
  594.     dir_index += ISO_REC_SIZE + s_entry->isorec.name_len[0];
  595.  
  596.     /* Add the Rock Ridge attributes, if present */
  597.     if(s_entry->rr_attr_size){
  598.       if(dir_index & 1)
  599.     directory_buffer[dir_index++] = 0;
  600.  
  601.       rockridge_size += s_entry->rr_attr_size;
  602.       memcpy(directory_buffer + dir_index, s_entry->rr_attributes, 
  603.          s_entry->rr_attr_size);
  604.       dir_index += s_entry->rr_attr_size;
  605.  
  606.     };
  607.     if(dir_index & 1)
  608.         directory_buffer[dir_index++] = 0;
  609.  
  610.     s_entry_d = s_entry;
  611.     s_entry = s_entry->next;
  612.     /* free (s_entry_d); */
  613.   };
  614.   sort_dir = NULL;
  615.  
  616.   if(dpnt->size != dir_index)
  617.     fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, 
  618.         dir_index, dpnt->de_name);
  619.   xfwrite(directory_buffer, 1, total_size, outfile);
  620.   last_extent_written += total_size >> 11;
  621.   free(directory_buffer);
  622. }
  623.  
  624. static void FDECL1(build_pathlist, struct directory *, node){
  625.   struct directory * dpnt;
  626.  
  627.   dpnt = node;
  628.  
  629.   while (dpnt){
  630.     pathlist[dpnt->path_index] = dpnt;
  631.     if(dpnt->subdir) build_pathlist(dpnt->subdir);
  632.     dpnt = dpnt->next;
  633.   };
  634. }
  635.  
  636. int FDECL2(compare_paths, const struct directory **, r, const struct directory **, l) {
  637.   if((*r)->parent->path_index < (*l)->parent->path_index) return -1;
  638.   if((*r)->parent->path_index > (*l)->parent->path_index) return 1;
  639. #ifdef AMIGA
  640.   return Stricmp ((STRPTR) (*r)->self->isorec.iso_name,
  641.             (STRPTR) (*l)->self->isorec.iso_name);
  642. #else
  643.   return strcmp((*r)->self->isorec.iso_name, (*l)->self->isorec.iso_name);
  644. #endif
  645.   
  646. }
  647.  
  648. void generate_path_tables(){
  649.   struct directory * dpnt;
  650.   int namelen;
  651.   struct directory_entry * de;
  652.   int fix;
  653.   int tablesize;
  654.   int i,j;
  655.   /* First allocate memory for the tables and initialize the memory */
  656.  
  657.   tablesize = path_blocks << 11;
  658.   path_table_m = (char *) malloc(tablesize);
  659.   path_table_l = (char *) malloc(tablesize);
  660.   memset(path_table_l, 0, tablesize);
  661.   memset(path_table_m, 0, tablesize);
  662.  
  663.   /* Now start filling in the path tables.  Start with root directory */
  664.   path_table_index = 0;
  665.   pathlist = (struct directory **) malloc(sizeof(struct directory *) * next_path_index);
  666.   memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
  667.   build_pathlist(root);
  668.  
  669.   do{
  670.     fix = 0;
  671.     qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
  672.       (int(*)(const void*, const void*)) compare_paths);
  673.  
  674.     for(j=1; j<next_path_index; j++)
  675.       if(pathlist[j]->path_index != j){
  676.     pathlist[j]->path_index = j;
  677.     fix++;
  678.       };
  679.   } while(fix);
  680.  
  681.   for(j=1; j<next_path_index; j++){
  682.     dpnt = pathlist[j];
  683.     if(!dpnt){
  684.       fprintf(stderr,"Entry %d not in path tables\n", j);
  685.       exit(1);
  686.     };
  687.         
  688.     de = dpnt->self;
  689.     if(!de) {fprintf(stderr,"Fatal goof\n"); exit(1);};
  690.  
  691.  
  692.     namelen = de->isorec.name_len[0];
  693.  
  694.     path_table_l[path_table_index] = namelen;
  695.     path_table_m[path_table_index] = namelen;
  696.     path_table_index += 2;
  697.     set_731(path_table_l + path_table_index, dpnt->extent); 
  698.     set_732(path_table_m + path_table_index, dpnt->extent); 
  699.     path_table_index += 4;
  700.     set_721(path_table_l + path_table_index, dpnt->parent->path_index); 
  701.     set_722(path_table_m + path_table_index, dpnt->parent->path_index); 
  702.     path_table_index += 2;
  703.     for(i =0; i<namelen; i++){
  704. #ifdef AMIGA
  705.       path_table_l[path_table_index] = ToUpper (de->isorec.iso_name[i]);
  706.       path_table_m[path_table_index] = ToUpper (de->isorec.iso_name[i]);
  707. #else
  708.       path_table_l[path_table_index] = toupper (de->isorec.iso_name[i]);
  709.       path_table_m[path_table_index] = toupper (de->isorec.iso_name[i]);
  710. #endif
  711.       path_table_index++;
  712.     };
  713.     if(path_table_index & 1) path_table_index++;  /* For odd lengths we pad */
  714.   };
  715.   free(pathlist);
  716.   if(path_table_index != path_table_size)
  717.     fprintf(stderr,"Path table lengths do not match %d %d\n",path_table_index,
  718.         path_table_size);
  719. }
  720.  
  721. void preallocate_space (FILE *outfile)
  722. {
  723.   long oldpos = ftell (outfile);
  724.   int numblocks = last_extent - oldpos / 2048;
  725.   int i;
  726.   static char empty[2048];
  727.  
  728.   fprintf (stderr, "Preallocating space for output file...\n");
  729.   memset (empty, 0, sizeof (empty));
  730.   for (i=0; i<numblocks; i++)
  731.     if (!fwrite (empty, sizeof (empty), 1, outfile)) {
  732.       fprintf (stderr, ">>>> WARNING: not enough space on output device\n");
  733.       break;
  734.     }
  735.   if (fseek (outfile, oldpos, SEEK_SET) == -1) {
  736.     fprintf (stderr, "cannot seek() on output file\n");
  737.     perror ("");
  738.     exit (1);
  739.   }
  740. }
  741.  
  742. int FDECL2(iso_write, FILE *, outfile, char *, volid){
  743.   static char buffer[2048];
  744.   char iso_time[17];
  745.   int should_write;
  746.   int i;
  747.  
  748.   if (verbose)
  749.     printf ("assigning file addresses\n");
  750.  
  751.   assign_file_addresses(root);
  752.   if (progress_indicator)
  753.     putchar ('\n');
  754.  
  755.   memset(buffer, 0, sizeof(buffer));
  756.  
  757.   /* This will break  in the year  2000, I supose, but there is no good way
  758.      to get the top two digits of the year. */
  759.   sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local->tm_year,
  760.       local->tm_mon+1, local->tm_mday,
  761.       local->tm_hour, local->tm_min, local->tm_sec);
  762.  
  763.   /* First, we output 16 sectors of all zero */
  764.  
  765.   for(i=0; i<16; i++)
  766.     xfwrite(buffer, 1, sizeof(buffer), outfile);
  767.  
  768.   last_extent_written += 16;
  769.  
  770.   /* Next we write out the primary descriptor for the disc */
  771.   memset(&vol_desc, 0, sizeof(vol_desc));
  772.   vol_desc.type[0] = ISO_VD_PRIMARY;
  773.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  774.   vol_desc.version[0] = 1;
  775.  
  776.   memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
  777.   if (system_identifier)
  778.     memcpy(vol_desc.system_id, system_identifier, strlen (system_identifier));
  779.   else
  780. #ifdef AMIGA
  781.     memcpy(vol_desc.system_id, "AMIGA", sizeof("AMIGA"));
  782. #else
  783. #ifdef __QNX__
  784.     memcpy(vol_desc.system_id, "QNX", sizeof("QNX"));
  785. #else
  786.     memcpy(vol_desc.system_id, "LINUX", sizeof("LINUX"));
  787. #endif
  788. #endif
  789.  
  790.   memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
  791.   memcpy(vol_desc.volume_id, volid, strlen(volid));
  792.  
  793.   should_write = last_extent;
  794.   set_733(vol_desc.volume_space_size, last_extent);
  795.   set_723(vol_desc.volume_set_size, 1);
  796.   set_723(vol_desc.volume_sequence_number, 1);
  797.   set_723(vol_desc.logical_block_size, 2048);
  798.  
  799.   /* The path tables are used by DOS based machines to cache directory
  800.      locations */
  801.  
  802.   set_733(vol_desc.path_table_size, path_table_size);
  803.   set_731(vol_desc.type_l_path_table, path_table[0]);
  804.   set_731(vol_desc.opt_type_l_path_table, path_table[1]);
  805.   set_732(vol_desc.type_m_path_table, path_table[2]);
  806.   set_732(vol_desc.opt_type_m_path_table, path_table[3]);
  807.  
  808.   /* Now we copy the actual root directory record */
  809.  
  810.   memcpy(vol_desc.root_directory_record, &root_record, 
  811.      sizeof(struct iso_directory_record) + 1);
  812.  
  813.   /* The rest is just fluff.  It looks nice to fill in many of these fields,
  814.      though */
  815.  
  816.   FILL_SPACE(volume_set_id);
  817.   FILL_SPACE(publisher_id);
  818.   if(publisher)  memcpy(vol_desc.publisher_id,  publisher, strlen(publisher));
  819.   FILL_SPACE(preparer_id);
  820.   if(preparer)  memcpy(vol_desc.preparer_id,  preparer, strlen(preparer));
  821.   FILL_SPACE(application_id);
  822.   FILL_SPACE(copyright_file_id);
  823.   FILL_SPACE(abstract_file_id);
  824.   FILL_SPACE(bibliographic_file_id);
  825.   FILL_SPACE(creation_date);
  826.   FILL_SPACE(modification_date);
  827.   FILL_SPACE(expiration_date);
  828.   FILL_SPACE(effective_date);
  829.   vol_desc.file_structure_version[0] = 1;
  830.   FILL_NULL(application_data);
  831.   if (cdtv_trademark_file) {
  832.     vol_desc.application_data[1] = 'F';
  833.     vol_desc.application_data[2] = 'S';
  834.     vol_desc.application_data[5] = 'T';
  835.     vol_desc.application_data[6] = 'M';
  836.     vol_desc.application_data[8] = 0x14;
  837.     vol_desc.application_data[11] = cdtv_trademark_length >> 8;
  838.     vol_desc.application_data[12] = cdtv_trademark_length & 255;
  839.     vol_desc.application_data[13] = cdtv_trademark_extent >> 24;
  840.     vol_desc.application_data[14] = (cdtv_trademark_extent >> 16) & 255;
  841.     vol_desc.application_data[15] = (cdtv_trademark_extent >> 8) & 255;
  842.     vol_desc.application_data[16] = cdtv_trademark_extent & 255;
  843.   }
  844.  
  845.   memcpy(vol_desc.creation_date,  iso_time, 16);
  846.   memcpy(vol_desc.modification_date,  iso_time, 16);
  847.   memcpy(vol_desc.expiration_date, "0000000000000000", 16);
  848.   memcpy(vol_desc.effective_date,  iso_time,  16);
  849.  
  850.   /* For some reason, Young Minds writes this twice.  Aw, what the heck */
  851.   xfwrite(&vol_desc, 1, 2048, outfile);
  852.   xfwrite(&vol_desc, 1, 2048, outfile);
  853.   
  854.   last_extent_written += 2;
  855.  
  856.   /* Now write the end volume descriptor.  Much simpler than the other one */
  857.   memset(&vol_desc, 0, sizeof(vol_desc));
  858.   vol_desc.type[0] = ISO_VD_END;
  859.   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  860.   vol_desc.version[0] = 1;
  861.   xfwrite(&vol_desc, 1, 2048, outfile);
  862.   xfwrite(&vol_desc, 1, 2048, outfile);
  863.   last_extent_written += 2;
  864.  
  865.   /* Next we write the path tables */
  866.   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
  867.   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
  868.   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
  869.   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
  870.   last_extent_written += 4*path_blocks;
  871.   free(path_table_l);
  872.   free(path_table_m);
  873.   path_table_l = NULL;
  874.   path_table_m = NULL;
  875.  
  876.   /* OK, all done with that crap.  Now write out the directories.
  877.      This is where the fur starts to fly, because we need to keep track of
  878.      each file as we find it and keep track of where we put it. */
  879.  
  880. #ifdef DBG_ISO
  881.   fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
  882. #endif
  883. #if 0 
  884.  generate_one_directory(root, outfile);
  885. #endif
  886.   if (verbose)
  887.     printf ("writing directories\n");
  888.  
  889.   generate_iso9660_directories(root, outfile);
  890.   if (progress_indicator)
  891.     putchar ('\n');
  892.  
  893.   if(extension_record) xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
  894.   
  895.   /* Now write all of the files that we need. */
  896.   if (verbose)
  897.     printf ("writing files\n");
  898.  
  899.   fprintf(stderr,"Total extents being written = %d\n", last_extent);
  900.   if (preallocate)
  901.     preallocate_space (outfile);
  902.   write_files(outfile);
  903.  
  904.   /* Hard links throw us off here */
  905.   if(should_write != last_extent){
  906.     fprintf(stderr,"Number of extents written not what was predicted.  Please fix.\n");
  907.     fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
  908.   };
  909.   fprintf(stderr,"Total translation table size: %d\n", table_size);
  910.   fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
  911.   fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
  912.   fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
  913. #ifdef DEBUG
  914.   fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
  915.       next_extent, last_extent, last_extent_written);
  916. #endif
  917.  
  918.   return 0;
  919. }
  920.