Made changes to the dir cache functions:
[samba.git] / source3 / smbd / dir.c
index 32f2eb5e7de526cc00f692a815f74929e9bc1bc1..d69ccfe1c190e5de88dc767674abe5c49dc4bfcb 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Directory handling routines
-   Copyright (C) Andrew Tridgell 1992-1995
+   Copyright (C) Andrew Tridgell 1992-1997
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
 */
 
 #include "includes.h"
-#include "loadparm.h"
 
 extern int DEBUGLEVEL;
 extern connection_struct Connections[];
@@ -111,16 +110,18 @@ get the dir ptr for a dir index
 ****************************************************************************/
 static void *dptr_get(int key,uint32 lastused)
 {
-  if (dirptrs[key].valid) {
-    if (lastused) dirptrs[key].lastused = lastused;
-    if (!dirptrs[key].ptr) {
+  struct dptr_struct *dp = &dirptrs[key];
+
+  if (dp->valid) {
+    if (lastused) dp->lastused = lastused;
+    if (!dp->ptr) {
       if (dptrs_open >= MAXDIR)
        dptr_idleoldest();
       DEBUG(4,("Reopening dptr key %d\n",key));
-      if ((dirptrs[key].ptr = OpenDir(dirptrs[key].path)))
+      if ((dp->ptr = OpenDir(dp->cnum, dp->path, True)))
        dptrs_open++;
     }
-    return(dirptrs[key].ptr);
+    return(dp->ptr);
   }
   return(NULL);
 }
@@ -260,7 +261,7 @@ static BOOL start_dir(int cnum,char *directory)
   if (! *directory)
     directory = ".";
 
-  Connections[cnum].dirptr = OpenDir(directory);
+  Connections[cnum].dirptr = OpenDir(cnum, directory, True);
   if (Connections[cnum].dirptr) {    
     dptrs_open++;
     string_set(&Connections[cnum].dirpath,directory);
@@ -281,7 +282,7 @@ int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
   int oldi;
 
   if (!start_dir(cnum,path))
-    return(-1);
+    return(-2); /* Code to say use a unix error return code. */
 
   if (dptrs_open >= MAXDIR)
     dptr_idleoldest();
@@ -434,6 +435,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
   BOOL isrootdir;
   pstring filename;
   BOOL matched;
+  BOOL needslash;
 
   *path = *pathreal = *filename = 0;
 
@@ -441,6 +443,9 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
               strequal(Connections[cnum].dirpath,".") ||
               strequal(Connections[cnum].dirpath,"/"));
   
+  needslash = 
+        ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
+
   if (!Connections[cnum].dirptr)
     return(False);
   
@@ -456,7 +461,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
       
       matched = False;
 
-      strcpy(filename,dname);      
+      pstrcpy(filename,dname);      
 
       if ((strcmp(filename,mask) == 0) ||
          (name_map_mangle(filename,True,SNUM(cnum)) &&
@@ -465,11 +470,12 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
          if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
            continue;
 
-         strcpy(fname,filename);
+         pstrcpy(fname,filename);
          *path = 0;
-         strcpy(path,Connections[cnum].dirpath);
-         strcat(path,"/");
-         strcpy(pathreal,path);
+         pstrcpy(path,Connections[cnum].dirpath);
+          if(needslash)
+           strcat(path,"/");
+         pstrcpy(pathreal,path);
          strcat(path,fname);
          strcat(pathreal,dname);
          if (sys_stat(pathreal,&sbuf) != 0) 
@@ -516,7 +522,7 @@ typedef struct
 /*******************************************************************
 open a directory
 ********************************************************************/
-void *OpenDir(char *name)
+void *OpenDir(int cnum, char *name, BOOL use_veto)
 {
   Dir *dirp;
   char *n;
@@ -532,8 +538,13 @@ void *OpenDir(char *name)
   dirp->pos = dirp->numentries = dirp->mallocsize = 0;
   dirp->data = dirp->current = NULL;
 
-  while ((n = readdirname(p))) {
+  while ((n = readdirname(p)))
+  {
     int l = strlen(n)+1;
+
+    /* If it's a vetoed file, pretend it doesn't even exist */
+    if (use_veto && IS_VETO_PATH(cnum, n)) continue;
+
     if (used + l > dirp->mallocsize) {
       int s = MAX(used+l,used+2000);
       char *r;
@@ -617,90 +628,135 @@ int TellDir(void *p)
 }
 
 
-static int dir_cache_size = 0;
-static struct dir_cache {
-  struct dir_cache *next;
-  struct dir_cache *prev;
-  char *path;
-  char *name;
-  char *dname;
-  int snum;
-} *dir_cache = NULL;
+/* -------------------------------------------------------------------------- **
+ * This section manages a global directory cache.
+ * (It should probably be split into a separate module.  crh)
+ * -------------------------------------------------------------------------- **
+ */
 
-/*******************************************************************
-add an entry to the directory cache
-********************************************************************/
-void DirCacheAdd(char *path,char *name,char *dname,int snum)
-{
-  struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
-  if (!entry) return;
-  entry->path = strdup(path);
-  entry->name = strdup(name);
-  entry->dname = strdup(dname);
-  entry->snum = snum;
-  if (!entry->path || !entry->name || !entry->dname) return;
-
-  entry->next = dir_cache;
-  entry->prev = NULL;
-  if (entry->next) entry->next->prev = entry;
-  dir_cache = entry;
-
-  DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
-  
-  if (dir_cache_size == DIRCACHESIZE) {
-    for (entry=dir_cache; entry->next; entry=entry->next) ;
-    free(entry->path);
-    free(entry->name);
-    free(entry->dname);
-    if (entry->prev) entry->prev->next = entry->next;
-    free(entry);
-  } else {
-    dir_cache_size++;
-  }
-}
+#include "ubi_dLinkList.h"
 
+typedef struct
+  {
+  ubi_dlNode  node;
+  char       *path;
+  char       *name;
+  char       *dname;
+  int         snum;
+  } dir_cache_entry;
+
+static ubi_dlList dir_cache[1] = { { NULL, NULL, 0 } };
+
+void DirCacheAdd( char *path, char *name, char *dname, int snum )
+  /* ------------------------------------------------------------------------ **
+   * Add an entry to the directory cache.
+   *
+   *  Input:  path  -
+   *          name  -
+   *          dname -
+   *          snum  -
+   *
+   *  Output: None.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  int               pathlen;
+  int               namelen;
+  dir_cache_entry  *entry;
+
+  /* Allocate the structure & string space in one go so that it can be freed
+   * in one call to free().
+   */
+  pathlen = strlen( path ) +1;  /* Bytes required to store path (with nul). */
+  namelen = strlen( name ) +1;  /* Bytes required to store name (with nul). */
+  entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
+                                   + pathlen
+                                   + namelen
+                                   + strlen( dname ) +1 );
+  if( NULL == entry )   /* Not adding to the cache is not fatal,  */
+    return;             /* so just return as if nothing happened. */
+
+  /* Set pointers correctly and load values. */
+  entry->path  = strcpy( (char *)&entry[1],       path);
+  entry->name  = strcpy( &(entry->path[pathlen]), name);
+  entry->dname = strcpy( &(entry->name[namelen]), dname);
+  entry->snum  = snum;
+
+  /* Add the new entry to the linked list. */
+  (void)ubi_dlAddHead( dir_cache, entry );
+  DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
+
+  /* Free excess cache entries. */
+  while( DIRCACHESIZE < dir_cache->count )
+    free( ubi_dlRemTail( dir_cache ) );
+
+  } /* DirCacheAdd */
+
+
+char *DirCacheCheck( char *path, char *name, int snum )
+  /* ------------------------------------------------------------------------ **
+   * Search for an entry to the directory cache.
+   *
+   *  Input:  path  -
+   *          name  -
+   *          snum  -
+   *
+   *  Output: The dname string of the located entry, or NULL if the entry was
+   *          not found.
+   *
+   *  Notes:  This uses a linear search, which is is okay because of
+   *          the small size of the cache.  Use a splay tree or hash
+   *          for large caches.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  dir_cache_entry *entry;
 
-/*******************************************************************
-check for an entry in the directory cache
-********************************************************************/
-char *DirCacheCheck(char *path,char *name,int snum)
-{
-  struct dir_cache *entry;
-
-  for (entry=dir_cache; entry; entry=entry->next) {
-    if (entry->snum == snum &&
-       strcmp(path,entry->path) == 0 &&
-       strcmp(name,entry->name) == 0) {
-      DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
-      return(entry->dname);
+  for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
+       NULL != entry;
+       entry = (dir_cache_entry *)ubi_dlNext( entry ) )
+    {
+    if( entry->snum == snum
+        && 0 == strcmp( name, entry->name )
+        && 0 == strcmp( path, entry->path ) )
+      {
+      DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
+      return( entry->dname );
+      }
     }
-  }
 
   return(NULL);
-}
+  } /* DirCacheCheck */
+
+void DirCacheFlush( int snum )
+  /* ------------------------------------------------------------------------ **
+   * Remove all cache entries which have an snum that matches the input.
+   *
+   *  Input:  snum  -
+   *
+   *  Output: None.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  dir_cache_entry *entry;
+  ubi_dlNodePtr    next;
 
-/*******************************************************************
-flush entries in the dir_cache
-********************************************************************/
-void DirCacheFlush(int snum)
-{
-  struct dir_cache *entry,*next;
-
-  for (entry=dir_cache; entry; entry=next) {
-    if (entry->snum == snum) {
-      free(entry->path);
-      free(entry->dname);
-      free(entry->name);
-      next = entry->next;
-      if (entry->prev) entry->prev->next = entry->next;
-      if (entry->next) entry->next->prev = entry->prev;
-      if (dir_cache == entry) dir_cache = entry->next; 
-      free(entry);
-    } else {
-      next = entry->next;
+  for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; )
+    {
+    next = ubi_dlNext( entry );
+    if( entry->snum == snum )
+      free( ubi_dlRemThis( dir_cache, entry ) );
+    entry = (dir_cache_entry *)next;
     }
-  }
-}
+  } /* DirCacheFlush */
+
+/* -------------------------------------------------------------------------- **
+ * End of the section that manages the global directory cache.
+ * -------------------------------------------------------------------------- **
+ */
 
 
 #ifdef REPLACE_GETWD