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

  1. #include "amigadef.h"
  2. /*
  3.  * File tree.c - scan directory  tree and build memory structures for iso9660
  4.  * filesystem
  5.  
  6.    Written by Eric Youngdale (1993).
  7.  
  8.    Copyright 1993 Yggdrasil Computing, Incorporated
  9.  
  10.    This program is free software; you can redistribute it and/or modify
  11.    it under the terms of the GNU General Public License as published by
  12.    the Free Software Foundation; either version 2, or (at your option)
  13.    any later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.    You should have received a copy of the GNU General Public License
  21.    along with this program; if not, write to the Free Software
  22.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23.  
  24. /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
  25.  
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <time.h>
  29. #include <errno.h>
  30.  
  31. #ifndef VMS
  32. #if defined(HASSYSMACROS) && !defined(HASMKDEV)
  33. #include <sys/sysmacros.h>
  34. #endif
  35. #include <unistd.h>
  36. #ifdef HASMKDEV
  37. #include <sys/types.h>
  38. #include <sys/mkdev.h>
  39. #endif
  40. #else
  41. #include <sys/file.h>
  42. #include <vms/fabdef.h>
  43. #include "vms.h"
  44. extern char * strdup(const char *);
  45. #endif
  46.  
  47. #include "mkisofs.h"
  48. #include "iso9660.h"
  49.  
  50. #include <sys/stat.h>
  51.  
  52. #include "exclude.h"
  53.  
  54. #ifdef NON_UNIXFS
  55. #define S_ISLNK(m)    (0)
  56. #define S_ISSOCK(m)    (0)
  57. #define S_ISFIFO(m)    (0)
  58. #else
  59. #ifndef S_ISLNK
  60. #define S_ISLNK(m)    (((m) & S_IFMT) == S_IFLNK)
  61. #endif
  62. #ifndef S_ISSOCK
  63. #define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)
  64. #endif
  65. #endif
  66.  
  67. #ifdef __svr4__
  68. extern char * strdup(const char *);
  69. #endif
  70.  
  71. static unsigned char symlink_buff[256];
  72.  
  73. extern int verbose;
  74.  
  75. struct stat fstatbuf = {0,};  /* We use this for the artificial entries we create */
  76.  
  77. struct stat root_statbuf = {0, };  /* Stat buffer for root directory */
  78.  
  79. struct directory * reloc_dir = NULL;
  80.  
  81. void
  82. FDECL1(stat_fix, struct stat *, st)
  83. {
  84.   /* Remove the uid and gid, they will only be useful on the author's
  85.      system.  */
  86.   st->st_uid = 0;
  87.   st->st_gid = 0;
  88.   +   /* Make sure the file modes make sense.  Turn on all read bits.  Turn
  89.      on all exec/search bits if any exec/search bit is set.  Turn off
  90.      all write bits, and all special mode bits (on a r/o fs lock bits
  91.      are useless, and with uid+gid 0 don't want set-id bits, either).
  92.      */
  93.     st->st_mode |= 0444;
  94.   if (st->st_mode & 0111)
  95.     st->st_mode |= 0111;
  96.   st->st_mode &= ~07222;
  97. }
  98.  
  99. int
  100. FDECL2(stat_filter, char *, path, struct stat *, st)
  101. {
  102.   int result = stat(path, st);
  103.   if (result >= 0 && rationalize)
  104.     stat_fix(st);
  105.   return result;
  106. }
  107.  
  108. int
  109. FDECL2(lstat_filter, char *, path, struct stat *, st)
  110. {
  111.   int result = lstat(path, st);
  112.   if (result >= 0 && rationalize)
  113.     stat_fix(st);
  114.   return result;
  115. }
  116.  
  117. void FDECL1(sort_n_finish, struct directory *, this_dir)
  118. {
  119.   struct directory_entry  *s_entry, *s_entry1;
  120.   time_t current_time;
  121.   struct directory_entry * table;
  122.   int count;
  123.   int new_reclen;
  124.   char *  c;
  125.   int tablesize = 0;
  126.   char newname[34],  rootname[34];
  127.  
  128.   /* Here we can take the opportunity to toss duplicate entries from the
  129.      directory.  */
  130.  
  131.   table = NULL;
  132.  
  133.   if(fstatbuf.st_ctime == 0){
  134.       time (¤t_time);
  135.       fstatbuf.st_uid = 0;
  136.       fstatbuf.st_gid = 0;
  137.       fstatbuf.st_ctime = current_time;
  138.       fstatbuf.st_mtime = current_time;
  139.       fstatbuf.st_atime = current_time;
  140.   };
  141.  
  142.   flush_file_hash();
  143.   s_entry = this_dir->contents;
  144.   while(s_entry){
  145.       
  146.       /* First assume no conflict, and handle this case */
  147.       
  148.       if(!(s_entry1 = find_file_hash(s_entry->isorec.name))){
  149.           add_file_hash(s_entry);
  150.           s_entry = s_entry->next;
  151.           continue;
  152.       };
  153.       
  154.       if(s_entry1 == s_entry){
  155.           fprintf(stderr,"Fatal goof\n");
  156.           exit(1);
  157.       };
  158.       /* OK, handle the conflicts.  Try substitute names until we come
  159.          up with a winner */
  160.       strcpy(rootname, s_entry->isorec.name);
  161.       if(full_iso9660_filenames) {
  162.         if(strlen(rootname) > 27) rootname[27] = 0;
  163.       }
  164.       c  = strchr(rootname, '.');
  165.       if (c) *c = 0;
  166.       count = 0;
  167.       while(count < 1000){
  168.           sprintf(newname,"%s.%3.3d%s", rootname,  count,
  169.               (s_entry->isorec.flags[0] == 2 || 
  170.                omit_version_number ? "" : ";1"));
  171.  
  172. #ifdef VMS
  173.           /* Sigh.  VAXCRTL seems to be broken here */
  174.           { int ijk = 0;
  175.             while(newname[ijk]) {
  176.               if(newname[ijk] == ' ') newname[ijk] = '0';
  177.               ijk++;
  178.             };
  179.           }
  180. #endif
  181.  
  182.           if(!find_file_hash(newname)) break;
  183.           count++;
  184.       };
  185.       if(count >= 1000){
  186.           fprintf(stderr,"Unable to  generate unique  name for file %s\n", s_entry->name);
  187.           exit(1);
  188.       };
  189.       
  190.       /* OK, now we have a good replacement name.  Now decide which one
  191.          of these two beasts should get the name changed */
  192.       
  193.       if(s_entry->priority < s_entry1->priority) {
  194.           fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,  this_dir->whole_name, SPATH_SEPARATOR, s_entry->name, s_entry1->name);
  195.           s_entry->isorec.name_len[0] =  strlen(newname);
  196.           new_reclen =  sizeof(struct iso_directory_record) -
  197.               sizeof(s_entry->isorec.name) +
  198.                   strlen(newname);
  199.           if(use_RockRidge) {
  200.               if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  201.               new_reclen += s_entry->rr_attr_size;
  202.           };
  203.           if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  204.           s_entry->isorec.length[0] = new_reclen;
  205.           strcpy(s_entry->isorec.name, newname);
  206.       } else {
  207.           delete_file_hash(s_entry1);
  208.           fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,  this_dir->whole_name, SPATH_SEPARATOR, s_entry1->name, s_entry->name);
  209.           s_entry1->isorec.name_len[0] =  strlen(newname);
  210.           new_reclen =  sizeof(struct iso_directory_record) -
  211.               sizeof(s_entry1->isorec.name) +
  212.                   strlen(newname);
  213.           if(use_RockRidge) {
  214.               if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  215.               new_reclen += s_entry1->rr_attr_size;
  216.           };
  217.           if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  218.           s_entry1->isorec.length[0] = new_reclen;
  219.           strcpy(s_entry1->isorec.name, newname);
  220.           add_file_hash(s_entry1);
  221.       };
  222.       add_file_hash(s_entry);
  223.       s_entry = s_entry->next;
  224.   };
  225.  
  226.   if(generate_tables && !find_file_hash("TRANS.TBL") && (reloc_dir != this_dir)){
  227.       /* First we need to figure out how big this table is */
  228.       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
  229.           if(strcmp(s_entry->name, ".") == 0  ||
  230.              strcmp(s_entry->name, "..") == 0) continue; 
  231.           if(s_entry->table) tablesize += 35 + strlen(s_entry->table);
  232.       };
  233.           table = (struct directory_entry *) 
  234.         e_malloc(sizeof (struct directory_entry));
  235.      memset(table, 0, sizeof(struct directory_entry));
  236.     table->table = NULL;
  237.     table->next = this_dir->contents;
  238.     this_dir->contents = table;
  239.  
  240.     table->filedir = root;
  241.     table->isorec.flags[0] = 0;
  242.     table->priority  = 32768;
  243.     iso9660_date(table->isorec.date, fstatbuf.st_ctime);
  244.     table->inode = TABLE_INODE;
  245.     table->dev = (dev_t) UNCACHED_DEVICE;
  246.     set_723(table->isorec.volume_sequence_number, 1);
  247.     set_733(table->isorec.size, tablesize);
  248.     table->size = tablesize;
  249.     table->filedir = this_dir;
  250.     table->name = strdup("<translation table>");
  251.     table->table = (char *) e_malloc(ROUND_UP(tablesize));
  252.     memset(table->table, 0, ROUND_UP(tablesize));
  253.     iso9660_file_length  ("TRANS.TBL", table, 1);
  254.         
  255.     if(use_RockRidge){
  256.         fstatbuf.st_mode = 0444 | S_IFREG;
  257.         fstatbuf.st_nlink = 1;
  258.         generate_rock_ridge_attributes("",
  259.                            "TRANS.TBL", table,
  260.                            &fstatbuf, &fstatbuf, 0);
  261.     };
  262.   };
  263.  
  264.   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
  265.  
  266.       new_reclen = strlen(s_entry->isorec.name);
  267.       
  268.       if(s_entry->isorec.flags[0] ==  2){
  269.           if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) {
  270.               path_table_size += new_reclen + sizeof(struct iso_path_table) - 1;
  271.               if (new_reclen & 1) path_table_size++;
  272.           } else {
  273.               new_reclen = 1;
  274.               if (this_dir == root && strlen(s_entry->name) == 1)
  275.                   path_table_size += sizeof(struct iso_path_table);
  276.           }
  277.       };
  278.       if(path_table_size & 1) path_table_size++;  /* For odd lengths we pad */
  279.       s_entry->isorec.name_len[0] = new_reclen;
  280.  
  281.       new_reclen += 
  282.           sizeof(struct iso_directory_record) -
  283.               sizeof(s_entry->isorec.name);
  284.       
  285.       if (new_reclen & 1)    
  286.           new_reclen++;
  287.       if(use_RockRidge){
  288.           new_reclen += s_entry->rr_attr_size;
  289.  
  290.           if (new_reclen & 1)    
  291.               new_reclen++;
  292.       };
  293.       if(new_reclen > 0xff) {
  294.           fprintf(stderr,"Fatal error - RR overflow for file %s\n",
  295.               s_entry->name);
  296.           exit(1);
  297.       };
  298.       s_entry->isorec.length[0] = new_reclen;
  299.   };
  300.  
  301.   sort_directory(&this_dir->contents);
  302.  
  303.   if(table){
  304.       char buffer[1024];
  305.       count = 0;
  306.       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
  307.           if(s_entry == table) continue;
  308.           if(!s_entry->table) continue;
  309.           if(strcmp(s_entry->name, ".") == 0  ||
  310.              strcmp(s_entry->name, "..") == 0) continue;
  311.  
  312.           sprintf(buffer,"%c %-34s%s",s_entry->table[0],  
  313.               s_entry->isorec.name, s_entry->table+1);
  314.           memcpy(table->table + count, buffer, strlen(buffer));
  315.           count +=  strlen(buffer);
  316.           free(s_entry->table);
  317.           s_entry->table = NULL;
  318.     };
  319.     if(count !=  tablesize) {
  320.          fprintf(stderr,"Translation table size mismatch %d %d\n",
  321.             count, tablesize);
  322.         exit(1);
  323.     };
  324.   };
  325.  
  326.   /* Now go through the directory and figure out how large this one will be.
  327.      Do not split a directory entry across a sector boundary */
  328.   
  329.   s_entry = this_dir->contents;
  330.   this_dir->ce_bytes = 0;
  331.   while(s_entry){
  332.       new_reclen = s_entry->isorec.length[0];
  333.       if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
  334.           this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & 
  335.               ~(SECTOR_SIZE - 1);
  336.       this_dir->size += new_reclen;
  337.  
  338.       /* See if continuation entries were used on disc */
  339.       if(use_RockRidge && 
  340.          s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
  341.         unsigned char * pnt;
  342.         int len;
  343.         int nbytes;
  344.  
  345.         pnt = s_entry->rr_attributes;
  346.         len = s_entry->total_rr_attr_size;
  347.  
  348.         /* We make sure that each continuation entry record is not
  349.            split across sectors, but each file could in theory have more
  350.            than one CE, so we scan through and figure out what we need. */
  351.  
  352.         while(len > 3){
  353.           if(pnt[0] == 'C' && pnt[1] == 'E') {
  354.         nbytes = get_733(pnt+20);
  355.         
  356.         if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
  357.            SECTOR_SIZE) this_dir->ce_bytes = 
  358.              ROUND_UP(this_dir->ce_bytes);
  359.         /* Now store the block in the ce buffer */
  360.         this_dir->ce_bytes += nbytes;
  361.         if(this_dir->ce_bytes & 1) this_dir->ce_bytes++;
  362.           };
  363.           len -= pnt[2];
  364.           pnt += pnt[2];
  365.         }
  366.       }
  367.       s_entry = s_entry->next;
  368.   }
  369. }
  370.  
  371. static void generate_reloc_directory()
  372. {
  373.     int new_reclen;
  374.     time_t current_time;
  375.     struct directory_entry  *s_entry;
  376.  
  377.     /* Create an  entry for our internal tree */
  378.     time (¤t_time);
  379.     reloc_dir = (struct directory *) 
  380.         e_malloc(sizeof(struct directory));
  381.     memset(reloc_dir, 0, sizeof(struct directory));
  382.     reloc_dir->parent = root;
  383.     reloc_dir->next = root->subdir;
  384.     root->subdir = reloc_dir;
  385.     reloc_dir->depth = 1;
  386.     reloc_dir->whole_name = strdup("./rr_moved");
  387.     reloc_dir->de_name =  strdup("rr_moved");
  388.     reloc_dir->extent = 0;
  389.     
  390.     new_reclen  = strlen(reloc_dir->de_name);
  391.     
  392.     /* Now create an actual directory  entry */
  393.     s_entry = (struct directory_entry *) 
  394.         e_malloc(sizeof (struct directory_entry));
  395.     memset(s_entry, 0, sizeof(struct directory_entry));
  396.     s_entry->next = root->contents;
  397.     reloc_dir->self = s_entry;
  398.  
  399.     root->contents = s_entry;
  400.     root->contents->name = strdup(reloc_dir->de_name);
  401.     root->contents->filedir = root;
  402.     root->contents->isorec.flags[0] = 2;
  403.     root->contents->priority  = 32768;
  404.     iso9660_date(root->contents->isorec.date, current_time);
  405.     root->contents->inode = UNCACHED_INODE;
  406.     root->contents->dev = (dev_t) UNCACHED_DEVICE;
  407.     set_723(root->contents->isorec.volume_sequence_number, 1);
  408.     iso9660_file_length (reloc_dir->de_name, root->contents, 1);
  409.  
  410.     if(use_RockRidge){
  411.         fstatbuf.st_mode = 0555 | S_IFDIR;
  412.         fstatbuf.st_nlink = 2;
  413.         generate_rock_ridge_attributes("",
  414.                            "rr_moved", s_entry,
  415.                            &fstatbuf, &fstatbuf, 0);
  416.     };
  417.     
  418.     /* Now create the . and .. entries in rr_moved */
  419.     /* Now create an actual directory  entry */
  420.     s_entry = (struct directory_entry *) 
  421.         e_malloc(sizeof (struct directory_entry));
  422.     memcpy(s_entry, root->contents, 
  423.            sizeof(struct directory_entry));
  424.     s_entry->name = strdup(".");
  425.     iso9660_file_length (".", s_entry, 1);
  426.  
  427.     s_entry->filedir = reloc_dir;
  428.     reloc_dir->contents = s_entry;
  429.  
  430.     if(use_RockRidge){
  431.         fstatbuf.st_mode = 0555 | S_IFDIR;
  432.         fstatbuf.st_nlink = 2;
  433.         generate_rock_ridge_attributes("",
  434.                            ".", s_entry,
  435.                            &fstatbuf, &fstatbuf, 0);
  436.     };
  437.     
  438.     s_entry = (struct directory_entry *) 
  439.         e_malloc(sizeof (struct directory_entry));
  440.     memcpy(s_entry, root->contents, 
  441.            sizeof(struct directory_entry));
  442.     s_entry->name = strdup("..");
  443.     iso9660_file_length ("..", s_entry, 1);
  444.     s_entry->filedir = root;
  445.     reloc_dir->contents->next = s_entry;
  446.     reloc_dir->contents->next->next = NULL;
  447.     if(use_RockRidge){
  448.         fstatbuf.st_mode = 0555 | S_IFDIR;
  449.         fstatbuf.st_nlink = 2;
  450.         generate_rock_ridge_attributes("",
  451.                            "..", s_entry,
  452.                            &root_statbuf, &root_statbuf, 0);
  453.     };
  454. }
  455.  
  456. static void FDECL1(increment_nlink, struct directory_entry *, s_entry){
  457.   unsigned char * pnt;
  458.   int len, nlink;
  459.  
  460.   pnt = s_entry->rr_attributes;
  461.   len = s_entry->total_rr_attr_size;
  462.   while(len){
  463.     if(pnt[0] == 'P' && pnt[1] == 'X') {
  464.       nlink =  get_733(pnt+12);
  465.       set_733(pnt+12, nlink+1);
  466.       break;
  467.     };
  468.     len -= pnt[2];
  469.     pnt += pnt[2];
  470.   };
  471. }
  472.  
  473. void finish_cl_pl_entries(){
  474.   struct directory_entry  *s_entry, *s_entry1;
  475.   struct directory *  d_entry;
  476.  
  477.   s_entry = reloc_dir->contents;
  478.    s_entry  = s_entry->next->next;  /* Skip past . and .. */
  479.   for(; s_entry; s_entry = s_entry->next){
  480.       d_entry = reloc_dir->subdir;
  481.       while(d_entry){
  482.           if(d_entry->self == s_entry) break;
  483.           d_entry = d_entry->next;
  484.       };
  485.       if(!d_entry){
  486.           fprintf(stderr,"Unable to locate directory parent\n");
  487.           exit(1);
  488.       };
  489.  
  490.       /* First fix the PL pointer in the directory in the rr_reloc dir */
  491.       s_entry1 = d_entry->contents->next;
  492.       set_733(s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
  493.           s_entry->filedir->extent);
  494.  
  495.       /* Now fix the CL pointer */
  496.       s_entry1 = s_entry->parent_rec;
  497.  
  498.       set_733(s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
  499.           d_entry->extent);
  500.  
  501.       s_entry->filedir = reloc_dir;  /* Now we can fix this */
  502.   }
  503.   /* Next we need to modify the NLINK terms in the assorted root directory records
  504.      to account for the presence of the RR_MOVED directory */
  505.  
  506.   increment_nlink(root->self);
  507.   increment_nlink(root->self->next);
  508.   d_entry = root->subdir;
  509.   while(d_entry){
  510.     increment_nlink(d_entry->contents->next);
  511.     d_entry = d_entry->next;
  512.   };
  513. }
  514.  
  515. #ifdef ADD_FILES
  516. /* This function looks up additions. */
  517. char *
  518. FDECL3(look_up_addition,char **, newpath, char *,path, struct dirent **,de) {
  519.   char *dup_path;
  520.   char *cp;
  521.   struct file_adds *f;
  522.   struct file_adds *tmp;
  523.  
  524.   f=root_file_adds;
  525.   if (!f) return NULL;
  526.  
  527.   /* I don't trust strtok */
  528.   dup_path = strdup (path);
  529.  
  530.   cp = strtok (dup_path, SPATH_SEPARATOR);
  531.   while (cp != NULL) {
  532.     for (tmp = f->child; tmp != NULL; tmp=tmp->next) {
  533.       if (strcmp (tmp->name, cp) == 0) break;
  534.     }
  535.     if (tmp == NULL) {
  536.       /* no match */
  537.       free (dup_path);
  538.       return (NULL);
  539.     }
  540.     f = tmp;
  541.     cp = strtok(NULL, SPATH_SEPARATOR);
  542.   }
  543.   free (dup_path);
  544.  
  545.   /* looks like we found something. */
  546.   if (tmp->used >= tmp->add_count) return (NULL);
  547.  
  548.   *newpath = tmp->adds[tmp->used].path;
  549.   tmp->used++;
  550.   *de = &(tmp->de);
  551.   return (tmp->adds[tmp->used-1].name);
  552.   
  553. }
  554.  
  555. /* This function lets us add files from outside the standard file tree.
  556.    It is useful if we want to duplicate a cd, but add/replace things.
  557.    We should note that the real path will be used for exclusions. */
  558.  
  559. struct dirent *
  560. FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){
  561.   struct dirent *de;
  562.  
  563.   char *addpath;
  564.   char *name;
  565.  
  566.   de = readdir (dir);
  567.   if (de) {
  568.     return (de);
  569.   }
  570.  
  571.   name=look_up_addition (&addpath, path, &de);
  572.  
  573.   if (!name) {
  574.     return;
  575.   }
  576.  
  577.   *pathp=addpath;
  578.   
  579.   /* Now we must create the directory entry. */
  580.   /* fortuneately only the name seems to matter. */
  581.   /*
  582.   de->d_ino = -1;
  583.   de->d_off = 0;
  584.   de->d_reclen = strlen (name);
  585.   */
  586.   strncpy (de->d_name, name, NAME_MAX);
  587.   de->d_name[NAME_MAX]=0;
  588.   return (de);
  589.  
  590. }
  591. #else
  592. struct dirent *
  593. FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){
  594. struct dirent *de=readdir (dir);
  595.  
  596. de->d_name[de->d_namlen]=0;
  597.  
  598.   return (de);
  599. }
  600. #endif
  601. /*
  602.  * This function scans the directory tree, looking for files, and it makes
  603.  * note of everything that is found.  We also begin to construct the ISO9660
  604.  * directory entries, so that we can determine how large each directory is.
  605.  */
  606.  
  607. int
  608. FDECL2(scan_directory_tree,char *, path, struct directory_entry *, de){
  609.   DIR * current_dir;
  610.   char whole_path[1024];
  611.   struct dirent * d_entry;
  612.   struct directory_entry  *s_entry, *s_entry1;
  613.   struct directory * this_dir, *next_brother, *parent;
  614.   struct stat statbuf, lstatbuf;
  615.   int status, dflag;
  616.   char * cpnt;
  617.   int new_reclen;
  618.   int deep_flag;
  619.   char *old_path;
  620.  
  621.   printf("%s\n",path);
  622.  
  623.   current_dir = opendir(path);
  624.   d_entry = NULL;
  625.  
  626.   /* Apparently NFS sometimes allows you to open the directory, but
  627.      then refuses to allow you to read the contents.  Allow for this */
  628.  
  629.   old_path = path;
  630.  
  631.   if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir);
  632.  
  633.   if(!current_dir || !d_entry) {
  634.       fprintf(stderr,"Unable to open directory %s\n", path);
  635.       de->isorec.flags[0] &= ~2; /* Mark as not a directory */
  636.       if(current_dir) closedir(current_dir);
  637.       return 0;
  638.   };
  639.  
  640.   parent = de->filedir;
  641.   /* Set up the struct for the current directory, and insert it into the
  642.      tree */
  643.  
  644. #ifdef VMS
  645.   vms_path_fixup(path);
  646. #endif
  647.  
  648.   this_dir = (struct directory *) e_malloc(sizeof(struct directory));
  649.   this_dir->next = NULL;
  650.   new_reclen = 0;
  651.   this_dir->subdir = NULL;
  652.   this_dir->self = de;
  653.   this_dir->contents = NULL;
  654.   this_dir->whole_name = strdup(path);
  655.   cpnt = strrchr(path, PATH_SEPARATOR);
  656.   if(cpnt)
  657.     cpnt++;
  658.   else
  659.     cpnt = path;
  660.   this_dir->de_name = strdup(cpnt);
  661.   this_dir->size = 0;
  662.   this_dir->extent = 0;
  663.  
  664.   if(!parent || parent == root){
  665.     if (!root) {
  666.       root = this_dir;  /* First time through for root directory only */
  667.       root->depth = 0;
  668.       root->parent = root;
  669.     } else {
  670.       this_dir->depth = 1;
  671.       if(!root->subdir)
  672.     root->subdir = this_dir;
  673.       else {
  674.     next_brother = root->subdir;
  675.     while(next_brother->next) next_brother = next_brother->next;
  676.     next_brother->next = this_dir;
  677.       };
  678.       this_dir->parent = parent;
  679.     };
  680.   } else {
  681.       /* Come through here for  normal traversal of  tree */
  682. #ifdef DEBUG
  683.       fprintf(stderr,"%s(%d) ", path, this_dir->depth);
  684. #endif
  685.       if(parent->depth >  RR_relocation_depth) {
  686.           fprintf(stderr,"Directories too deep  %s\n", path);
  687.           exit(1);
  688.       };
  689.  
  690.       this_dir->parent = parent; 
  691.       this_dir->depth = parent->depth + 1;
  692.  
  693.       if(!parent->subdir)
  694.           parent->subdir = this_dir;
  695.       else {
  696.           next_brother = parent->subdir;
  697.           while(next_brother->next) next_brother = next_brother->next;
  698.           next_brother->next = this_dir;
  699.       };
  700.   };
  701.  
  702. /* Now we scan the directory itself, and look at what is inside of it. */
  703.  
  704.   dflag = 0;
  705.   while(1==1){
  706.  
  707.     /* The first time through, skip this, since we already asked for
  708.        the first entry when we opened the directory. */
  709.     if(dflag!=0)
  710.      {
  711.      d_entry = readdir_add_files(&path, old_path, current_dir);
  712.      }
  713.     dflag++;
  714.  
  715.     if(!d_entry) break;
  716.  
  717.  
  718. /*if ( (strlen(d_entry->d_name)==0) || (strcmp(d_entry->d_name,"..")==0) || (strcmp(d_entry->d_name,".")==0) )
  719.  {
  720.  continue;    /*skip fake dirs*/
  721. /* }*/
  722.  
  723.     /* OK, got a valid entry */
  724.  
  725.     /* If we do not want all files, then pitch the backups. */
  726.     if(!all_files){
  727.         if(strchr(d_entry->d_name,'~')) continue;
  728.         if(strchr(d_entry->d_name,'#')) continue;
  729.     };
  730.  
  731.     if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
  732.       fprintf(stderr, "Overflow of stat buffer\n");
  733.       exit(1);
  734.     };
  735.  
  736.     /* Generate the complete ASCII path for this file */
  737.     strcpy(whole_path, path);
  738. #ifndef VMS
  739.     if ( (whole_path[strlen(whole_path)-1] != '/') 
  740. #ifdef AMIGAdirs
  741.     && (whole_path[strlen(whole_path)-1] != ':')
  742. #endif
  743.        )
  744.       strcat(whole_path, "/");
  745. #endif
  746.     strcat(whole_path, d_entry->d_name);
  747.  
  748.  
  749.  
  750.     /* Should we exclude this file? */
  751.     if (is_excluded(whole_path)) {
  752.       if (verbose) {
  753.         fprintf(stderr, "Excluded: %s\n",whole_path);
  754.       }
  755.       continue;
  756.     }
  757. #if 0
  758.     if (verbose)  fprintf(stderr, "%s\n",whole_path);
  759. #endif
  760.     status = stat_filter(whole_path, &statbuf);
  761. #ifdef AMIGAdirs
  762. if (status) /*do we have a problem with some "#?:.." ?*/
  763.  {
  764.  if (
  765.     (whole_path[strlen(whole_path)-1]=='.')
  766.             &&
  767.     (whole_path[strlen(whole_path)-2]=='.')
  768.             &&
  769.     (whole_path[strlen(whole_path)-3]==':')
  770.     )
  771.   { 
  772.   whole_path[strlen(whole_path)-1]=0;    /*get "#?:." instead*/
  773.  
  774.   status = stat_filter(whole_path, &statbuf);
  775.  
  776.   whole_path[strlen(whole_path)]='.';    /*restore*/
  777.   }
  778.  }
  779. #endif
  780.  
  781.     lstat_filter(whole_path, &lstatbuf);
  782.  
  783.     if(this_dir == root && strcmp(d_entry->d_name, ".") == 0)
  784.       root_statbuf = statbuf;  /* Save this for later on */
  785.  
  786.     /* We do this to make sure that the root entries are consistent */
  787.     if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) {
  788.       statbuf = root_statbuf;
  789.       lstatbuf = root_statbuf;
  790.     };
  791.  
  792.     if(S_ISLNK(lstatbuf.st_mode)){
  793.  
  794.         /* Here we decide how to handle the symbolic links.  Here
  795.            we handle the general case - if we are not following
  796.            links or there is an error, then we must change
  797.            something.  If RR is in use, it is easy, we let RR
  798.            describe the file.  If not, then we punt the file. */
  799.  
  800.         if((status || !follow_links)){
  801.             if(use_RockRidge){
  802.                 status = 0;
  803.                 statbuf.st_size = 0;
  804.                 STAT_INODE(statbuf) = UNCACHED_INODE;
  805.                 statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
  806.                 statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
  807.             } else {
  808.                 if(follow_links) fprintf(stderr,
  809.                     "Unable to stat file %s - ignoring and continuing.\n",
  810.                     whole_path);
  811.                 else fprintf(stderr,
  812.                     "Symlink %s ignored - continuing.\n",
  813.                     whole_path);
  814.                 continue;  /* Non Rock Ridge discs - ignore all symlinks */
  815.             };
  816.         }
  817.         
  818.         /* Here we handle a different kind of case.  Here we have
  819.            a symlink, but we want to follow symlinks.  If we run
  820.            across a directory loop, then we need to pretend that
  821.            we are not following symlinks for this file.  If this
  822.            is the first time we have seen this, then make this
  823.            seem as if there was no symlink there in the first
  824.            place */
  825.                       
  826.         if( follow_links
  827.            && S_ISDIR(statbuf.st_mode) ) 
  828.           {
  829.         if(   strcmp(d_entry->d_name, ".")
  830.            && strcmp(d_entry->d_name, "..") )
  831.           {
  832.             if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
  833.               {
  834.             if(!use_RockRidge) 
  835.               {
  836.                 fprintf(stderr, "Already cached directory seen (%s)\n", 
  837.                     whole_path);
  838.                 continue;
  839.               }
  840.             statbuf.st_size = 0;
  841.             STAT_INODE(statbuf) = UNCACHED_INODE;
  842.             statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
  843.             statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
  844.             } else {
  845.               lstatbuf = statbuf;
  846.               add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  847.             }
  848.           }
  849.           }
  850.     }
  851.  
  852.     /*
  853.      * Add directories to the cache so that we don't waste space even
  854.      * if we are supposed to be following symlinks.
  855.      */
  856.     if( follow_links
  857.        && strcmp(d_entry->d_name, ".")
  858.        && strcmp(d_entry->d_name, "..")
  859.        && S_ISDIR(statbuf.st_mode) ) 
  860.       {
  861.         add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  862.       }
  863. #ifdef VMS
  864.     if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && 
  865.                       statbuf.st_fab_rfm != FAB$C_STMLF)) {
  866.       fprintf(stderr,"Warning - file %s has an unsupported VMS record"
  867.           " format (%d)\n",
  868.           whole_path, statbuf.st_fab_rfm);
  869.     }
  870. #endif
  871.  
  872.     if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){
  873.       fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", 
  874.           whole_path, errno);
  875.       continue;
  876.     }
  877.  
  878.  
  879.  
  880.     /* Add this so that we can detect directory loops with hard links.
  881.      If we are set up to follow symlinks, then we skip this checking. */
  882.     if(   !follow_links 
  883.        && S_ISDIR(lstatbuf.st_mode) 
  884.        && strcmp(d_entry->d_name, ".") 
  885.        && strcmp(d_entry->d_name, "..")
  886.       ) 
  887.       {
  888.         if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
  889.             fprintf(stderr,"Directory loop(file=%s) - fatal goof (%s %lx %lu).\n",
  890.                 d_entry->d_name,whole_path, (unsigned long) statbuf.st_dev,
  891.                 (unsigned long) STAT_INODE(statbuf));
  892.             exit(1);
  893.         };
  894.         add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  895.     };
  896.  
  897.  
  898.  
  899.  
  900.     if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
  901.     !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode)
  902.     && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
  903.     !S_ISDIR(lstatbuf.st_mode)) 
  904.     {
  905.       fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n",
  906.           whole_path);
  907.       continue;
  908.     };
  909.  
  910.     /* Who knows what trash this is - ignore and continue */
  911.  
  912.     if(status) {
  913.         fprintf(stderr,
  914.             "Unable to stat file %s - ignoring and continuing.\n",
  915.             whole_path);
  916.         continue; 
  917.     };
  918.  
  919.     s_entry = (struct directory_entry *) 
  920.       e_malloc(sizeof (struct directory_entry));
  921.     s_entry->next = this_dir->contents;
  922.     this_dir->contents = s_entry;
  923.     deep_flag = 0;
  924.     s_entry->table = NULL;
  925.  
  926.     s_entry->name = strdup(d_entry->d_name);
  927.     s_entry->whole_name = strdup (whole_path);
  928.  
  929.     s_entry->filedir = this_dir;
  930.     s_entry->isorec.flags[0] = 0;
  931.     s_entry->isorec.ext_attr_length[0] = 0;
  932.     iso9660_date(s_entry->isorec.date, statbuf.st_ctime);
  933.     s_entry->isorec.file_unit_size[0] = 0;
  934.     s_entry->isorec.interleave[0] = 0;
  935.     if(parent && parent ==  reloc_dir && strcmp(d_entry->d_name,  "..") == 0){
  936.         s_entry->inode = UNCACHED_INODE;
  937.         s_entry->dev = (dev_t) UNCACHED_DEVICE;
  938.         deep_flag  = NEED_PL;
  939.     } else  {
  940.         s_entry->inode = STAT_INODE(statbuf);
  941.         s_entry->dev = statbuf.st_dev;
  942.     };
  943.     set_723(s_entry->isorec.volume_sequence_number, 1);
  944.     iso9660_file_length(d_entry->d_name, s_entry, S_ISDIR(statbuf.st_mode));
  945.     s_entry->rr_attr_size = 0;
  946.     s_entry->total_rr_attr_size = 0;
  947.     s_entry->rr_attributes = NULL;
  948.  
  949.     /* Directories are assigned sizes later on */
  950.     if (!S_ISDIR(statbuf.st_mode)) {
  951.     set_733(s_entry->isorec.size, statbuf.st_size); 
  952.  
  953.     if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || 
  954.         S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode)
  955.       || S_ISLNK(lstatbuf.st_mode))
  956.       s_entry->size = 0; 
  957.     else
  958.       s_entry->size = statbuf.st_size; 
  959.     } else
  960.       s_entry->isorec.flags[0] = 2;
  961.  
  962.     if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") && 
  963.     S_ISDIR(statbuf.st_mode) && this_dir->depth >  RR_relocation_depth){
  964.           if(!reloc_dir) generate_reloc_directory();
  965.  
  966.           s_entry1 = (struct directory_entry *) 
  967.               e_malloc(sizeof (struct directory_entry));
  968.           memcpy(s_entry1, this_dir->contents, 
  969.              sizeof(struct directory_entry));
  970.           s_entry1->table = NULL;
  971.           s_entry1->name = strdup(this_dir->contents->name);
  972.           s_entry1->next = reloc_dir->contents;
  973.           reloc_dir->contents = s_entry1;
  974.           s_entry1->priority  =  32768;
  975.           s_entry1->parent_rec = this_dir->contents;
  976.  
  977.           deep_flag = NEED_RE;
  978.  
  979.           if(use_RockRidge) {
  980.               generate_rock_ridge_attributes(whole_path,
  981.                              d_entry->d_name, s_entry1,
  982.                              &statbuf, &lstatbuf, deep_flag);
  983.           }
  984.  
  985.           deep_flag = 0;
  986.  
  987.           /* We need to set this temporarily so that the parent to this is correctly
  988.              determined. */
  989.           s_entry1->filedir = reloc_dir;
  990.           scan_directory_tree(whole_path, s_entry1);
  991.           s_entry1->filedir = this_dir;
  992.  
  993.           statbuf.st_size = 0;
  994.           statbuf.st_mode &= 0777;
  995.           set_733(s_entry->isorec.size, 0);
  996.           s_entry->size = 0;
  997.           s_entry->isorec.flags[0] = 0;
  998.           s_entry->inode = UNCACHED_INODE;
  999.           deep_flag = NEED_CL;
  1000.       };
  1001.  
  1002.     if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) {
  1003.         char  buffer[2048];
  1004.         switch(lstatbuf.st_mode & S_IFMT){
  1005.         case S_IFDIR:
  1006.             sprintf(buffer,"D\t%s\n",
  1007.                 s_entry->name);
  1008.             break;
  1009. #ifndef NON_UNIXFS
  1010.         case S_IFBLK:
  1011.             sprintf(buffer,"B\t%s\t%lu %lu\n",
  1012.                 s_entry->name,
  1013.                 (unsigned long) major(statbuf.st_rdev),
  1014.                 (unsigned long) minor(statbuf.st_rdev));
  1015.             break;
  1016.         case S_IFIFO:
  1017.             sprintf(buffer,"P\t%s\n",
  1018.                 s_entry->name);
  1019.             break;
  1020.         case S_IFCHR:
  1021.             sprintf(buffer,"C\t%s\t%lu %lu\n",
  1022.                 s_entry->name,
  1023.                 (unsigned long) major(statbuf.st_rdev),
  1024.                 (unsigned long) minor(statbuf.st_rdev));
  1025.             break;
  1026.         case S_IFLNK:
  1027.             readlink(whole_path, symlink_buff, sizeof(symlink_buff));
  1028.             sprintf(buffer,"L\t%s\t%s\n",
  1029.                 s_entry->name, symlink_buff);
  1030.             break;
  1031.         case S_IFSOCK:
  1032.             sprintf(buffer,"S\t%s\n",
  1033.                 s_entry->name);
  1034.             break;
  1035. #endif /* NON_UNIXFS */
  1036.         case S_IFREG:
  1037.         default:
  1038.             sprintf(buffer,"F\t%s\n",
  1039.                 s_entry->name);
  1040.             break;
  1041.         };
  1042.         s_entry->table = strdup(buffer);
  1043.     };
  1044.     
  1045.     if(S_ISDIR(statbuf.st_mode)){
  1046.             int dflag;
  1047.         if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) {
  1048.         dflag = scan_directory_tree(whole_path, s_entry);
  1049.         /* If unable to scan directory, mark this as a non-directory */
  1050.             if(!dflag)
  1051.           lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
  1052.           }
  1053.       };
  1054.  
  1055.   if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")  == 0)
  1056.       deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
  1057.  
  1058.     /* Now figure out how much room this file will take in the directory */
  1059.  
  1060.     if(use_RockRidge) {
  1061.         generate_rock_ridge_attributes(whole_path,
  1062.                        d_entry->d_name, s_entry,
  1063.                        &statbuf, &lstatbuf, deep_flag);
  1064.         
  1065.     }
  1066.   }
  1067.   closedir(current_dir);
  1068.   sort_n_finish(this_dir);
  1069.   return 1;
  1070. }
  1071.  
  1072.  
  1073. void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
  1074.   struct directory * dpnt;
  1075.  
  1076.   dpnt = node;
  1077.  
  1078.   while (dpnt){
  1079.     generate_one_directory(dpnt, outfile);
  1080.     if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
  1081.     dpnt = dpnt->next;
  1082.   };
  1083. }
  1084.  
  1085. void FDECL1(dump_tree, struct directory *, node){
  1086.   struct directory * dpnt;
  1087.  
  1088.   dpnt = node;
  1089.  
  1090.   while (dpnt){
  1091.     fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name);
  1092.     if(dpnt->subdir) dump_tree(dpnt->subdir);
  1093.     dpnt = dpnt->next;
  1094.   };
  1095. }
  1096.  
  1097.