tree.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:53k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*
  2.  * File tree.c - scan directory  tree and build memory structures for iso9660
  3.  * filesystem
  4.    Written by Eric Youngdale (1993).
  5.    Copyright 1993 Yggdrasil Computing, Incorporated
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17. static char rcsid[] ="$Id: tree.c,v 1.29 1999/03/07 17:41:19 eric Exp $";
  18. /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
  19. #include "config.h"
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include <errno.h>
  24. #include <unixstd.h>
  25. #include <fctldefs.h>
  26. #include <device.h>
  27. #ifdef VMS
  28. #include <sys/file.h>
  29. #include <vms/fabdef.h>
  30. #include "vms.h"
  31. extern char * strdup(const char *);
  32. #endif
  33. /*
  34.  * Autoconf should be able to figure this one out for us and let us know
  35.  * whether the system has memmove or not.
  36.  */
  37. # ifndef HAVE_MEMMOVE
  38. #  define memmove(d, s, n) bcopy ((s), (d), (n))
  39. # endif
  40. #include "mkisofs.h"
  41. #include "iso9660.h"
  42. #include "match.h"
  43. #include <sys/stat.h>
  44. #include "exclude.h"
  45. #ifdef DOESNT_WORK
  46. /*
  47.  * This is the dead code
  48.  */
  49. #ifdef NON_UNIXFS
  50. #define S_ISLNK(m) (0)
  51. #define S_ISSOCK(m) (0)
  52. #define S_ISFIFO(m) (0)
  53. #else
  54. #ifndef S_ISLNK
  55. #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  56. #endif
  57. #ifndef S_ISSOCK
  58. # ifdef S_IFSOCK
  59. #   define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
  60. # else
  61. #   define S_ISSOCK(m) (0)
  62. # endif
  63. #endif
  64. #endif
  65. #else
  66. /*
  67.  * This is the new code
  68.  */
  69. #include <statdefs.h>
  70. #endif
  71. #ifdef USE_LIBSCHILY
  72. #include <standard.h>
  73. #endif
  74. #ifdef __SVR4
  75. extern char * strdup(const char *);
  76. #endif
  77. static unsigned char symlink_buff[256];
  78. static char * filetype __PR((int t));
  79. static char * rstr __PR((char *s1, char *s2));
  80. static void stat_fix __PR((struct stat * st));
  81. static void generate_reloc_directory __PR((void));
  82. static void DECL(attach_dot_entries, (struct directory * dirnode,
  83.    struct stat * parent_stat));
  84. static void DECL(delete_directory, (struct directory * parent, struct directory * child));
  85. extern int verbose;
  86. struct stat fstatbuf = {0,};  /* We use this for the artificial entries we create */
  87. struct stat root_statbuf = {0, };  /* Stat buffer for root directory */
  88. struct directory * reloc_dir = NULL;
  89. static char *
  90. filetype(t)
  91. int t;
  92. {
  93. if ((t & S_IFMT) == 0) /* 0 (unallocated) */
  94. return ("unallocated");
  95. if (S_ISFIFO(t)) /* 1 */
  96. return ("fifo");
  97. if (S_ISCHR(t)) /* 2 */
  98. return ("chr");
  99. if ((t & S_IFMT) == 3) /* 3 (multiplexed chr) */
  100. return ("multiplexed chr");
  101. if (S_ISDIR(t)) /* 4 */
  102. return ("dir");
  103. if ((t & S_IFMT) == 5) /* 5 (named file) */
  104. return ("named file");
  105. if (S_ISBLK(t)) /* 6 */
  106. return ("blk");
  107. if ((t & S_IFMT) == 7) /* 7 (multiplexed blk) */
  108. return ("multiplexed blk");
  109. if (S_ISREG(t)) /* 8 */
  110. return ("regular file");
  111. if (S_ISCNT(t)) /* 9 */
  112. return ("contiguous file");
  113. if (S_ISLNK(t)) /* 10 */
  114. return ("symlink");
  115. if ((t & S_IFMT) == 11) /* 11 (Solaris shadow inode) */
  116. return ("Solaris shadow inode");
  117. if (S_ISSOCK(t)) /* 12 */
  118. return ("socket");
  119. if (S_ISDOOR(t)) /* 13 */
  120. return ("door");
  121. if ((t & S_IFMT) == 14) /* 14 (CPIO acl) */
  122. return ("CPIO acl");
  123. if ((t & S_IFMT) == 15) /* 15 (unused) */
  124. return ("unused 15");
  125. return ("BLETCH");
  126. }
  127. /*
  128.  * Check if s1 ends in strings s2
  129.  */
  130. static char *
  131. rstr(s1, s2)
  132. char *s1;
  133. char *s2;
  134. {
  135. int l1;
  136. int l2;
  137. l1 = strlen(s1);
  138. l2 = strlen(s2);
  139. if (l2 > l1)
  140. return ((char *)NULL);
  141. if (strcmp(&s1[l1 - l2], s2) == 0)
  142. return (&s1[l1 - l2]);
  143. return ((char *)NULL);
  144. }
  145. static void
  146. FDECL1(stat_fix, struct stat *, st)
  147. {
  148.   /* Remove the uid and gid, they will only be useful on the author's
  149.      system.  */
  150.   st->st_uid = 0;
  151.   st->st_gid = 0;
  152.  /*
  153.   * Make sure the file modes make sense.  Turn on all read bits.  Turn
  154.   * on all exec/search bits if any exec/search bit is set.  Turn off
  155.   * all write bits, and all special mode bits (on a r/o fs lock bits
  156.   * are useless, and with uid+gid 0 don't want set-id bits, either).
  157.   */
  158.   st->st_mode |= 0444;
  159. #ifndef _WIN32 /* make all file "executable" */
  160.   if (st->st_mode & 0111)
  161. #endif /* _WIN32 */
  162.     st->st_mode |= 0111;
  163.   st->st_mode &= ~07222;
  164. }
  165. int
  166. FDECL2(stat_filter, char *, path, struct stat *, st)
  167. {
  168.   int result = stat(path, st);
  169.   if (result >= 0 && rationalize)
  170.     stat_fix(st);
  171.   return result;
  172. }
  173. int
  174. FDECL2(lstat_filter, char *, path, struct stat *, st)
  175. {
  176.   int result = lstat(path, st);
  177.   if (result >= 0 && rationalize)
  178.     stat_fix(st);
  179.   return result;
  180. }
  181. static int FDECL1(sort_n_finish, struct directory *, this_dir)
  182. {
  183.   struct directory_entry  * s_entry;
  184.   struct directory_entry  * s_entry1;
  185.   struct directory_entry  * table;
  186.   int     count;
  187.   int     d1;
  188.   int     d2;
  189.   int     d3;
  190.   int     new_reclen;
  191.   char  *  c;
  192.   int     status = 0;
  193.   int     tablesize = 0;
  194.   char     newname[34];
  195.   char     rootname[34];
  196.   /* Here we can take the opportunity to toss duplicate entries from the
  197.      directory.  */
  198.   /* ignore if it's hidden */
  199.   if(this_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
  200.     {
  201.       return 0;
  202.     }
  203.   table = NULL;
  204.   init_fstatbuf();
  205.   /*
  206.    * If we had artificially created this directory, then we might be
  207.    * missing the required '.' entries.  Create these now if we need
  208.    * them.
  209.    */
  210.   if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) != 
  211.       (DIR_HAS_DOT | DIR_HAS_DOTDOT) )
  212.     {
  213.       attach_dot_entries(this_dir, &fstatbuf);
  214.     }
  215.   flush_file_hash();
  216.   s_entry = this_dir->contents;
  217.   while(s_entry)
  218.     {
  219.     /* ignore if it's hidden */
  220.     if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
  221.       {
  222. s_entry = s_entry->next;
  223. continue;
  224.       }
  225.   
  226.       /*
  227.        * First assume no conflict, and handle this case 
  228.        */
  229.       if(!(s_entry1 = find_file_hash(s_entry->isorec.name)))
  230. {
  231.   add_file_hash(s_entry);
  232.   s_entry = s_entry->next;
  233.   continue;
  234. }
  235.   
  236.       if(s_entry1 == s_entry)
  237. {
  238. #ifdef USE_LIBSCHILY
  239.   comerrno(EX_BAD, "Fatal goof, file '%s' already in hash table.n", s_entry->isorec.name);
  240. #else
  241.   fprintf(stderr, "Fatal goof, file '%s' already in hash table.n", s_entry->isorec.name);
  242.   exit(1);
  243. #endif
  244. }
  245.       
  246.       /* 
  247.        * OK, handle the conflicts.  Try substitute names until we come
  248.        * up with a winner 
  249.        */
  250.       strcpy(rootname, s_entry->isorec.name);
  251.       if(full_iso9660_filenames) 
  252. {
  253. /*
  254.  * 27 is 30 chars minus the 3 characters we are
  255.  * appending below to create unique filenames.
  256.  */
  257.   if(strlen(rootname) > 27) rootname[27] = 0;
  258. }
  259.       /*
  260.        * Strip off the non-significant part of the name so that we are left
  261.        * with a sensible root filename.  If we don't find a '.', then try
  262.        * a ';'.
  263.        */
  264.       c  = strchr(rootname, '.');
  265. /*
  266.  * In case we ever allow more than on dot, only modify the section
  267.  * past the last dot if the file name starts with a dot.
  268.  */
  269.       if (c != NULL && c == rootname && c != strrchr(rootname, '.'))
  270. c = strrchr(rootname, '.');
  271.       if (c) 
  272. *c = 0;
  273.       else
  274. {
  275.   c  = strchr(rootname, ';');
  276.   if (c) *c = 0;
  277. }
  278.       for(d1 = 0; d1 < 36; d1++)
  279. {
  280.   for(d2 = 0; d2 < 36; d2++)
  281.     {
  282.       for(d3 = 0; d3 < 36; d3++)
  283. {
  284.   sprintf(newname,"%s.%c%c%c%s", rootname,  
  285.   (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10),
  286.   (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10),
  287.   (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10),
  288.   (s_entry->isorec.flags[0] == 2 || 
  289.    omit_version_number ? "" : ";1"));
  290.   
  291. #ifdef VMS
  292.   /* Sigh.  VAXCRTL seems to be broken here */
  293.   {
  294.     int ijk = 0;
  295.     while(newname[ijk]) 
  296.       {
  297. if(newname[ijk] == ' ') newname[ijk] = '0';
  298. ijk++;
  299.       }
  300.   }
  301. #endif
  302.   
  303.   if(!find_file_hash(newname)) goto got_valid_name;
  304. }
  305.     }
  306. }
  307.       /*
  308.        * If we fell off the bottom here, we were in real trouble.
  309.        */
  310. #ifdef USE_LIBSCHILY
  311.       comerrno(EX_BAD, "Unable to generate unique name for file %sn", s_entry->name);
  312. #else
  313.       fprintf(stderr,"Unable to generate unique name for file %sn", s_entry->name);
  314.       exit(1);
  315. #endif
  316. got_valid_name:      
  317.       /* 
  318.        * OK, now we have a good replacement name.  Now decide which one
  319.        * of these two beasts should get the name changed 
  320.        */
  321.       if(s_entry->priority < s_entry1->priority) 
  322. {
  323.   if( verbose > 0 )
  324.     {
  325.       fprintf(stderr,"Using %s for  %s%s%s (%s)n", newname,  
  326.       this_dir->whole_name, SPATH_SEPARATOR, 
  327.       s_entry->name, s_entry1->name);
  328.     }
  329.   s_entry->isorec.name_len[0] =  strlen(newname);
  330.   new_reclen =  offsetof(struct iso_directory_record, name[0]) +
  331.     strlen(newname);
  332.   if(use_RockRidge) 
  333.     {
  334.       if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  335.       new_reclen += s_entry->rr_attr_size;
  336.     }
  337.   if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  338.   s_entry->isorec.length[0] = new_reclen;
  339.   strcpy(s_entry->isorec.name, newname);
  340. }
  341.       else 
  342. {
  343.   delete_file_hash(s_entry1);
  344.   if( verbose > 0 )
  345.     {
  346.       fprintf(stderr,"Using %s for  %s%s%s (%s)n", newname,  
  347.       this_dir->whole_name, SPATH_SEPARATOR, 
  348.       s_entry1->name, s_entry->name);
  349.     }
  350.   s_entry1->isorec.name_len[0] =  strlen(newname);
  351.   new_reclen =  offsetof(struct iso_directory_record, name[0]) +
  352.     strlen(newname);
  353.   if(use_RockRidge) 
  354.     {
  355.       if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  356.       new_reclen += s_entry1->rr_attr_size;
  357.     }
  358.   if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
  359.   s_entry1->isorec.length[0] = new_reclen;
  360.   strcpy(s_entry1->isorec.name, newname);
  361.   add_file_hash(s_entry1);
  362. }
  363.       add_file_hash(s_entry);
  364.       s_entry = s_entry->next;
  365.     }
  366.   if(generate_tables 
  367.      && !find_file_hash(trans_tbl) 
  368.      && (reloc_dir != this_dir)
  369.      && (this_dir->extent == 0) )
  370.     {
  371.       /* 
  372.        * First we need to figure out how big this table is 
  373.        */
  374.       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  375. {
  376.   if(strcmp(s_entry->name, ".") == 0  ||
  377.      strcmp(s_entry->name, "..") == 0) continue; 
  378.   if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue;
  379.   if(s_entry->table) tablesize += 35 + strlen(s_entry->table);
  380. }
  381.     }
  382.   if( tablesize > 0 )
  383.     {
  384.       table = (struct directory_entry *) 
  385. e_malloc(sizeof (struct directory_entry));
  386.       memset(table, 0, sizeof(struct directory_entry));
  387.       table->table = NULL;
  388.       table->next = this_dir->contents;
  389.       this_dir->contents = table;
  390.       
  391.       table->filedir = root;
  392.       table->isorec.flags[0] = 0;
  393.       table->priority  = 32768;
  394.       iso9660_date(table->isorec.date, fstatbuf.st_mtime);
  395.       table->inode = TABLE_INODE;
  396.       table->dev = (dev_t) UNCACHED_DEVICE;
  397.       set_723(table->isorec.volume_sequence_number, volume_sequence_number);
  398.       set_733((char *) table->isorec.size, tablesize);
  399.       table->size = tablesize;
  400.       table->filedir = this_dir;
  401.       if (jhide_trans_tbl)
  402.        table->de_flags    |= INHIBIT_JOLIET_ENTRY;
  403. /*      table->name = strdup("<translation table>");*/
  404.       table->name = strdup(trans_tbl);
  405.       table->table = (char *) e_malloc(ROUND_UP(tablesize));
  406.       memset(table->table, 0, ROUND_UP(tablesize));
  407.       iso9660_file_length  (trans_tbl, table, 0);
  408.       
  409.       if(use_RockRidge)
  410. {
  411.   fstatbuf.st_mode = 0444 | S_IFREG;
  412.   fstatbuf.st_nlink = 1;
  413.   generate_rock_ridge_attributes("",
  414.  trans_tbl, table,
  415.  &fstatbuf, &fstatbuf, 0);
  416. }
  417.     }
  418.   
  419.   /*
  420.    * We have now chosen the 8.3 names and we should now know the length
  421.    * of every entry in the directory.
  422.    */
  423.   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  424.     {
  425.       /* skip if it's hidden */
  426.       if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
  427. {
  428.   continue;
  429. }
  430.       new_reclen = strlen(s_entry->isorec.name);
  431.   
  432.       /*
  433.        * First update the path table sizes for directories.
  434.        */
  435.       if(s_entry->isorec.flags[0] ==  2)
  436. {
  437.   if (strcmp(s_entry->name,".") != 0 && strcmp(s_entry->name,"..") != 0)
  438.     {
  439.       path_table_size += new_reclen + offsetof(struct iso_path_table, name[0]);
  440.       if (new_reclen & 1) path_table_size++;
  441.     }
  442.   else 
  443.     {
  444.       new_reclen = 1;
  445.       if (this_dir == root && strlen(s_entry->name) == 1)
  446. {
  447.   path_table_size += new_reclen + offsetof(struct iso_path_table, name[0]);
  448. }
  449.     }
  450. }
  451.       if(path_table_size & 1) path_table_size++;  /* For odd lengths we pad */
  452.       s_entry->isorec.name_len[0] = new_reclen;
  453.       
  454.       new_reclen += offsetof(struct iso_directory_record, name[0]);
  455.       
  456.       if (new_reclen & 1)
  457. new_reclen++;
  458.       
  459.       new_reclen += s_entry->rr_attr_size;
  460.       
  461.       if (new_reclen & 1) new_reclen++;
  462.       
  463.       if(new_reclen > 0xff) 
  464. {
  465. #ifdef USE_LIBSCHILY
  466.   comerrno(EX_BAD, "Fatal error - RR overflow for file %sn",
  467.   s_entry->name);
  468. #else
  469.   fprintf(stderr,"Fatal error - RR overflow for file %sn",
  470.   s_entry->name);
  471.   exit(1);
  472. #endif
  473. }
  474.       s_entry->isorec.length[0] = new_reclen;
  475.     }
  476.   status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
  477.   if( status > 0 )
  478.     {
  479. #ifdef USE_LIBSCHILY
  480.       comerrno(EX_BAD, "Unable to sort directory %sn", 
  481.       this_dir->whole_name);
  482. #else
  483.       fprintf(stderr, "Unable to sort directory %sn", 
  484.       this_dir->whole_name);
  485. exit(1);
  486. #endif
  487.     }
  488.   /*
  489.    * If we are filling out a TRANS.TBL, generate the entries that will
  490.    * go in the thing.
  491.    */
  492.   if(table)
  493.     {
  494.       count = 0;
  495.       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
  496. if(s_entry == table) continue;
  497. if(!s_entry->table) continue;
  498. if(strcmp(s_entry->name, ".") == 0  ||
  499.    strcmp(s_entry->name, "..") == 0) continue;
  500. if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue;
  501. /*
  502.  * Warning: we cannot use the return value of sprintf because
  503.  * old BSD based sprintf() implementations will return
  504.  * a pointer to the result instead of a count.
  505.  */
  506. sprintf(table->table + count, "%c %-34s%s",
  507. s_entry->table[0],
  508. s_entry->isorec.name, s_entry->table+1);
  509. count += strlen(table->table + count);
  510. free(s_entry->table);
  511. /* for a memory file, set s_entry->table to the correct data -
  512.    which is stored in s_entry->whole_name */
  513. if (s_entry->de_flags & MEMORY_FILE) {
  514.     s_entry->table = s_entry->whole_name;
  515.     s_entry->whole_name = NULL;
  516. } else {
  517.     s_entry->table = NULL;
  518. }
  519.       }
  520.       if(count !=  tablesize) 
  521. {
  522. #ifdef USE_LIBSCHILY
  523.   comerrno(EX_BAD, "Translation table size mismatch %d %dn",
  524.   count, tablesize);
  525. #else
  526.   fprintf(stderr,"Translation table size mismatch %d %dn",
  527.   count, tablesize);
  528.   exit(1);
  529. #endif
  530. }
  531.     }
  532.   /* 
  533.    * Now go through the directory and figure out how large this one will be.
  534.    * Do not split a directory entry across a sector boundary 
  535.    */
  536.   s_entry = this_dir->contents;
  537.   this_dir->ce_bytes = 0;
  538.   while(s_entry)
  539.     {
  540.       /* skip if it's hidden */
  541.       if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
  542. s_entry = s_entry->next;
  543. continue;
  544.       }
  545.       new_reclen = s_entry->isorec.length[0];
  546.       if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
  547. this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & 
  548. ~(SECTOR_SIZE - 1);
  549.       this_dir->size += new_reclen;
  550.       /* See if continuation entries were used on disc */
  551.       if(use_RockRidge && 
  552.  s_entry->rr_attr_size != s_entry->total_rr_attr_size) 
  553. {
  554.   unsigned char * pnt;
  555.   int len;
  556.   int nbytes;
  557.   
  558.   pnt = s_entry->rr_attributes;
  559.   len = s_entry->total_rr_attr_size;
  560.   
  561.   /*
  562.    * We make sure that each continuation entry record is not
  563.    * split across sectors, but each file could in theory have more
  564.    * than one CE, so we scan through and figure out what we need. 
  565.    */
  566.   while(len > 3)
  567.     {
  568.       if(pnt[0] == 'C' && pnt[1] == 'E') 
  569. {
  570.   nbytes = get_733((char *) pnt+20);
  571.   
  572.   if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
  573.      SECTOR_SIZE) this_dir->ce_bytes = 
  574.     ROUND_UP(this_dir->ce_bytes);
  575.   /* Now store the block in the ce buffer */
  576.   this_dir->ce_bytes += nbytes;
  577.   if(this_dir->ce_bytes & 1) this_dir->ce_bytes++;
  578. }
  579.       len -= pnt[2];
  580.       pnt += pnt[2];
  581.     }
  582. }
  583.       s_entry = s_entry->next;
  584.     }
  585.   return status;
  586. }
  587. static void generate_reloc_directory()
  588. {
  589. time_t current_time;
  590. struct directory_entry  *s_entry;
  591. /* Create an  entry for our internal tree */
  592. time (&current_time);
  593. reloc_dir = (struct directory *) 
  594. e_malloc(sizeof(struct directory));
  595. memset(reloc_dir, 0, sizeof(struct directory));
  596. reloc_dir->parent = root;
  597. reloc_dir->next = root->subdir;
  598. root->subdir = reloc_dir;
  599. reloc_dir->depth = 1;
  600. if (hide_rr_moved) {
  601. reloc_dir->whole_name = strdup("./.rr_moved");
  602. reloc_dir->de_name =  strdup(".rr_moved");
  603. } else {
  604. reloc_dir->whole_name = strdup("./rr_moved");
  605. reloc_dir->de_name =  strdup("rr_moved");
  606. }
  607. reloc_dir->extent = 0;
  608. /* Now create an actual directory  entry */
  609. s_entry = (struct directory_entry *) 
  610. e_malloc(sizeof (struct directory_entry));
  611. memset(s_entry, 0, sizeof(struct directory_entry));
  612. s_entry->next = root->contents;
  613. reloc_dir->self = s_entry;
  614. /*
  615.  * The rr_moved entry will not appear in the Joliet tree.
  616.  */
  617. reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
  618. s_entry->de_flags    |= INHIBIT_JOLIET_ENTRY;
  619. /*
  620.  * Hiding RR_MOVED seems not to be possible.....
  621.  */
  622. #ifdef HIDE_RR
  623. reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
  624. s_entry->de_flags    |= INHIBIT_ISO9660_ENTRY;
  625. #endif
  626. root->contents = s_entry;
  627. root->contents->name = strdup(reloc_dir->de_name);
  628. root->contents->filedir = root;
  629. root->contents->isorec.flags[0] = 2;
  630. root->contents->priority  = 32768;
  631. iso9660_date(root->contents->isorec.date, current_time);
  632. root->contents->inode = UNCACHED_INODE;
  633. root->contents->dev = (dev_t) UNCACHED_DEVICE;
  634. set_723(root->contents->isorec.volume_sequence_number, volume_sequence_number);
  635. iso9660_file_length (reloc_dir->de_name, root->contents, 1);
  636. init_fstatbuf();
  637. if(use_RockRidge) {
  638. fstatbuf.st_mode = 0555 | S_IFDIR;
  639. fstatbuf.st_nlink = 2;
  640. generate_rock_ridge_attributes("",
  641.        hide_rr_moved?".rr_moved":"rr_moved",
  642. s_entry, &fstatbuf, &fstatbuf, 0);
  643. };
  644. /* Now create the . and .. entries in rr_moved */
  645. /* Now create an actual directory  entry */
  646. attach_dot_entries(reloc_dir, &root_statbuf);
  647. }
  648. /* 
  649.  * Function: attach_dot_entries
  650.  *
  651.  * Purpose: Create . and .. entries for a new directory.
  652.  *
  653.  * Notes: Only used for artificial directories that
  654.  * we are creating.
  655.  */
  656. static void FDECL2(attach_dot_entries, struct directory *, dirnode,
  657.    struct stat *, parent_stat)
  658. {
  659. struct directory_entry  *s_entry;
  660. struct directory_entry  *orig_contents;
  661. int deep_flag = 0;
  662. init_fstatbuf();
  663. orig_contents = dirnode->contents;
  664. if( (dirnode->dir_flags & DIR_HAS_DOTDOT) == 0 )
  665.   {
  666.     s_entry = (struct directory_entry *) 
  667.       e_malloc(sizeof (struct directory_entry));
  668.     memcpy(s_entry, dirnode->self, 
  669.    sizeof(struct directory_entry));
  670.     s_entry->name = strdup("..");
  671.     s_entry->whole_name = NULL;
  672.     s_entry->isorec.name_len[0] = 1;
  673.     s_entry->isorec.flags[0] = 2; /* Mark as a directory */
  674.     iso9660_file_length ("..", s_entry, 1);
  675.     iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
  676.     set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number);
  677.     set_733(s_entry->isorec.size,SECTOR_SIZE);
  678.     memset(s_entry->isorec.extent, 0, 8);
  679.     s_entry->filedir = dirnode->parent;
  680.     dirnode->contents = s_entry;
  681.     dirnode->contents->next = orig_contents;
  682.     orig_contents = s_entry;
  683.     if(use_RockRidge)
  684.       {
  685. if( parent_stat == NULL )
  686.   {
  687.     parent_stat = &fstatbuf;
  688.   }
  689. generate_rock_ridge_attributes("",
  690.        "..", s_entry,
  691.        parent_stat, 
  692.        parent_stat, 0);
  693.       }
  694.     dirnode->dir_flags |= DIR_HAS_DOTDOT;
  695.   }
  696. if( (dirnode->dir_flags & DIR_HAS_DOT) == 0 )
  697.   {
  698.     s_entry = (struct directory_entry *) 
  699.       e_malloc(sizeof (struct directory_entry));
  700.     memcpy(s_entry, dirnode->self, 
  701.    sizeof(struct directory_entry));
  702.     s_entry->name = strdup(".");
  703.     s_entry->whole_name = NULL;
  704.     s_entry->isorec.name_len[0] = 1;
  705.     s_entry->isorec.flags[0] = 2; /* Mark as a directory */
  706.     iso9660_file_length (".", s_entry, 1);
  707.     iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
  708.     set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number);
  709.     set_733(s_entry->isorec.size,SECTOR_SIZE);
  710.     memset(s_entry->isorec.extent, 0, 8);
  711.     s_entry->filedir = dirnode;
  712.     
  713.     dirnode->contents = s_entry;
  714.     dirnode->contents->next = orig_contents;
  715.     if(use_RockRidge)
  716.       {
  717. fstatbuf.st_mode = 0555 | S_IFDIR;
  718. fstatbuf.st_nlink = 2;
  719. if( dirnode == root )
  720.   {
  721.     deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
  722.   }
  723. generate_rock_ridge_attributes("",
  724.        ".", s_entry,
  725.        &fstatbuf, &fstatbuf, deep_flag);
  726.       }
  727.     
  728.     dirnode->dir_flags |= DIR_HAS_DOT;
  729.   }
  730. }
  731. static void FDECL2(update_nlink, struct directory_entry *, s_entry, int, value)
  732. {
  733.     unsigned char * pnt;
  734.     int len;
  735.     
  736.     pnt = s_entry->rr_attributes;
  737.     len = s_entry->total_rr_attr_size;
  738.     while(len)
  739.     {
  740. if(pnt[0] == 'P' && pnt[1] == 'X') 
  741. {
  742.     set_733((char *) pnt+12, value);
  743.     break;
  744. }
  745. len -= pnt[2];
  746. pnt += pnt[2];
  747.     }
  748. }
  749. static void FDECL1(increment_nlink, struct directory_entry *, s_entry)
  750. {
  751.     unsigned char * pnt;
  752.     int len, nlink;
  753.     
  754.     pnt = s_entry->rr_attributes;
  755.     len = s_entry->total_rr_attr_size;
  756.     while(len)
  757.     {
  758. if(pnt[0] == 'P' && pnt[1] == 'X') 
  759. {
  760.     nlink =  get_733((char *) pnt+12);
  761.     set_733((char *) pnt+12, nlink+1);
  762.     break;
  763. }
  764. len -= pnt[2];
  765. pnt += pnt[2];
  766.     }
  767. }
  768. void finish_cl_pl_entries(){
  769.   struct directory_entry  *s_entry, *s_entry1;
  770.   struct directory *  d_entry;
  771.   /* if the reloc_dir is hidden (empty), then return */
  772.   if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
  773.     return;
  774.   s_entry = reloc_dir->contents;
  775.    s_entry  = s_entry->next->next;  /* Skip past . and .. */
  776.   for(; s_entry; s_entry = s_entry->next){
  777.   /* skip if it's hidden */
  778.   if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
  779.     continue;
  780.   }
  781.   d_entry = reloc_dir->subdir;
  782.   while(d_entry){
  783.   if(d_entry->self == s_entry) break;
  784.   d_entry = d_entry->next;
  785.   };
  786.   if(!d_entry){
  787. #ifdef USE_LIBSCHILY
  788.   comerrno(EX_BAD, "Unable to locate directory parentn");
  789. #else
  790.   fprintf(stderr,"Unable to locate directory parentn");
  791.   exit(1);
  792. #endif
  793.   };
  794.   /* First fix the PL pointer in the directory in the rr_reloc dir */
  795.   s_entry1 = d_entry->contents->next;
  796.   set_733((char *) s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
  797.   s_entry->filedir->extent);
  798.   /* Now fix the CL pointer */
  799.   s_entry1 = s_entry->parent_rec;
  800.   set_733((char *) s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
  801.   d_entry->extent);
  802.   s_entry->filedir = reloc_dir;  /* Now we can fix this */
  803.   }
  804.   /* Next we need to modify the NLINK terms in the assorted root directory records
  805.      to account for the presence of the RR_MOVED directory */
  806.   increment_nlink(root->self);
  807.   increment_nlink(root->self->next);
  808.   d_entry = root->subdir;
  809.   while(d_entry){
  810.     increment_nlink(d_entry->contents->next);
  811.     d_entry = d_entry->next;
  812.   };
  813. }
  814. /* 
  815.  * Function: scan_directory_tree
  816.  *
  817.  * Purpose: Walk through a directory on the local machine
  818.  * filter those things we don't want to include
  819.  * and build our representation of a dir.
  820.  *
  821.  * Notes:
  822.  */
  823. int
  824. FDECL3(scan_directory_tree,struct directory *, this_dir,
  825.        char *, path, 
  826.        struct directory_entry *, de)
  827. {
  828.   DIR * current_dir;
  829.   char   whole_path[1024];
  830.   struct dirent * d_entry;
  831.   struct directory * parent;
  832.   int   dflag;
  833.   char * old_path;
  834.     if (verbose > 1)
  835.     {
  836.       fprintf(stderr, "Scanning %sn", path);
  837.     }
  838.   current_dir = opendir(path);
  839.   d_entry = NULL;
  840.   /* Apparently NFS sometimes allows you to open the directory, but
  841.      then refuses to allow you to read the contents.  Allow for this */
  842.   old_path = path;
  843.   if(current_dir) d_entry = readdir(current_dir);
  844.   if(!current_dir || !d_entry) 
  845.     {
  846. int ret = 1;
  847. #ifdef USE_LIBSCHILY
  848.       errmsg("Unable to open directory %sn", path);
  849. #else
  850.       fprintf(stderr,"Unable to open directory %sn", path);
  851. #endif
  852. if (errno == ENOTDIR) {
  853. de->isorec.flags[0] &= ~2; /* Mark as not a directory */
  854. ret = 0;
  855. }
  856.       if(current_dir) closedir(current_dir);
  857.       return ret;
  858.     }
  859. #ifdef ABORT_DEEP_ISO_ONLY
  860. if ((this_dir->depth > RR_relocation_depth) && !use_RockRidge) {
  861. errmsgno(EX_BAD, "Directories too deep for '%s' (%d) max is %d.n",
  862. path, this_dir->depth, RR_relocation_depth);
  863. closedir(current_dir);
  864. return 1;
  865. }
  866. #endif
  867.   parent = de->filedir;
  868.   /* Set up the struct for the current directory, and insert it into the
  869.      tree */
  870. #ifdef VMS
  871.   vms_path_fixup(path);
  872. #endif
  873.   /*
  874.    * if entry for this sub-directory is hidden, then hide this directory
  875.    */
  876.   if (de->de_flags & INHIBIT_ISO9660_ENTRY)
  877.     this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
  878.   
  879.   if (de->de_flags & INHIBIT_JOLIET_ENTRY)
  880.     this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
  881.   
  882.   /* 
  883.    * Now we scan the directory itself, and look at what is inside of it. 
  884.    */
  885.   dflag = 0;
  886.   while(1==1){
  887.     /* The first time through, skip this, since we already asked for
  888.        the first entry when we opened the directory. */
  889.     if(dflag) d_entry = readdir(current_dir);
  890.     dflag++;
  891.     if(!d_entry) break;
  892.     /* OK, got a valid entry */
  893.     /* If we do not want all files, then pitch the backups. */
  894.     if(!all_files){
  895.     if(   strchr(d_entry->d_name,'~')
  896.        || strchr(d_entry->d_name,'#')
  897.        || rstr(d_entry->d_name,".bak"))
  898.       {
  899. if( verbose > 0 )
  900.   {
  901.     fprintf(stderr, "Ignoring file %sn", d_entry->d_name);
  902.   }
  903. continue;
  904.       }
  905.     }
  906.     if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
  907. #ifdef USE_LIBSCHILY
  908.       comerrno(EX_BAD, "Overflow of stat buffern");
  909. #else
  910.       fprintf(stderr, "Overflow of stat buffern");
  911.       exit(1);
  912. #endif
  913.     };
  914.     /* Generate the complete ASCII path for this file */
  915.     strcpy(whole_path, path);
  916. #ifndef VMS
  917.     if(whole_path[strlen(whole_path)-1] != '/')
  918.       strcat(whole_path, "/");
  919. #endif
  920.     strcat(whole_path, d_entry->d_name);
  921.     /** Should we exclude this file ? */
  922.     if (matches(d_entry->d_name) || matches(whole_path)) {
  923.       if (verbose > 1) {
  924. fprintf(stderr, "Excluded by match: %sn", whole_path);
  925.       }
  926.       continue;
  927.     }
  928.     if(    generate_tables 
  929. && strcmp(d_entry->d_name, trans_tbl) == 0 )
  930.       {
  931. /*
  932.  * Ignore this entry.  We are going to be generating new
  933.  * versions of these files, and we need to ignore any
  934.  * originals that we might have found.
  935.  */
  936. if (verbose > 1) 
  937.   {
  938.     fprintf(stderr, "Excluded: %sn",whole_path);
  939.   }
  940. continue;
  941.       }
  942.     /*
  943.      * If we already have a '.' or a '..' entry, then don't
  944.      * insert new ones.
  945.      */
  946.     if( strcmp(d_entry->d_name, ".") == 0 
  947. && this_dir->dir_flags & DIR_HAS_DOT )
  948.       {
  949. continue;
  950.       }
  951.     if( strcmp(d_entry->d_name, "..") == 0 
  952. && this_dir->dir_flags & DIR_HAS_DOTDOT )
  953.       {
  954. continue;
  955.       }
  956. #if 0
  957.     if (verbose > 1)  fprintf(stderr, "%sn",whole_path);
  958. #endif
  959.     /*
  960.      * This actually adds the entry to the directory in question.
  961.      */
  962.     insert_file_entry(this_dir, whole_path, d_entry->d_name);
  963.   }
  964.   closedir(current_dir);
  965.   
  966.   return 1;
  967. }
  968. /* 
  969.  * Function: insert_file_entry
  970.  *
  971.  * Purpose: Insert one entry into our directory node.
  972.  *
  973.  * Note:
  974.  * This function inserts a single entry into the directory.  It
  975.  * is assumed that all filtering and decision making regarding what
  976.  * we want to include has already been made, so the purpose of this
  977.  * is to insert one entry (file, link, dir, etc), into this directory.
  978.  * Note that if the entry is a dir (or if we are following links,
  979.  * and the thing it points to is a dir), then we will scan those
  980.  * trees before we return.
  981.  */
  982. int
  983. FDECL3(insert_file_entry,struct directory *, this_dir,
  984.        char *, whole_path,
  985.        char *, short_name)
  986. {
  987.   struct stat   statbuf, lstatbuf;
  988.   struct directory_entry * s_entry, *s_entry1;
  989.   int   lstatus;
  990.   int   status;
  991.   int   deep_flag;
  992.   int   no_scandir = 0;
  993.   status = stat_filter(whole_path, &statbuf);
  994.   lstatus = lstat_filter(whole_path, &lstatbuf);
  995.   if( (status == -1) && (lstatus == -1) )
  996.     {
  997.       /*
  998.        * This means that the file doesn't exist, or isn't accessible.
  999.        * Sometimes this is because of NFS permissions problems.
  1000.        */
  1001. #ifdef USE_LIBSCHILY
  1002.       errmsg("Non-existant or inaccessible: %sn",whole_path);
  1003. #else
  1004.       fprintf(stderr, "Non-existant or inaccessible: %sn",whole_path);
  1005. #endif
  1006.       return 0;
  1007.     }
  1008.   
  1009.   if(this_dir == root && strcmp(short_name, ".") == 0)
  1010.     root_statbuf = statbuf;  /* Save this for later on */
  1011.   
  1012.   /* We do this to make sure that the root entries are consistent */
  1013.   if(this_dir == root && strcmp(short_name, "..") == 0) 
  1014.     {
  1015.       statbuf = root_statbuf;
  1016.       lstatbuf = root_statbuf;
  1017.     }
  1018.   if(S_ISLNK(lstatbuf.st_mode))
  1019.     {
  1020.       
  1021.       /* Here we decide how to handle the symbolic links.  Here
  1022.  we handle the general case - if we are not following
  1023.  links or there is an error, then we must change
  1024.  something.  If RR is in use, it is easy, we let RR
  1025.  describe the file.  If not, then we punt the file. */
  1026.       
  1027.       if((status || !follow_links))
  1028. {
  1029.   if(use_RockRidge)
  1030.     {
  1031.       status = 0;
  1032.       statbuf.st_size = 0;
  1033.       STAT_INODE(statbuf) = UNCACHED_INODE;
  1034.       statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
  1035.       statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
  1036.     } else {
  1037.       if(follow_links) 
  1038. {
  1039. #ifdef USE_LIBSCHILY
  1040. /* XXX errno may be wrong! */
  1041.   errmsg("Unable to stat file %s - ignoring and continuing.n",
  1042.   whole_path);
  1043. #else
  1044.   fprintf(stderr,
  1045.   "Unable to stat file %s - ignoring and continuing.n",
  1046.   whole_path);
  1047. #endif
  1048. }
  1049.       else
  1050. {
  1051. #ifdef USE_LIBSCHILY
  1052.   errmsgno(EX_BAD,
  1053.   "Symlink %s ignored - continuing.n",
  1054.   whole_path);
  1055. #else
  1056.   fprintf(stderr,
  1057.   "Symlink %s ignored - continuing.n",
  1058.   whole_path);
  1059. #endif
  1060.   return 0;  /* Non Rock Ridge discs - ignore all symlinks */
  1061. }
  1062.     }
  1063. }
  1064.       
  1065.       /* Here we handle a different kind of case.  Here we have
  1066.  a symlink, but we want to follow symlinks.  If we run
  1067.  across a directory loop, then we need to pretend that
  1068.  we are not following symlinks for this file.  If this
  1069.  is the first time we have seen this, then make this
  1070.  seem as if there was no symlink there in the first
  1071.  place */
  1072.       
  1073.       if( follow_links
  1074.   && S_ISDIR(statbuf.st_mode) ) 
  1075. {
  1076.   if(   strcmp(short_name, ".")
  1077. && strcmp(short_name, "..") )
  1078.     {
  1079.       if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
  1080. {
  1081.   if(!use_RockRidge) 
  1082.     {
  1083.       fprintf(stderr, "Already cached directory seen (%s)n", 
  1084.       whole_path);
  1085.       return 0;
  1086.     }
  1087.   lstatbuf = statbuf;
  1088.   no_scandir = 1;
  1089. }
  1090.       else 
  1091. {
  1092.   lstatbuf = statbuf;
  1093.   add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  1094. }
  1095.     }
  1096. }
  1097.       
  1098.       /*
  1099.        * For non-directories, we just copy the stat information over
  1100.        * so we correctly include this file.
  1101.        */
  1102.       if( follow_links
  1103.   && !S_ISDIR(statbuf.st_mode) ) 
  1104. {
  1105.   lstatbuf = statbuf;
  1106. }
  1107.     }
  1108.   
  1109.   /*
  1110.    * Add directories to the cache so that we don't waste space even
  1111.    * if we are supposed to be following symlinks.
  1112.    */
  1113.   if( follow_links
  1114.       && strcmp(short_name, ".")
  1115.       && strcmp(short_name, "..")
  1116.       && S_ISDIR(statbuf.st_mode) ) 
  1117.     {
  1118.       add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  1119.     }
  1120. #ifdef VMS
  1121.   if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && 
  1122.     statbuf.st_fab_rfm != FAB$C_STMLF)) {
  1123.     fprintf(stderr,"Warning - file %s has an unsupported VMS record"
  1124.     " format (%d)n",
  1125.     whole_path, statbuf.st_fab_rfm);
  1126.   }
  1127. #endif
  1128.   
  1129.   if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK)))
  1130.     {
  1131. #ifdef USE_LIBSCHILY
  1132.       errmsg("File %s is not readable - ignoringn", 
  1133.       whole_path);
  1134. #else
  1135.       fprintf(stderr, "File %s is not readable (errno = %d) - ignoringn", 
  1136.       whole_path, errno);
  1137. #endif
  1138.       return 0;
  1139.     }
  1140.   
  1141.   /* Add this so that we can detect directory loops with hard links.
  1142.      If we are set up to follow symlinks, then we skip this checking. */
  1143.   if(   !follow_links 
  1144. && S_ISDIR(lstatbuf.st_mode) 
  1145. && strcmp(short_name, ".") 
  1146. && strcmp(short_name, "..") ) 
  1147.     {
  1148.       if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
  1149. #ifdef USE_LIBSCHILY
  1150. /* comerrno(EX_BAD, "Directory loop - fatal goof (%s %lx %lu).n",*/
  1151. comerrno(EX_BAD, "Warning: Directory loop (%s dev: %lx ino: %lu).n",
  1152. whole_path, (unsigned long) statbuf.st_dev,
  1153. (unsigned long) STAT_INODE(statbuf));
  1154. #else
  1155. /* fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).n",*/
  1156. fprintf(stderr, "Warning: Directory loop (%s dev: %lx ino: %lu).n",
  1157. whole_path, (unsigned long) statbuf.st_dev,
  1158. (unsigned long) STAT_INODE(statbuf));
  1159. exit(1);
  1160. #endif
  1161.       }
  1162.       add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  1163.     }
  1164.   
  1165.   if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
  1166.       !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode)
  1167.       && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
  1168.       !S_ISDIR(lstatbuf.st_mode)) {
  1169.     fprintf(stderr,"Unknown file type (%s) %s - ignoring and continuing.n",
  1170.     filetype((int)lstatbuf.st_mode), whole_path);
  1171.     return 0;
  1172.   }
  1173.   
  1174.   /* Who knows what trash this is - ignore and continue */
  1175.   
  1176.   if(status) 
  1177.     {
  1178. #ifdef USE_LIBSCHILY
  1179.       errmsg("Unable to stat file %s - ignoring and continuing.n",
  1180.       whole_path);
  1181. #else
  1182.       fprintf(stderr,
  1183.       "Unable to stat file %s - ignoring and continuing.n",
  1184.       whole_path);
  1185. #endif
  1186.       return 0; 
  1187.     }
  1188.   
  1189.   /*
  1190.    * Check to see if we have already seen this directory node.
  1191.    * If so, then we don't create a new entry for it, but we do want
  1192.    * to recurse beneath it and add any new files we do find.
  1193.    */
  1194.   if (S_ISDIR(statbuf.st_mode)) 
  1195.     {
  1196.       int dflag;
  1197.       
  1198.       for( s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
  1199. {
  1200.   if( strcmp(s_entry->name, short_name) == 0 )
  1201.     {
  1202.       break;
  1203.     }
  1204. }
  1205.       if ( s_entry != NULL 
  1206.    && strcmp(short_name,".") 
  1207.    && strcmp(short_name,"..")) 
  1208. {
  1209.   struct directory * child;
  1210.   
  1211.   if ( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0)
  1212.     {
  1213.       for( s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next)
  1214. {
  1215.   if( strcmp(s_entry->name, short_name) == 0 )
  1216.     {
  1217.       break;
  1218.     }
  1219. }
  1220.       child = find_or_create_directory(reloc_dir, whole_path, 
  1221.        s_entry, 1);
  1222.     }
  1223.   else
  1224.     {
  1225.       child = find_or_create_directory(this_dir, whole_path, 
  1226.        s_entry, 1);
  1227.       /* If unable to scan directory, mark this as a non-directory */
  1228.     }
  1229.   if (no_scandir) dflag = 1; else
  1230.   dflag = scan_directory_tree(child, whole_path, s_entry);
  1231.   if(!dflag)
  1232.     {
  1233.       lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
  1234.     }
  1235.   return 0;
  1236. }
  1237.     }
  1238.   
  1239.   s_entry = (struct directory_entry *) 
  1240.     e_malloc(sizeof (struct directory_entry));
  1241.   s_entry->next = this_dir->contents;
  1242.   memset(s_entry->isorec.extent, 0, 8);
  1243.   this_dir->contents = s_entry;
  1244.   deep_flag = 0;
  1245.   s_entry->table = NULL;
  1246.   
  1247.   s_entry->name = strdup(short_name);
  1248.   s_entry->whole_name = strdup (whole_path);
  1249.   s_entry->de_flags = 0;
  1250.   /*
  1251.    * If the current directory is hidden, then hide all it's members
  1252.    * otherwise check if this entry needs to be hidden as well */
  1253.   if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
  1254.     s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
  1255.   }
  1256.   else if (strcmp(short_name,".") != 0 && strcmp(short_name,"..") != 0) {
  1257.     if (i_matches(short_name) || i_matches(whole_path)) {
  1258.       if (verbose > 1) {
  1259. fprintf(stderr, "Hidden from ISO9660 tree: %sn", whole_path);
  1260.       }
  1261.       s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
  1262.     }
  1263.   }
  1264.   if (this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
  1265.     s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
  1266.   }
  1267.   else if (strcmp(short_name,".") != 0 && strcmp(short_name,"..") != 0) {
  1268.     if (j_matches(short_name) || j_matches(whole_path)) {
  1269.       if (verbose > 1) {
  1270. fprintf(stderr, "Hidden from Joliet tree: %sn", whole_path);
  1271.       }
  1272.       s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
  1273.     }
  1274.   }
  1275.   s_entry->filedir = this_dir;
  1276.   s_entry->isorec.flags[0] = 0;
  1277.   s_entry->isorec.ext_attr_length[0] = 0;
  1278.   iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
  1279.   s_entry->isorec.file_unit_size[0] = 0;
  1280.   s_entry->isorec.interleave[0] = 0;
  1281.   if( strcmp(short_name,  ".") == 0)
  1282.     {
  1283.       this_dir->dir_flags |= DIR_HAS_DOT;
  1284.     } 
  1285.   if( strcmp(short_name,  "..") == 0)
  1286.     {
  1287.       this_dir->dir_flags |= DIR_HAS_DOTDOT;
  1288.     } 
  1289.   if(   this_dir->parent 
  1290.      && this_dir->parent == reloc_dir 
  1291.      && strcmp(short_name,  "..") == 0)
  1292.     {
  1293.       s_entry->inode = UNCACHED_INODE;
  1294.       s_entry->dev = (dev_t) UNCACHED_DEVICE;
  1295.       deep_flag  = NEED_PL;
  1296.     } 
  1297.   else
  1298.     {
  1299.       s_entry->inode = STAT_INODE(statbuf);
  1300.       s_entry->dev = statbuf.st_dev;
  1301.     }
  1302.   set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number);
  1303.   iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
  1304.   s_entry->rr_attr_size = 0;
  1305.   s_entry->total_rr_attr_size = 0;
  1306.   s_entry->rr_attributes = NULL;
  1307.   
  1308.   /* Directories are assigned sizes later on */
  1309.   if (!S_ISDIR(statbuf.st_mode)) 
  1310.     {
  1311.       if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || 
  1312.   S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode)
  1313.   || S_ISLNK(lstatbuf.st_mode))
  1314. {
  1315.   s_entry->size = 0; 
  1316.   statbuf.st_size = 0; 
  1317. }
  1318.       else
  1319. {
  1320.   s_entry->size = statbuf.st_size; 
  1321. }
  1322.       set_733((char *) s_entry->isorec.size, statbuf.st_size); 
  1323.     } 
  1324.   else
  1325.     {
  1326.       s_entry->isorec.flags[0] = 2;
  1327.     }
  1328.   
  1329.   if (strcmp(short_name,".") != 0 && strcmp(short_name,"..") != 0 &&
  1330.       S_ISDIR(statbuf.st_mode) && this_dir->depth >  RR_relocation_depth)
  1331.     {
  1332.       struct directory * child;
  1333.       if(!reloc_dir) generate_reloc_directory();
  1334.       
  1335.       /*
  1336.        * Replicate the entry for this directory.  The old one will stay where it
  1337.        * is, and it will be neutered so that it no longer looks like a directory.
  1338.        * The new one will look like a directory, and it will be put in the reloc_dir.
  1339.        */
  1340.       s_entry1 = (struct directory_entry *) 
  1341. e_malloc(sizeof (struct directory_entry));
  1342.       memcpy(s_entry1, s_entry,  sizeof(struct directory_entry));
  1343.       s_entry1->table = NULL;
  1344.       s_entry1->name = strdup(this_dir->contents->name);
  1345.       s_entry1->whole_name = strdup(this_dir->contents->whole_name);
  1346.       s_entry1->next = reloc_dir->contents;
  1347.       reloc_dir->contents = s_entry1;
  1348.       s_entry1->priority  =  32768;
  1349.       s_entry1->parent_rec = this_dir->contents;
  1350.       set_723(s_entry1->isorec.volume_sequence_number, volume_sequence_number);
  1351.       
  1352.       deep_flag = NEED_RE;
  1353.       
  1354.       if(use_RockRidge) 
  1355. {
  1356.   generate_rock_ridge_attributes(whole_path,
  1357.  short_name, s_entry1,
  1358.  &statbuf, &lstatbuf, deep_flag);
  1359. }
  1360.       
  1361.       deep_flag = 0;
  1362.       
  1363.       /* We need to set this temporarily so that the parent to this
  1364.  is correctly determined. */
  1365.       s_entry1->filedir = reloc_dir;
  1366.       child = find_or_create_directory(reloc_dir, whole_path, 
  1367.        s_entry1, 0);
  1368.       if (!no_scandir)
  1369.       scan_directory_tree(child, whole_path, s_entry1);
  1370.       s_entry1->filedir = this_dir;
  1371.       
  1372.       statbuf.st_size = 0;
  1373.       statbuf.st_mode &= 0777;
  1374.       set_733((char *) s_entry->isorec.size, 0);
  1375.       s_entry->size = 0;
  1376.       s_entry->isorec.flags[0] = 0;
  1377.       s_entry->inode = UNCACHED_INODE;
  1378.       s_entry->de_flags |= RELOCATED_DIRECTORY;
  1379.       deep_flag = NEED_CL;
  1380.     }
  1381.   
  1382.   if(generate_tables 
  1383.      && strcmp(s_entry->name, ".") != 0
  1384.      && strcmp(s_entry->name, "..") != 0) 
  1385.     {
  1386.       char  buffer[2048];
  1387.       int nchar;
  1388.       switch(lstatbuf.st_mode & S_IFMT)
  1389. {
  1390. case S_IFDIR:
  1391.   sprintf(buffer,"Dt%sn",
  1392.   s_entry->name);
  1393.   break;
  1394. /* extra for WIN32 - if it doesn't have the major/minor defined, then
  1395.    S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
  1396.    code similar to that in rock.c */
  1397. #if 0
  1398. /*
  1399.  * Use the device handling code from <device.h>
  1400.  */
  1401. #ifndef major
  1402. #define major(dev) (sizeof(dev_t) <= 2 ? ((dev) >> 8) : 
  1403. (sizeof(dev_t) <= 4 ? (((dev) >> 8) >> 8) : 
  1404. (((dev) >> 16) >> 16)))
  1405. #define minor(dev) (sizeof(dev_t) <= 2 ? (dev) & 0xff : 
  1406. (sizeof(dev_t) <= 4 ? (dev) & 0xffff : 
  1407. (dev) & 0xffffffff))
  1408. #endif
  1409. #endif
  1410. #ifdef S_IFBLK
  1411. case S_IFBLK:
  1412.   sprintf(buffer,"Bt%st%lu %lun",
  1413.   s_entry->name,
  1414.   (unsigned long) major(statbuf.st_rdev),
  1415.   (unsigned long) minor(statbuf.st_rdev));
  1416.   break;
  1417. #endif
  1418. #ifdef S_IFIFO
  1419. case S_IFIFO:
  1420.   sprintf(buffer,"Pt%sn",
  1421.   s_entry->name);
  1422.   break;
  1423. #endif
  1424. #ifdef S_IFCHR
  1425. case S_IFCHR:
  1426.   sprintf(buffer,"Ct%st%lu %lun",
  1427.   s_entry->name,
  1428.   (unsigned long) major(statbuf.st_rdev),
  1429.   (unsigned long) minor(statbuf.st_rdev));
  1430.   break;
  1431. #endif
  1432. #ifdef S_IFLNK
  1433. case S_IFLNK:
  1434. #ifdef HAVE_READLINK
  1435.   nchar = readlink(whole_path, 
  1436.    (char *)symlink_buff, 
  1437.    sizeof(symlink_buff));
  1438. #else
  1439.   nchar = -1;
  1440. #endif
  1441.   symlink_buff[nchar < 0 ? 0 : nchar] = 0;
  1442.   sprintf(buffer,"Lt%st%sn",
  1443.   s_entry->name, symlink_buff);
  1444.   break;
  1445. #endif
  1446. #ifdef S_IFSOCK
  1447. case S_IFSOCK:
  1448.   sprintf(buffer,"St%sn",
  1449.   s_entry->name);
  1450.   break;
  1451. #endif
  1452. case S_IFREG:
  1453. default:
  1454.   sprintf(buffer,"Ft%sn",
  1455.   s_entry->name);
  1456.   break;
  1457. };
  1458.       s_entry->table = strdup(buffer);
  1459.     }
  1460.   
  1461.   if(S_ISDIR(statbuf.st_mode))
  1462.     {
  1463.       int dflag;
  1464.       if (strcmp(short_name,".") != 0 && strcmp(short_name,"..") != 0) 
  1465. {
  1466.   struct directory * child;
  1467.   
  1468.   child = find_or_create_directory(this_dir, whole_path, 
  1469.    s_entry, 1);
  1470.   if (no_scandir) dflag = 1; else
  1471.   dflag = scan_directory_tree(child, whole_path, s_entry);
  1472.   
  1473.   if(!dflag)
  1474.     {
  1475.       lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
  1476.       if( child->contents == NULL )
  1477. {
  1478.   delete_directory(this_dir, child);
  1479. }
  1480.     }
  1481. }
  1482.       /* If unable to scan directory, mark this as a non-directory */
  1483.     }
  1484.   
  1485.   if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")  == 0)
  1486.     {
  1487.       deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
  1488.     }
  1489.   
  1490.   /* Now figure out how much room this file will take in the
  1491.      directory */
  1492.   
  1493.   if(use_RockRidge) 
  1494.     {
  1495.       generate_rock_ridge_attributes(whole_path,
  1496.      short_name, s_entry,
  1497.      &statbuf, &lstatbuf, deep_flag);
  1498.       
  1499.     }
  1500.   
  1501.   return 1;
  1502. }
  1503. void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
  1504.   struct directory * dpnt;
  1505.   dpnt = node;
  1506.   while (dpnt){
  1507.     if( dpnt->extent > session_start )
  1508.       {
  1509. generate_one_directory(dpnt, outfile);
  1510.       }
  1511.     if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
  1512.     dpnt = dpnt->next;
  1513.   }
  1514. }
  1515. /*
  1516.  * Function: find_or_create_directory
  1517.  *
  1518.  * Purpose: Locate a directory entry in the tree, create if needed.
  1519.  *
  1520.  * Arguments: parent & de are never NULL at the same time.
  1521.  */
  1522. struct directory * FDECL4(find_or_create_directory, struct directory *, parent,
  1523.   const char *, path,
  1524.   struct directory_entry *, de, int, flag)
  1525. {
  1526.   struct directory * dpnt;
  1527.   struct directory_entry * orig_de;
  1528.   struct directory * next_brother;
  1529.   const char                    * cpnt;
  1530.   const char * pnt;
  1531.   orig_de = de;
  1532. /*
  1533.  * XXX It seems that the tree that has been read from the
  1534.  * XXX previous session does not carry whole_name entries.
  1535.  * XXX We provide a hack in multi.c:find_or_create_directory()
  1536.  * XXX that should be removed when a reasonable method could
  1537.  * XXX be found.
  1538.  */
  1539. if (path == NULL) {
  1540. error("Warning: missing whole name for: '%s'n", de->name);
  1541. path = de->name;
  1542. }
  1543.   pnt = strrchr(path, PATH_SEPARATOR);
  1544.   if( pnt == NULL )
  1545.     {
  1546.       pnt = path;
  1547.     }
  1548.   else
  1549.     {
  1550.       pnt++;
  1551.     }
  1552.   if( parent != NULL )
  1553.     {
  1554.       dpnt = parent->subdir;
  1555.       while (dpnt)
  1556. {
  1557.   /*
  1558.    * Weird hack time - if there are two directories by the
  1559.    * same name in the reloc_dir, they are not treated as the
  1560.    * same thing unless the entire path matches completely.
  1561.    */
  1562.   if( flag && strcmp(dpnt->de_name, pnt) == 0 )
  1563.     {
  1564.       return dpnt;
  1565.     }
  1566.   dpnt = dpnt->next;
  1567. }
  1568.     }
  1569.   /*
  1570.    * We don't know if we have a valid directory entry for this one
  1571.    * yet.  If not, we need to create one.
  1572.    */
  1573.   if( de == NULL )
  1574.     {
  1575.       de = (struct directory_entry *) 
  1576. e_malloc(sizeof (struct directory_entry));
  1577.       memset(de, 0, sizeof(struct directory_entry));
  1578.       de->next            = parent->contents;
  1579.       parent->contents    = de;
  1580.       de->name            = strdup(pnt);
  1581.       de->whole_name      = strdup(path);
  1582.       de->filedir         = parent;
  1583.       de->isorec.flags[0] = 2;
  1584.       de->priority        = 32768;
  1585.       de->inode           = UNCACHED_INODE;
  1586.       de->dev             = (dev_t) UNCACHED_DEVICE;
  1587.       set_723(de->isorec.volume_sequence_number, volume_sequence_number);
  1588.       iso9660_file_length (pnt, de, 1);
  1589.       init_fstatbuf();
  1590.       /*
  1591.        * It doesn't exist for real, so we cannot add any Rock Ridge.
  1592.        */
  1593.       if(use_RockRidge)
  1594. {
  1595.   fstatbuf.st_mode = 0555 | S_IFDIR;
  1596.   fstatbuf.st_nlink = 2;
  1597.   generate_rock_ridge_attributes("",
  1598.  (char *) pnt, de,
  1599.  &fstatbuf, 
  1600.  &fstatbuf, 0);
  1601. }
  1602.       iso9660_date(de->isorec.date, fstatbuf.st_mtime);
  1603.     }
  1604.   /*
  1605.    * If we don't have a directory for this one yet, then allocate it
  1606.    * now, and patch it into the tree in the appropriate place.
  1607.    */
  1608.   dpnt             = (struct directory *) e_malloc(sizeof(struct directory));
  1609.   memset(dpnt, 0, sizeof(struct directory));
  1610.   dpnt->next       = NULL;
  1611.   dpnt->subdir     = NULL;
  1612.   dpnt->self       = de;
  1613.   dpnt->contents   = NULL;
  1614.   dpnt->whole_name = strdup(path);
  1615.   cpnt             = strrchr(path, PATH_SEPARATOR);
  1616.   if(cpnt)
  1617.     cpnt++;
  1618.   else
  1619.     cpnt = path;
  1620.   dpnt->de_name    = strdup(cpnt);
  1621.   dpnt->size       = 0;
  1622.   dpnt->extent     = 0;
  1623.   dpnt->jextent    = 0;
  1624.   dpnt->jsize      = 0;
  1625.   if( orig_de == NULL )
  1626.     {
  1627.       struct stat xstatbuf;
  1628.       int sts;
  1629.       /*
  1630.        * Now add a . and .. entry in the directory itself.
  1631.        * This is a little tricky - if the real directory
  1632.        * exists, we need to stat it first.  Otherwise, we
  1633.        * use the fictitious fstatbuf which points to the time
  1634.        * at which mkisofs was started.
  1635.        */
  1636.       sts = stat_filter(parent->whole_name, &xstatbuf);
  1637.       if( sts == 0 )
  1638. {
  1639.   attach_dot_entries(dpnt, &xstatbuf);
  1640. }
  1641.       else
  1642. {
  1643.   attach_dot_entries(dpnt, &fstatbuf);
  1644. }
  1645.     }
  1646.   if(!parent || parent == root)
  1647.     {
  1648.       if (!root) 
  1649. {
  1650.   root = dpnt;  /* First time through for root directory only */
  1651.   root->depth = 0;
  1652.   root->parent = root;
  1653. } else {
  1654.   dpnt->depth = 1;
  1655.   if(!root->subdir)
  1656.     {
  1657.       root->subdir = dpnt;
  1658.     }
  1659.   else 
  1660.     {
  1661.       next_brother = root->subdir;
  1662.       while(next_brother->next) next_brother = next_brother->next;
  1663.       next_brother->next = dpnt;
  1664.     }
  1665.   dpnt->parent = parent;
  1666. }
  1667.     } 
  1668.   else 
  1669.     {
  1670.       /* Come through here for  normal traversal of  tree */
  1671. #ifdef DEBUG
  1672.       fprintf(stderr,"%s(%d) ", path, dpnt->depth);
  1673. #endif
  1674.       if(parent->depth >  RR_relocation_depth) 
  1675. {
  1676. #ifdef USE_LIBSCHILY
  1677.   comerrno(EX_BAD, "Directories too deep for '%s' (%d) max is %d.n",
  1678. path, parent->depth, RR_relocation_depth);
  1679. #else
  1680.   fprintf(stderr,"Directories too deep for '%s' (%d) max is %d.n",
  1681. path, parent->depth, RR_relocation_depth);
  1682.   exit(1);
  1683. #endif
  1684. }
  1685.       
  1686.       dpnt->parent = parent; 
  1687.       dpnt->depth = parent->depth + 1;
  1688.       
  1689.       if(!parent->subdir)
  1690. {
  1691.   parent->subdir = dpnt;
  1692. }
  1693.       else 
  1694. {
  1695.   next_brother = parent->subdir;
  1696.   while(next_brother->next) next_brother = next_brother->next;
  1697.   next_brother->next = dpnt;
  1698. }
  1699.     }
  1700.   return dpnt;
  1701. }
  1702. /*
  1703.  * Function: delete_directory
  1704.  *
  1705.  * Purpose: Locate a directory entry in the tree, create if needed.
  1706.  *
  1707.  * Arguments:
  1708.  */
  1709. static void FDECL2(delete_directory, struct directory *, parent, struct directory *, child)
  1710. {
  1711.   struct directory * tdir;
  1712.   if( child->contents != NULL )
  1713.     {
  1714. #ifdef USE_LIBSCHILY
  1715.       comerrno(EX_BAD, "Unable to delete non-empty directoryn");
  1716. #else
  1717.       fprintf(stderr, "Unable to delete non-empty directoryn");
  1718.       exit(1);
  1719. #endif
  1720.     }
  1721.   free(child->whole_name);
  1722.   child->whole_name = NULL;
  1723.   free(child->de_name);
  1724.   child->de_name = NULL;
  1725.   if( parent->subdir == child )
  1726.     {
  1727.       parent->subdir = child->next;
  1728.     }
  1729.   else
  1730.     {
  1731.       for( tdir = parent->subdir; tdir->next != NULL; tdir = tdir->next )
  1732. {
  1733.   if( tdir->next == child )
  1734.     {
  1735.       tdir->next = child->next;
  1736.       break;
  1737.     }
  1738. }
  1739.       if( tdir == NULL )
  1740. {
  1741. #ifdef USE_LIBSCHILY
  1742.   comerrno(EX_BAD, "Unable to locate child directory in parent listn");
  1743. #else
  1744.   fprintf(stderr, "Unable to locate child directory in parent listn");
  1745.   exit(1);
  1746. #endif
  1747. }
  1748.     }
  1749.   free(child);
  1750.   return;
  1751. }
  1752. int FDECL1(sort_tree, struct directory *, node){
  1753.   struct directory * dpnt;
  1754.   int ret = 0;
  1755.   dpnt = node;
  1756.   while (dpnt){
  1757.     ret = sort_n_finish(dpnt);
  1758.     if( ret )
  1759.       {
  1760. break;
  1761.       }
  1762.     
  1763.     if(dpnt->subdir) sort_tree(dpnt->subdir);
  1764.     dpnt = dpnt->next;
  1765.   }
  1766.   return ret;
  1767. }
  1768. void FDECL1(dump_tree, struct directory *, node){
  1769.   struct directory * dpnt;
  1770.   dpnt = node;
  1771.   while (dpnt){
  1772.     fprintf(stderr,"%4d %5d %sn",dpnt->extent, dpnt->size, dpnt->de_name);
  1773.     if(dpnt->subdir) dump_tree(dpnt->subdir);
  1774.     dpnt = dpnt->next;
  1775.   }
  1776. }
  1777. void FDECL1(update_nlink_field, struct directory *, node)
  1778. {
  1779.     struct directory * dpnt;
  1780.     struct directory * xpnt;
  1781.     struct directory_entry * s_entry;
  1782.     int   i;
  1783.     dpnt = node;
  1784.     
  1785.     while (dpnt)
  1786.     {
  1787. if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
  1788.     dpnt = dpnt->next;
  1789.     continue;
  1790. }
  1791. /*
  1792.  * First, count up the number of subdirectories this guy has.
  1793.  */
  1794.         for(i=0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
  1795.             if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
  1796.                 i++;
  1797. /*
  1798.  * Next check to see if we have any relocated directories
  1799.  * in this directory.   The nlink field will include these
  1800.  * as real directories when they are properly relocated.
  1801.  *
  1802.  * In the non-rockridge disk, the relocated entries appear
  1803.  * as zero length files.
  1804.  */
  1805. for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
  1806. {
  1807. if( (s_entry->de_flags  & RELOCATED_DIRECTORY) != 0 &&
  1808. (s_entry->de_flags  & INHIBIT_ISO9660_ENTRY) == 0)
  1809. {
  1810. i++;
  1811. }
  1812. }
  1813. /*
  1814.  * Now update the field in the Rock Ridge entry.
  1815.  */
  1816. update_nlink(dpnt->self, i + 2);
  1817. /*
  1818.  * Update the '.' entry for this directory.
  1819.  */
  1820. update_nlink(dpnt->contents, i + 2);
  1821. /*
  1822.  * Update all of the '..' entries that point to this guy.
  1823.  */
  1824. for(xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
  1825.     update_nlink(xpnt->contents->next, i + 2);
  1826. if(dpnt->subdir) update_nlink_field(dpnt->subdir);
  1827. dpnt = dpnt->next;
  1828.     }
  1829. }
  1830. /*
  1831.  * something quick and dirty to locate a file given a path
  1832.  * recursively walks down path in filename until it finds the
  1833.  * directory entry for the desired file 
  1834.  */
  1835. struct directory_entry * FDECL2(search_tree_file, struct directory *, 
  1836. node,char *, filename)
  1837. {
  1838.   struct directory_entry * depnt;
  1839.   struct directory  * dpnt;
  1840.   char  * p1;
  1841.   char  * rest;
  1842.   char  * subdir;
  1843.   /*
  1844.    * strip off next directory name from filename 
  1845.    */
  1846.   subdir = strdup(filename);
  1847.   if( (p1=strchr(subdir, '/')) == subdir )
  1848.     {
  1849.       fprintf(stderr,"call to search_tree_file with an absolute path, strippingn");
  1850.       fprintf(stderr,"initial path separator. Hope this was intended...n");
  1851.       memmove(subdir, subdir+1, strlen(subdir)-1);
  1852.       p1 = strchr(subdir, '/');
  1853.     }
  1854.   /*
  1855.    * do we need to find a subdirectory 
  1856.    */
  1857.   if (p1) 
  1858.     {
  1859.       *p1 = '';
  1860. #ifdef DEBUG_TORITO
  1861.       fprintf(stderr,"Looking for subdir called %sn",p1); 
  1862. #endif
  1863.       rest = p1+1;
  1864. #ifdef DEBUG_TORITO
  1865.       fprintf(stderr,"Remainder of path name is now %sn", rest); 
  1866. #endif
  1867.       
  1868.       dpnt = node->subdir;
  1869.      while( dpnt )
  1870.        {
  1871. #ifdef DEBUG_TORITO
  1872.  fprintf(stderr,"%4d %5d %sn", dpnt->extent, dpnt->size, 
  1873.  dpnt->de_name); 
  1874. #endif
  1875.  if (!strcmp(subdir, dpnt->de_name)) 
  1876.    {
  1877. #ifdef DEBUG_TORITO
  1878.      fprintf(stderr,"Calling next level with filename = %s", rest); 
  1879. #endif
  1880.      return(search_tree_file( dpnt, rest ));
  1881.    }
  1882.  dpnt = dpnt->next;
  1883.        }
  1884.       
  1885.      /* if we got here means we couldnt find the subdir */
  1886.      return (NULL);
  1887.     }    
  1888.   else 
  1889.     {
  1890.       /* 
  1891.        * look for a normal file now 
  1892.        */
  1893.       depnt = node->contents;
  1894.       while (depnt)
  1895. {
  1896. #ifdef DEBUG_TORITO
  1897.   fprintf(stderr,"%4d %5d %sn",depnt->isorec.extent, 
  1898.   depnt->size, depnt->name); 
  1899. #endif
  1900.   if (!strcmp(filename, depnt->name)) 
  1901.     {
  1902. #ifdef DEBUG_TORITO
  1903.       fprintf(stderr,"Found our file %s", filename); 
  1904. #endif
  1905.       return(depnt);
  1906.     }
  1907.   depnt = depnt->next;
  1908. }
  1909.       /* 
  1910.        * if we got here means we couldnt find the subdir 
  1911.        */
  1912.       return (NULL);
  1913.     }
  1914. #ifdef ERIC_FUN
  1915.   fprintf(stderr,"We cant get here in search_tree_file :-/ n");
  1916. #endif
  1917. }
  1918. void init_fstatbuf()
  1919. {
  1920.   time_t     current_time;
  1921.   if(fstatbuf.st_ctime == 0)
  1922.     {
  1923.       time (&current_time);
  1924.       if( rationalize )
  1925. {
  1926.   fstatbuf.st_uid = 0;
  1927.   fstatbuf.st_gid = 0;
  1928. }
  1929.       else
  1930. {
  1931.   fstatbuf.st_uid = getuid();
  1932.   fstatbuf.st_gid = getgid();
  1933. }
  1934.       fstatbuf.st_ctime = current_time;
  1935.       fstatbuf.st_mtime = current_time;
  1936.       fstatbuf.st_atime = current_time;
  1937.     }
  1938. }