home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / cdrom / Misc / mkisofs / tree.c < prev    next >
C/C++ Source or Header  |  1994-11-21  |  27KB  |  936 lines

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