home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / samba-1.9.18p7.tar.gz / samba-1.9.18p7.tar / samba-1.9.18p7 / source / dir.c < prev    next >
C/C++ Source or Header  |  1998-05-12  |  26KB  |  1,028 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Directory handling routines
  5.    Copyright (C) Andrew Tridgell 1992-1998
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include "includes.h"
  23.  
  24. extern int DEBUGLEVEL;
  25. extern connection_struct Connections[];
  26.  
  27. /*
  28.    This module implements directory related functions for Samba.
  29. */
  30.  
  31.  
  32.  
  33. uint32 dircounter = 0;
  34.  
  35.  
  36. #define NUMDIRPTRS 256
  37.  
  38.  
  39. static struct dptr_struct
  40. {
  41.   int pid;
  42.   int cnum;
  43.   uint32 lastused;
  44.   void *ptr;
  45.   BOOL valid;
  46.   BOOL finished;
  47.   BOOL expect_close;
  48.   char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */
  49.   uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */
  50.   char *path;
  51. }
  52. dirptrs[NUMDIRPTRS];
  53.  
  54.  
  55. static int dptrs_open = 0;
  56.  
  57. /****************************************************************************
  58. initialise the dir array
  59. ****************************************************************************/
  60. void init_dptrs(void)
  61. {
  62.   static BOOL dptrs_init=False;
  63.   int i;
  64.  
  65.   if (dptrs_init) return;
  66.   for (i=0;i<NUMDIRPTRS;i++)    
  67.     {
  68.       dirptrs[i].valid = False;
  69.       dirptrs[i].wcard = NULL;
  70.       dirptrs[i].ptr = NULL;
  71.       string_init(&dirptrs[i].path,"");
  72.     }
  73.   dptrs_init = True;
  74. }
  75.  
  76. /****************************************************************************
  77. idle a dptr - the directory is closed but the control info is kept
  78. ****************************************************************************/
  79. static void dptr_idle(int key)
  80. {
  81.   if (dirptrs[key].valid && dirptrs[key].ptr) {
  82.     DEBUG(4,("Idling dptr key %d\n",key));
  83.     dptrs_open--;
  84.     CloseDir(dirptrs[key].ptr);
  85.     dirptrs[key].ptr = NULL;
  86.   }    
  87. }
  88.  
  89. /****************************************************************************
  90. idle the oldest dptr
  91. ****************************************************************************/
  92. static void dptr_idleoldest(void)
  93. {
  94.   int i;
  95.   uint32 old=dircounter+1;
  96.   int oldi= -1;
  97.   for (i=0;i<NUMDIRPTRS;i++)
  98.     if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) {
  99.       old = dirptrs[i].lastused;
  100.       oldi = i;
  101.     }
  102.   if (oldi != -1)
  103.     dptr_idle(oldi);
  104.   else
  105.     DEBUG(0,("No dptrs available to idle??\n"));
  106. }
  107.  
  108. /****************************************************************************
  109. get the dir ptr for a dir index
  110. ****************************************************************************/
  111. static void *dptr_get(int key,uint32 lastused)
  112. {
  113.   struct dptr_struct *dp = &dirptrs[key];
  114.  
  115.   if (dp->valid) {
  116.     if (lastused) dp->lastused = lastused;
  117.     if (!dp->ptr) {
  118.       if (dptrs_open >= MAXDIR)
  119.     dptr_idleoldest();
  120.       DEBUG(4,("Reopening dptr key %d\n",key));
  121.       if ((dp->ptr = OpenDir(dp->cnum, dp->path, True)))
  122.     dptrs_open++;
  123.     }
  124.     return(dp->ptr);
  125.   }
  126.   return(NULL);
  127. }
  128.  
  129. /****************************************************************************
  130. get the dir path for a dir index
  131. ****************************************************************************/
  132. char *dptr_path(int key)
  133. {
  134.   if (dirptrs[key].valid)
  135.     return(dirptrs[key].path);
  136.   return(NULL);
  137. }
  138.  
  139. /****************************************************************************
  140. get the dir wcard for a dir index (lanman2 specific)
  141. ****************************************************************************/
  142. char *dptr_wcard(int key)
  143. {
  144.   if (dirptrs[key].valid)
  145.     return(dirptrs[key].wcard);
  146.   return(NULL);
  147. }
  148.  
  149. /****************************************************************************
  150. set the dir wcard for a dir index (lanman2 specific)
  151. Returns 0 on ok, 1 on fail.
  152. ****************************************************************************/
  153. BOOL dptr_set_wcard(int key, char *wcard)
  154. {
  155.   if (dirptrs[key].valid) {
  156.     dirptrs[key].wcard = wcard;
  157.     return True;
  158.   }
  159.   return False;
  160. }
  161.  
  162. /****************************************************************************
  163. set the dir attrib for a dir index (lanman2 specific)
  164. Returns 0 on ok, 1 on fail.
  165. ****************************************************************************/
  166. BOOL dptr_set_attr(int key, uint16 attr)
  167. {
  168.   if (dirptrs[key].valid) {
  169.     dirptrs[key].attr = attr;
  170.     return True;
  171.   }
  172.   return False;
  173. }
  174.  
  175. /****************************************************************************
  176. get the dir attrib for a dir index (lanman2 specific)
  177. ****************************************************************************/
  178. uint16 dptr_attr(int key)
  179. {
  180.   if (dirptrs[key].valid)
  181.     return(dirptrs[key].attr);
  182.   return(0);
  183. }
  184.  
  185. /****************************************************************************
  186. close a dptr
  187. ****************************************************************************/
  188. void dptr_close(int key)
  189. {
  190.   /* OS/2 seems to use -1 to indicate "close all directories" */
  191.   if (key == -1) {
  192.     int i;
  193.     for (i=0;i<NUMDIRPTRS;i++) 
  194.       dptr_close(i);
  195.     return;
  196.   }
  197.  
  198.   if (key < 0 || key >= NUMDIRPTRS) {
  199.     DEBUG(3,("Invalid key %d given to dptr_close\n",key));
  200.     return;
  201.   }
  202.  
  203.   if (dirptrs[key].valid) {
  204.     DEBUG(4,("closing dptr key %d\n",key));
  205.     if (dirptrs[key].ptr) {
  206.       CloseDir(dirptrs[key].ptr);
  207.       dptrs_open--;
  208.     }
  209.     /* Lanman 2 specific code */
  210.     if (dirptrs[key].wcard)
  211.       free(dirptrs[key].wcard);
  212.     dirptrs[key].valid = False;
  213.     string_set(&dirptrs[key].path,"");
  214.   }
  215. }
  216.  
  217. /****************************************************************************
  218. close all dptrs for a cnum
  219. ****************************************************************************/
  220. void dptr_closecnum(int cnum)
  221. {
  222.   int i;
  223.   for (i=0;i<NUMDIRPTRS;i++)
  224.     if (dirptrs[i].valid && dirptrs[i].cnum == cnum)
  225.       dptr_close(i);
  226. }
  227.  
  228. /****************************************************************************
  229. idle all dptrs for a cnum
  230. ****************************************************************************/
  231. void dptr_idlecnum(int cnum)
  232. {
  233.   int i;
  234.   for (i=0;i<NUMDIRPTRS;i++)
  235.     if (dirptrs[i].valid && dirptrs[i].cnum == cnum && dirptrs[i].ptr)
  236.       dptr_idle(i);
  237. }
  238.  
  239. /****************************************************************************
  240. close a dptr that matches a given path, only if it matches the pid also
  241. ****************************************************************************/
  242. void dptr_closepath(char *path,int pid)
  243. {
  244.   int i;
  245.   for (i=0;i<NUMDIRPTRS;i++)
  246.     if (dirptrs[i].valid && pid == dirptrs[i].pid &&
  247.     strequal(dirptrs[i].path,path))
  248.       dptr_close(i);
  249. }
  250.  
  251. /****************************************************************************
  252.   start a directory listing
  253. ****************************************************************************/
  254. static BOOL start_dir(int cnum,char *directory)
  255. {
  256.   DEBUG(5,("start_dir cnum=%d dir=%s\n",cnum,directory));
  257.  
  258.   if (!check_name(directory,cnum))
  259.     return(False);
  260.   
  261.   if (! *directory)
  262.     directory = ".";
  263.  
  264.   Connections[cnum].dirptr = OpenDir(cnum, directory, True);
  265.   if (Connections[cnum].dirptr) {    
  266.     dptrs_open++;
  267.     string_set(&Connections[cnum].dirpath,directory);
  268.     return(True);
  269.   }
  270.   
  271.   return(False);
  272. }
  273.  
  274.  
  275. /****************************************************************************
  276. create a new dir ptr
  277. ****************************************************************************/
  278. int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
  279. {
  280.   int i;
  281.   uint32 old;
  282.   int oldi;
  283.  
  284.   if (!start_dir(cnum,path))
  285.     return(-2); /* Code to say use a unix error return code. */
  286.  
  287.   if (dptrs_open >= MAXDIR)
  288.     dptr_idleoldest();
  289.  
  290.   for (i=0;i<NUMDIRPTRS;i++)
  291.     if (!dirptrs[i].valid)
  292.       break;
  293.   if (i == NUMDIRPTRS) i = -1;
  294.  
  295.  
  296.   /* as a 2nd option, grab the oldest not marked for expect_close */
  297.   if (i == -1) {
  298.     old=dircounter+1;
  299.     oldi= -1;
  300.     for (i=0;i<NUMDIRPTRS;i++)
  301.       if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
  302.     old = dirptrs[i].lastused;
  303.     oldi = i;
  304.       }
  305.     i = oldi;
  306.   }
  307.  
  308.   /* a 3rd option - grab the oldest one */
  309.   if (i == -1) {
  310.     old=dircounter+1;
  311.     oldi= -1;
  312.     for (i=0;i<NUMDIRPTRS;i++)
  313.       if (dirptrs[i].lastused < old) {
  314.     old = dirptrs[i].lastused;
  315.     oldi = i;
  316.       }
  317.     i = oldi;
  318.   }
  319.  
  320.   if (i == -1) {
  321.     DEBUG(0,("Error - all dirptrs in use??\n"));
  322.     return(-1);
  323.   }
  324.  
  325.   if (dirptrs[i].valid)
  326.     dptr_close(i);
  327.  
  328.   dirptrs[i].ptr = Connections[cnum].dirptr;
  329.   string_set(&dirptrs[i].path,path);
  330.   dirptrs[i].lastused = dircounter++;
  331.   dirptrs[i].finished = False;
  332.   dirptrs[i].cnum = cnum;
  333.   dirptrs[i].pid = pid;
  334.   dirptrs[i].expect_close = expect_close;
  335.   dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
  336.   dirptrs[i].attr = 0; /* Only used in lanman2 searches */
  337.   dirptrs[i].valid = True;
  338.  
  339.   DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
  340.        i,path,expect_close));  
  341.  
  342.   return(i);
  343. }
  344.  
  345. #define DPTR_MASK ((uint32)(((uint32)1)<<31))
  346.  
  347. /****************************************************************************
  348. fill the 5 byte server reserved dptr field
  349. ****************************************************************************/
  350. BOOL dptr_fill(char *buf1,unsigned int key)
  351. {
  352.   unsigned char *buf = (unsigned char *)buf1;
  353.   void *p = dptr_get(key,0);
  354.   uint32 offset;
  355.   if (!p) {
  356.     DEBUG(1,("filling null dirptr %d\n",key));
  357.     return(False);
  358.   }
  359.   offset = TellDir(p);
  360.   DEBUG(6,("fill on key %d dirptr 0x%x now at %d\n",key,p,offset));
  361.   buf[0] = key;
  362.   SIVAL(buf,1,offset | DPTR_MASK);
  363.   return(True);
  364. }
  365.  
  366.  
  367. /****************************************************************************
  368. return True is the offset is at zero
  369. ****************************************************************************/
  370. BOOL dptr_zero(char *buf)
  371. {
  372.   return((IVAL(buf,1)&~DPTR_MASK) == 0);
  373. }
  374.  
  375. /****************************************************************************
  376. fetch the dir ptr and seek it given the 5 byte server field
  377. ****************************************************************************/
  378. void *dptr_fetch(char *buf,int *num)
  379. {
  380.   unsigned int key = *(unsigned char *)buf;
  381.   void *p = dptr_get(key,dircounter++);
  382.   uint32 offset;
  383.   if (!p) {
  384.     DEBUG(3,("fetched null dirptr %d\n",key));
  385.     return(NULL);
  386.   }
  387.   *num = key;
  388.   offset = IVAL(buf,1)&~DPTR_MASK;
  389.   SeekDir(p,offset);
  390.   DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
  391.        key,dptr_path(key),offset));
  392.   return(p);
  393. }
  394.  
  395. /****************************************************************************
  396. fetch the dir ptr.
  397. ****************************************************************************/
  398. void *dptr_fetch_lanman2(int dptr_num)
  399. {
  400.   void *p = dptr_get(dptr_num,dircounter++);
  401.  
  402.   if (!p) {
  403.     DEBUG(3,("fetched null dirptr %d\n",dptr_num));
  404.     return(NULL);
  405.   }
  406.   DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
  407.   return(p);
  408. }
  409.  
  410. /****************************************************************************
  411. check a filetype for being valid
  412. ****************************************************************************/
  413. BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype)
  414. {
  415.   if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
  416.     return False;
  417.   return True;
  418. }
  419.  
  420. /****************************************************************************
  421.   get a directory entry
  422. ****************************************************************************/
  423. BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
  424. {
  425.   char *dname;
  426.   BOOL found = False;
  427.   struct stat sbuf;
  428.   pstring path;
  429.   pstring pathreal;
  430.   BOOL isrootdir;
  431.   pstring filename;
  432.   BOOL matched;
  433.   BOOL needslash;
  434.  
  435.   *path = *pathreal = *filename = 0;
  436.  
  437.   isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
  438.            strequal(Connections[cnum].dirpath,".") ||
  439.            strequal(Connections[cnum].dirpath,"/"));
  440.   
  441.   needslash = 
  442.         ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
  443.  
  444.   if (!Connections[cnum].dirptr)
  445.     return(False);
  446.   
  447.   while (!found)
  448.     {
  449.       dname = ReadDirName(Connections[cnum].dirptr);
  450.  
  451.       DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
  452.         Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
  453.       
  454.       if (dname == NULL) 
  455.     return(False);
  456.       
  457.       matched = False;
  458.  
  459.       pstrcpy(filename,dname);      
  460.  
  461.       if ((strcmp(filename,mask) == 0) ||
  462.       (name_map_mangle(filename,True,SNUM(cnum)) &&
  463.        mask_match(filename,mask,False,False)))
  464.     {
  465.       if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
  466.         continue;
  467.  
  468.       pstrcpy(fname,filename);
  469.       *path = 0;
  470.       pstrcpy(path,Connections[cnum].dirpath);
  471.           if(needslash)
  472.           pstrcat(path,"/");
  473.       pstrcpy(pathreal,path);
  474.       pstrcat(path,fname);
  475.       pstrcat(pathreal,dname);
  476.       if (sys_stat(pathreal,&sbuf) != 0) 
  477.         {
  478.           DEBUG(5,("Couldn't stat 1 [%s]\n",path));
  479.           continue;
  480.         }
  481.  
  482.       if (check_descend &&
  483.           !strequal(fname,".") && !strequal(fname,".."))
  484.         continue;
  485.       
  486.       *mode = dos_mode(cnum,pathreal,&sbuf);
  487.  
  488.       if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
  489.         DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
  490.         continue;
  491.       }
  492.  
  493.       *size = sbuf.st_size;
  494.       *date = sbuf.st_mtime;
  495.  
  496.       DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
  497.       
  498.       found = True;
  499.     }
  500.     }
  501.  
  502.   return(found);
  503. }
  504.  
  505.  
  506.  
  507. typedef struct
  508. {
  509.   int pos;
  510.   int numentries;
  511.   int mallocsize;
  512.   char *data;
  513.   char *current;
  514. } Dir;
  515.  
  516.  
  517. /*******************************************************************
  518. open a directory
  519. ********************************************************************/
  520. void *OpenDir(int cnum, char *name, BOOL use_veto)
  521. {
  522.   Dir *dirp;
  523.   char *n;
  524.   void *p = sys_opendir(name);
  525.   int used=0;
  526.  
  527.   if (!p) return(NULL);
  528.   dirp = (Dir *)malloc(sizeof(Dir));
  529.   if (!dirp) {
  530.     closedir(p);
  531.     return(NULL);
  532.   }
  533.   dirp->pos = dirp->numentries = dirp->mallocsize = 0;
  534.   dirp->data = dirp->current = NULL;
  535.  
  536.   while ((n = readdirname(p)))
  537.   {
  538.     int l = strlen(n)+1;
  539.  
  540.     /* If it's a vetoed file, pretend it doesn't even exist */
  541.     if (use_veto && IS_VETO_PATH(cnum, n)) continue;
  542.  
  543.     if (used + l > dirp->mallocsize) {
  544.       int s = MAX(used+l,used+2000);
  545.       char *r;
  546.       r = (char *)Realloc(dirp->data,s);
  547.       if (!r) {
  548.     DEBUG(0,("Out of memory in OpenDir\n"));
  549.     break;
  550.       }
  551.       dirp->data = r;
  552.       dirp->mallocsize = s;
  553.       dirp->current = dirp->data;
  554.     }
  555.     pstrcpy(dirp->data+used,n);
  556.     used += l;
  557.     dirp->numentries++;
  558.   }
  559.  
  560.   closedir(p);
  561.   return((void *)dirp);
  562. }
  563.  
  564.  
  565. /*******************************************************************
  566. close a directory
  567. ********************************************************************/
  568. void CloseDir(void *p)
  569. {
  570.   Dir *dirp = (Dir *)p;
  571.   if (!dirp) return;    
  572.   if (dirp->data) free(dirp->data);
  573.   free(dirp);
  574. }
  575.  
  576. /*******************************************************************
  577. read from a directory
  578. ********************************************************************/
  579. char *ReadDirName(void *p)
  580. {
  581.   char *ret;
  582.   Dir *dirp = (Dir *)p;
  583.  
  584.   if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
  585.  
  586.   ret = dirp->current;
  587.   dirp->current = skip_string(dirp->current,1);
  588.   dirp->pos++;
  589.  
  590.   return(ret);
  591. }
  592.  
  593.  
  594. /*******************************************************************
  595. seek a dir
  596. ********************************************************************/
  597. BOOL SeekDir(void *p,int pos)
  598. {
  599.   Dir *dirp = (Dir *)p;
  600.  
  601.   if (!dirp) return(False);
  602.  
  603.   if (pos < dirp->pos) {
  604.     dirp->current = dirp->data;
  605.     dirp->pos = 0;
  606.   }
  607.  
  608.   while (dirp->pos < pos && ReadDirName(p)) ;
  609.  
  610.   return(dirp->pos == pos);
  611. }
  612.  
  613. /*******************************************************************
  614. tell a dir position
  615. ********************************************************************/
  616. int TellDir(void *p)
  617. {
  618.   Dir *dirp = (Dir *)p;
  619.  
  620.   if (!dirp) return(-1);
  621.   
  622.   return(dirp->pos);
  623. }
  624.  
  625.  
  626. /* -------------------------------------------------------------------------- **
  627.  * This section manages a global directory cache.
  628.  * (It should probably be split into a separate module.  crh)
  629.  * -------------------------------------------------------------------------- **
  630.  */
  631.  
  632. typedef struct
  633.   {
  634.   ubi_dlNode  node;
  635.   char       *path;
  636.   char       *name;
  637.   char       *dname;
  638.   int         snum;
  639.   } dir_cache_entry;
  640.  
  641. static ubi_dlList dir_cache[1] = { { NULL, NULL, 0 } };
  642.  
  643. void DirCacheAdd( char *path, char *name, char *dname, int snum )
  644.   /* ------------------------------------------------------------------------ **
  645.    * Add an entry to the directory cache.
  646.    *
  647.    *  Input:  path  -
  648.    *          name  -
  649.    *          dname -
  650.    *          snum  -
  651.    *
  652.    *  Output: None.
  653.    *
  654.    * ------------------------------------------------------------------------ **
  655.    */
  656.   {
  657.   int               pathlen;
  658.   int               namelen;
  659.   dir_cache_entry  *entry;
  660.  
  661.   /* Allocate the structure & string space in one go so that it can be freed
  662.    * in one call to free().
  663.    */
  664.   pathlen = strlen( path ) +1;  /* Bytes required to store path (with nul). */
  665.   namelen = strlen( name ) +1;  /* Bytes required to store name (with nul). */
  666.   entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
  667.                                    + pathlen
  668.                                    + namelen
  669.                                    + strlen( dname ) +1 );
  670.   if( NULL == entry )   /* Not adding to the cache is not fatal,  */
  671.     return;             /* so just return as if nothing happened. */
  672.  
  673.   /* Set pointers correctly and load values. */
  674.   entry->path  = pstrcpy( (char *)&entry[1],       path);
  675.   entry->name  = pstrcpy( &(entry->path[pathlen]), name);
  676.   entry->dname = pstrcpy( &(entry->name[namelen]), dname);
  677.   entry->snum  = snum;
  678.  
  679.   /* Add the new entry to the linked list. */
  680.   (void)ubi_dlAddHead( dir_cache, entry );
  681.   DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
  682.  
  683.   /* Free excess cache entries. */
  684.   while( DIRCACHESIZE < dir_cache->count )
  685.     free( ubi_dlRemTail( dir_cache ) );
  686.  
  687.   } /* DirCacheAdd */
  688.  
  689.  
  690. char *DirCacheCheck( char *path, char *name, int snum )
  691.   /* ------------------------------------------------------------------------ **
  692.    * Search for an entry to the directory cache.
  693.    *
  694.    *  Input:  path  -
  695.    *          name  -
  696.    *          snum  -
  697.    *
  698.    *  Output: The dname string of the located entry, or NULL if the entry was
  699.    *          not found.
  700.    *
  701.    *  Notes:  This uses a linear search, which is is okay because of
  702.    *          the small size of the cache.  Use a splay tree or hash
  703.    *          for large caches.
  704.    *
  705.    * ------------------------------------------------------------------------ **
  706.    */
  707.   {
  708.   dir_cache_entry *entry;
  709.  
  710.   for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
  711.        NULL != entry;
  712.        entry = (dir_cache_entry *)ubi_dlNext( entry ) )
  713.     {
  714.     if( entry->snum == snum
  715.         && 0 == strcmp( name, entry->name )
  716.         && 0 == strcmp( path, entry->path ) )
  717.       {
  718.       DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
  719.       return( entry->dname );
  720.       }
  721.     }
  722.  
  723.   return(NULL);
  724.   } /* DirCacheCheck */
  725.  
  726. void DirCacheFlush( int snum )
  727.   /* ------------------------------------------------------------------------ **
  728.    * Remove all cache entries which have an snum that matches the input.
  729.    *
  730.    *  Input:  snum  -
  731.    *
  732.    *  Output: None.
  733.    *
  734.    * ------------------------------------------------------------------------ **
  735.    */
  736.   {
  737.   dir_cache_entry *entry;
  738.   ubi_dlNodePtr    next;
  739.  
  740.   for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; )
  741.     {
  742.     next = ubi_dlNext( entry );
  743.     if( entry->snum == snum )
  744.       free( ubi_dlRemThis( dir_cache, entry ) );
  745.     entry = (dir_cache_entry *)next;
  746.     }
  747.   } /* DirCacheFlush */
  748.  
  749. /* -------------------------------------------------------------------------- **
  750.  * End of the section that manages the global directory cache.
  751.  * -------------------------------------------------------------------------- **
  752.  */
  753.  
  754.  
  755. #ifdef REPLACE_GETWD
  756. /* This is getcwd.c from bash.  It is needed in Interactive UNIX.  To
  757.  * add support for another OS you need to determine which of the
  758.  * conditional compilation macros you need to define.  All the options
  759.  * are defined for Interactive UNIX.
  760.  */
  761. #ifdef ISC
  762. #define HAVE_UNISTD_H
  763. #define USGr3
  764. #define USG
  765. #endif
  766.  
  767. #if defined (HAVE_UNISTD_H)
  768. #  include <unistd.h>
  769. #endif
  770.  
  771. #if defined (__STDC__)
  772. #  define CONST const
  773. #  define PTR void *
  774. #else /* !__STDC__ */
  775. #  define CONST
  776. #  define PTR char *
  777. #endif /* !__STDC__ */
  778.  
  779. #if !defined (PATH_MAX)
  780. #  if defined (MAXPATHLEN)
  781. #    define PATH_MAX MAXPATHLEN
  782. #  else /* !MAXPATHLEN */
  783. #    define PATH_MAX 1024
  784. #  endif /* !MAXPATHLEN */
  785. #endif /* !PATH_MAX */
  786.  
  787. #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
  788. #  if !defined (HAVE_DIRENT)
  789. #    define HAVE_DIRENT
  790. #  endif /* !HAVE_DIRENT */
  791. #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
  792.  
  793. #if defined (HAVE_DIRENT)
  794. #  define D_NAMLEN(d)    (strlen ((d)->d_name))
  795. #else
  796. #  define D_NAMLEN(d)    ((d)->d_namlen)
  797. #endif /* ! (_POSIX_VERSION || USGr3) */
  798.  
  799. #if defined (USG) || defined (USGr3)
  800. #  define d_fileno d_ino
  801. #endif
  802.  
  803. #if !defined (alloca)
  804. extern char *alloca ();
  805. #endif /* alloca */
  806.  
  807. /* Get the pathname of the current working directory,
  808.    and put it in SIZE bytes of BUF.  Returns NULL if the
  809.    directory couldn't be determined or SIZE was too small.
  810.    If successful, returns BUF.  In GNU, if BUF is NULL,
  811.    an array is allocated with `malloc'; the array is SIZE
  812.    bytes long, unless SIZE <= 0, in which case it is as
  813.    big as necessary.  */
  814. #if defined (__STDC__)
  815. char *
  816. getcwd (char *buf, size_t size)
  817. #else /* !__STDC__ */
  818. char *
  819. getcwd (buf, size)
  820.      char *buf;
  821.      int size;
  822. #endif /* !__STDC__ */
  823. {
  824.   static CONST char dots[]
  825.     = "../../../../../../../../../../../../../../../../../../../../../../../\
  826. ../../../../../../../../../../../../../../../../../../../../../../../../../../\
  827. ../../../../../../../../../../../../../../../../../../../../../../../../../..";
  828.   CONST char *dotp, *dotlist;
  829.   size_t dotsize;
  830.   dev_t rootdev, thisdev;
  831.   ino_t rootino, thisino;
  832.   char path[PATH_MAX + 1];
  833.   register char *pathp;
  834.   char *pathbuf;
  835.   size_t pathsize;
  836.   struct stat st;
  837.  
  838.   if (buf != NULL && size == 0)
  839.     {
  840.       errno = EINVAL;
  841.       return ((char *)NULL);
  842.     }
  843.  
  844.   pathsize = sizeof (path);
  845.   pathp = &path[pathsize];
  846.   *--pathp = '\0';
  847.   pathbuf = path;
  848.  
  849.   if (stat (".", &st) < 0)
  850.     return ((char *)NULL);
  851.   thisdev = st.st_dev;
  852.   thisino = st.st_ino;
  853.  
  854.   if (stat ("/", &st) < 0)
  855.     return ((char *)NULL);
  856.   rootdev = st.st_dev;
  857.   rootino = st.st_ino;
  858.  
  859.   dotsize = sizeof (dots) - 1;
  860.   dotp = &dots[sizeof (dots)];
  861.   dotlist = dots;
  862.   while (!(thisdev == rootdev && thisino == rootino))
  863.     {
  864.       register DIR *dirstream;
  865.       register struct dirent *d;
  866.       dev_t dotdev;
  867.       ino_t dotino;
  868.       char mount_point;
  869.       int namlen;
  870.  
  871.       /* Look at the parent directory.  */
  872.       if (dotp == dotlist)
  873.     {
  874.       /* My, what a deep directory tree you have, Grandma.  */
  875.       char *new;
  876.       if (dotlist == dots)
  877.         {
  878.           new = malloc (dotsize * 2 + 1);
  879.           if (new == NULL)
  880.         goto lose;
  881.           memcpy (new, dots, dotsize);
  882.         }
  883.       else
  884.         {
  885.           new = realloc ((PTR) dotlist, dotsize * 2 + 1);
  886.           if (new == NULL)
  887.         goto lose;
  888.         }
  889.       memcpy (&new[dotsize], new, dotsize);
  890.       dotp = &new[dotsize];
  891.       dotsize *= 2;
  892.       new[dotsize] = '\0';
  893.       dotlist = new;
  894.     }
  895.  
  896.       dotp -= 3;
  897.  
  898.       /* Figure out if this directory is a mount point.  */
  899.       if (stat (dotp, &st) < 0)
  900.     goto lose;
  901.       dotdev = st.st_dev;
  902.       dotino = st.st_ino;
  903.       mount_point = dotdev != thisdev;
  904.  
  905.       /* Search for the last directory.  */
  906.       dirstream = opendir(dotp);
  907.       if (dirstream == NULL)
  908.     goto lose;
  909.       while ((d = (struct dirent *)readdir(dirstream)) != NULL)
  910.     {
  911.       if (d->d_name[0] == '.' &&
  912.           (d->d_name[1] == '\0' ||
  913.         (d->d_name[1] == '.' && d->d_name[2] == '\0')))
  914.         continue;
  915.       if (mount_point || d->d_fileno == thisino)
  916.         {
  917.           char *name;
  918.  
  919.           namlen = D_NAMLEN(d);
  920.           name = (char *)
  921.         alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
  922.           memcpy (name, dotp, dotlist + dotsize - dotp);
  923.           name[dotlist + dotsize - dotp] = '/';
  924.           memcpy (&name[dotlist + dotsize - dotp + 1],
  925.               d->d_name, namlen + 1);
  926.           if (lstat (name, &st) < 0)
  927.         {
  928.           int save = errno;
  929.           closedir(dirstream);
  930.           errno = save;
  931.           goto lose;
  932.         }
  933.           if (st.st_dev == thisdev && st.st_ino == thisino)
  934.         break;
  935.         }
  936.     }
  937.       if (d == NULL)
  938.     {
  939.       int save = errno;
  940.       closedir(dirstream);
  941.       errno = save;
  942.       goto lose;
  943.     }
  944.       else
  945.     {
  946.       size_t space;
  947.  
  948.       while ((space = pathp - pathbuf) <= namlen)
  949.         {
  950.           char *new;
  951.  
  952.           if (pathbuf == path)
  953.         {
  954.           new = malloc (pathsize * 2);
  955.           if (!new)
  956.             goto lose;
  957.         }
  958.           else
  959.         {
  960.           new = realloc ((PTR) pathbuf, (pathsize * 2));
  961.           if (!new)
  962.             goto lose;
  963.           pathp = new + space;
  964.         }
  965.           (void) memcpy (new + pathsize + space, pathp, pathsize - space);
  966.           pathp = new + pathsize + space;
  967.           pathbuf = new;
  968.           pathsize *= 2;
  969.         }
  970.  
  971.       pathp -= namlen;
  972.       (void) memcpy (pathp, d->d_name, namlen);
  973.       *--pathp = '/';
  974.       closedir(dirstream);
  975.     }
  976.  
  977.       thisdev = dotdev;
  978.       thisino = dotino;
  979.     }
  980.  
  981.   if (pathp == &path[sizeof(path) - 1])
  982.     *--pathp = '/';
  983.  
  984.   if (dotlist != dots)
  985.     free ((PTR) dotlist);
  986.  
  987.   {
  988.     size_t len = pathbuf + pathsize - pathp;
  989.     if (buf == NULL)
  990.       {
  991.     if (len < (size_t) size)
  992.       len = size;
  993.     buf = (char *) malloc (len);
  994.     if (buf == NULL)
  995.       goto lose2;
  996.       }
  997.     else if ((size_t) size < len)
  998.       {
  999.     errno = ERANGE;
  1000.     goto lose2;
  1001.       }
  1002.     (void) memcpy((PTR) buf, (PTR) pathp, len);
  1003.   }
  1004.  
  1005.   if (pathbuf != path)
  1006.     free (pathbuf);
  1007.  
  1008.   return (buf);
  1009.  
  1010.  lose:
  1011.   if ((dotlist != dots) && dotlist)
  1012.     {
  1013.       int e = errno;
  1014.       free ((PTR) dotlist);
  1015.       errno = e;
  1016.     }
  1017.  
  1018.  lose2:
  1019.   if ((pathbuf != path) && pathbuf)
  1020.     {
  1021.       int e = errno;
  1022.       free ((PTR) pathbuf);
  1023.       errno = e;
  1024.     }
  1025.   return ((char *)NULL);
  1026. }
  1027. #endif
  1028.