first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[sfrench/samba-autobuild/.git] / source3 / smbd / dir.c
index b7ae2af47cb867c5b194efc274b389dc5adfa416..28faa9a06b7eea04f31eb95e48b9265235304b19 100644 (file)
@@ -27,257 +27,378 @@ extern int DEBUGLEVEL;
    This module implements directory related functions for Samba.
 */
 
-
-
-static uint32 dircounter = 0;
-
-
-#define NUMDIRPTRS 256
-
-
-static struct dptr_struct {
-       int pid;
+typedef struct _dptr_struct {
+       struct _dptr_struct *next, *prev;
+       int dnum;
+       uint16 spid;
        connection_struct *conn;
-       uint32 lastused;
        void *ptr;
-       BOOL valid;
-       BOOL finished;
        BOOL expect_close;
        char *wcard; /* Field only used for trans2_ searches */
        uint16 attr; /* Field only used for trans2_ searches */
        char *path;
-}
-dirptrs[NUMDIRPTRS];
+} dptr_struct;
 
+static struct bitmap *dptr_bmap;
+static dptr_struct *dirptrs;
 
 static int dptrs_open = 0;
 
+#define INVALID_DPTR_KEY (-3)
+
 /****************************************************************************
-initialise the dir array
+ Initialise the dir bitmap.
 ****************************************************************************/
+
 void init_dptrs(void)
 {
   static BOOL dptrs_init=False;
-  int i;
 
-  if (dptrs_init) return;
-  for (i=0;i<NUMDIRPTRS;i++)    
-    {
-      dirptrs[i].valid = False;
-      dirptrs[i].wcard = NULL;
-      dirptrs[i].ptr = NULL;
-      string_init(&dirptrs[i].path,"");
-    }
+  if (dptrs_init)
+    return;
+
+  dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
+
+  if (!dptr_bmap)
+    exit_server("out of memory in init_dptrs\n");
+
   dptrs_init = True;
 }
 
 /****************************************************************************
-idle a dptr - the directory is closed but the control info is kept
+ Idle a dptr - the directory is closed but the control info is kept.
 ****************************************************************************/
-static void dptr_idle(int key)
+
+static void dptr_idle(dptr_struct *dptr)
 {
-  if (dirptrs[key].valid && dirptrs[key].ptr) {
-    DEBUG(4,("Idling dptr key %d\n",key));
+  if (dptr->ptr) {
+    DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
     dptrs_open--;
-    CloseDir(dirptrs[key].ptr);
-    dirptrs[key].ptr = NULL;
-  }    
+    CloseDir(dptr->ptr);
+    dptr->ptr = NULL;
+  }
 }
 
 /****************************************************************************
-idle the oldest dptr
+ Idle the oldest dptr.
 ****************************************************************************/
+
 static void dptr_idleoldest(void)
 {
-  int i;
-  uint32 old=dircounter+1;
-  int oldi= -1;
-  for (i=0;i<NUMDIRPTRS;i++)
-    if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) {
-      old = dirptrs[i].lastused;
-      oldi = i;
+  dptr_struct *dptr;
+
+  /*
+   * Go to the end of the list.
+   */
+  for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+    ;
+
+  if(!dptr) {
+    DEBUG(0,("No dptrs available to idle ?\n"));
+    return;
+  }
+
+  /*
+   * Idle the oldest pointer.
+   */
+
+  for(; dptr; dptr = dptr->prev) {
+    if (dptr->ptr) {
+      dptr_idle(dptr);
+      return;
     }
-  if (oldi != -1)
-    dptr_idle(oldi);
-  else
-    DEBUG(0,("No dptrs available to idle??\n"));
+  }
 }
 
 /****************************************************************************
-get the dir ptr for a dir index
+ Get the dptr_struct for a dir index.
 ****************************************************************************/
-static void *dptr_get(int key,uint32 lastused)
+
+static dptr_struct *dptr_get(int key, BOOL forclose)
 {
-       struct dptr_struct *dp = &dirptrs[key];
-
-       if (dp->valid) {
-               if (lastused) dp->lastused = lastused;
-               if (!dp->ptr) {
-                       if (dptrs_open >= MAX_OPEN_DIRECTORIES)
-                               dptr_idleoldest();
-                       DEBUG(4,("Reopening dptr key %d\n",key));
-                       if ((dp->ptr = OpenDir(dp->conn, dp->path, True)))
-                               dptrs_open++;
-               }
-               return(dp->ptr);
-       }
-       return(NULL);
+  dptr_struct *dptr;
+
+  for(dptr = dirptrs; dptr; dptr = dptr->next) {
+    if(dptr->dnum == key) {
+      if (!forclose && !dptr->ptr) {
+        if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+          dptr_idleoldest();
+        DEBUG(4,("Reopening dptr key %d\n",key));
+        if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
+          dptrs_open++;
+      }
+      DLIST_PROMOTE(dirptrs,dptr);
+      return dptr;
+    }
+  }
+  return(NULL);
 }
 
 /****************************************************************************
-get the dir path for a dir index
+ Get the dptr ptr for a dir index.
 ****************************************************************************/
+
+static void *dptr_ptr(int key)
+{
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr)
+    return(dptr->ptr);
+  return(NULL);
+}
+
+/****************************************************************************
+ Get the dir path for a dir index.
+****************************************************************************/
+
 char *dptr_path(int key)
 {
-  if (dirptrs[key].valid)
-    return(dirptrs[key].path);
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr)
+    return(dptr->path);
   return(NULL);
 }
 
 /****************************************************************************
-get the dir wcard for a dir index (lanman2 specific)
+ Get the dir wcard for a dir index (lanman2 specific).
 ****************************************************************************/
+
 char *dptr_wcard(int key)
 {
-  if (dirptrs[key].valid)
-    return(dirptrs[key].wcard);
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr)
+    return(dptr->wcard);
   return(NULL);
 }
 
 /****************************************************************************
-set the dir wcard for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir wcard for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
 ****************************************************************************/
+
 BOOL dptr_set_wcard(int key, char *wcard)
 {
-  if (dirptrs[key].valid) {
-    dirptrs[key].wcard = wcard;
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr) {
+    dptr->wcard = wcard;
     return True;
   }
   return False;
 }
 
 /****************************************************************************
-set the dir attrib for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir attrib for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
 ****************************************************************************/
+
 BOOL dptr_set_attr(int key, uint16 attr)
 {
-  if (dirptrs[key].valid) {
-    dirptrs[key].attr = attr;
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr) {
+    dptr->attr = attr;
     return True;
   }
   return False;
 }
 
 /****************************************************************************
-get the dir attrib for a dir index (lanman2 specific)
+ Get the dir attrib for a dir index (lanman2 specific)
 ****************************************************************************/
+
 uint16 dptr_attr(int key)
 {
-  if (dirptrs[key].valid)
-    return(dirptrs[key].attr);
+  dptr_struct *dptr = dptr_get(key, False);
+
+  if (dptr)
+    return(dptr->attr);
   return(0);
 }
 
 /****************************************************************************
-close a dptr
+ Close a dptr (internal func).
+****************************************************************************/
+
+static void dptr_close_internal(dptr_struct *dptr)
+{
+  DEBUG(4,("closing dptr key %d\n",dptr->dnum));
+
+  DLIST_REMOVE(dirptrs, dptr);
+
+  /* 
+   * Free the dnum in the bitmap. Remember the dnum value is always 
+   * biased by one with respect to the bitmap.
+   */
+
+  if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
+    DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
+                       dptr->dnum ));
+  }
+
+  bitmap_clear(dptr_bmap, dptr->dnum - 1);
+
+  if (dptr->ptr) {
+    CloseDir(dptr->ptr);
+    dptrs_open--;
+  }
+
+  /* Lanman 2 specific code */
+  if (dptr->wcard)
+    free(dptr->wcard);
+  string_set(&dptr->path,"");
+  free((char *)dptr);
+}
+
+/****************************************************************************
+ Close a dptr given a key.
 ****************************************************************************/
-void dptr_close(int key)
+
+void dptr_close(int *key)
 {
+  dptr_struct *dptr;
+
+  if(*key == INVALID_DPTR_KEY)
+    return;
+
   /* OS/2 seems to use -1 to indicate "close all directories" */
-  if (key == -1) {
-    int i;
-    for (i=0;i<NUMDIRPTRS;i++) 
-      dptr_close(i);
+  if (*key == -1) {
+    dptr_struct *next;
+    for(dptr = dirptrs; dptr; dptr = next) {
+      next = dptr->next;
+      dptr_close_internal(dptr);
+    }
+    *key = INVALID_DPTR_KEY;
     return;
   }
 
-  if (key < 0 || key >= NUMDIRPTRS) {
-    DEBUG(3,("Invalid key %d given to dptr_close\n",key));
+  dptr = dptr_get(*key, True);
+
+  if (!dptr) {
+    DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
     return;
   }
 
-  if (dirptrs[key].valid) {
-    DEBUG(4,("closing dptr key %d\n",key));
-    if (dirptrs[key].ptr) {
-      CloseDir(dirptrs[key].ptr);
-      dptrs_open--;
-    }
-    /* Lanman 2 specific code */
-    if (dirptrs[key].wcard)
-      free(dirptrs[key].wcard);
-    dirptrs[key].valid = False;
-    string_set(&dirptrs[key].path,"");
-  }
+  dptr_close_internal(dptr);
+
+  *key = INVALID_DPTR_KEY;
 }
 
 /****************************************************************************
-close all dptrs for a cnum
+ Close all dptrs for a cnum.
 ****************************************************************************/
+
 void dptr_closecnum(connection_struct *conn)
 {
-  int i;
-  for (i=0;i<NUMDIRPTRS;i++)
-    if (dirptrs[i].valid && dirptrs[i].conn == conn)
-      dptr_close(i);
+  dptr_struct *dptr, *next;
+  for(dptr = dirptrs; dptr; dptr = next) {
+    next = dptr->next;
+    if (dptr->conn == conn)
+      dptr_close_internal(dptr);
+  }
 }
 
 /****************************************************************************
-idle all dptrs for a cnum
+ Idle all dptrs for a cnum.
 ****************************************************************************/
+
 void dptr_idlecnum(connection_struct *conn)
 {
-  int i;
-  for (i=0;i<NUMDIRPTRS;i++)
-    if (dirptrs[i].valid && dirptrs[i].conn == conn && dirptrs[i].ptr)
-      dptr_idle(i);
+  dptr_struct *dptr;
+  for(dptr = dirptrs; dptr; dptr = dptr->next) {
+    if (dptr->conn == conn && dptr->ptr)
+      dptr_idle(dptr);
+  }
 }
 
 /****************************************************************************
-close a dptr that matches a given path, only if it matches the pid also
+ Close a dptr that matches a given path, only if it matches the spid also.
 ****************************************************************************/
-void dptr_closepath(char *path,int pid)
+
+void dptr_closepath(char *path,uint16 spid)
 {
-  int i;
-  for (i=0;i<NUMDIRPTRS;i++)
-    if (dirptrs[i].valid && pid == dirptrs[i].pid &&
-       strequal(dirptrs[i].path,path))
-      dptr_close(i);
+  dptr_struct *dptr, *next;
+  for(dptr = dirptrs; dptr; dptr = next) {
+    next = dptr->next;
+    if (spid == dptr->spid && strequal(dptr->path,path))
+      dptr_close_internal(dptr);
+  }
 }
 
 /****************************************************************************
-  start a directory listing
+ Start a directory listing.
 ****************************************************************************/
+
 static BOOL start_dir(connection_struct *conn,char *directory)
 {
-       DEBUG(5,("start_dir dir=%s\n",directory));
+  DEBUG(5,("start_dir dir=%s\n",directory));
 
-       if (!check_name(directory,conn))
-               return(False);
+  if (!check_name(directory,conn))
+    return(False);
   
-       if (! *directory)
-               directory = ".";
-
-       conn->dirptr = OpenDir(conn, directory, True);
-       if (conn->dirptr) {    
-               dptrs_open++;
-               string_set(&conn->dirpath,directory);
-               return(True);
-       }
+  if (! *directory)
+    directory = ".";
+
+  conn->dirptr = OpenDir(conn, directory, True);
+  if (conn->dirptr) {    
+    dptrs_open++;
+    string_set(&conn->dirpath,directory);
+    return(True);
+  }
   
-       return(False);
+  return(False);
 }
 
+/****************************************************************************
+ Try and close the oldest handle not marked for
+ expect close in the hope that the client has
+ finished with that one.
+****************************************************************************/
+
+static void dptr_close_oldest(BOOL old)
+{
+  dptr_struct *dptr;
+
+  /*
+   * Go to the end of the list.
+   */
+  for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+    ;
+
+  if(!dptr) {
+    DEBUG(0,("No old dptrs available to close oldest ?\n"));
+    return;
+  }
+
+  /*
+   * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
+   * does not have expect_close set. If 'old' is false, close
+   * one of the new dnum handles.
+   */
+
+  for(; dptr; dptr = dptr->prev) {
+    if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
+        (!old && (dptr->dnum > 255))) {
+      dptr_close_internal(dptr);
+      return;
+    }
+  }
+}
 
 /****************************************************************************
-create a new dir ptr
+ Create a new dir ptr. If the flag old_handle is true then we must allocate
+ from the bitmap range 0 - 255 as old SMBsearch directory handles are only
+ one byte long. If old_handle is false we allocate from the range
+ 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
+ a directory handle is never zero. All the above is folklore taught to
+ me at Andrew's knee.... :-) :-). JRA.
 ****************************************************************************/
-int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
+
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
 {
-  int i;
-  uint32 old;
-  int oldi;
+  dptr_struct *dptr;
 
   if (!start_dir(conn,path))
     return(-2); /* Code to say use a unix error return code. */
@@ -285,70 +406,103 @@ int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
   if (dptrs_open >= MAX_OPEN_DIRECTORIES)
     dptr_idleoldest();
 
-  for (i=0;i<NUMDIRPTRS;i++)
-    if (!dirptrs[i].valid)
-      break;
-  if (i == NUMDIRPTRS) i = -1;
+  dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
+  if(!dptr) {
+    DEBUG(0,("malloc fail in dptr_create.\n"));
+    return -1;
+  }
+
+  ZERO_STRUCTP(dptr);
+
+  if(old_handle) {
+
+    /*
+     * This is an old-style SMBsearch request. Ensure the
+     * value we return will fit in the range 1-255.
+     */
+
+    dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+    if(dptr->dnum == -1 || dptr->dnum > 254) {
+
+      /*
+       * Try and close the oldest handle not marked for
+       * expect close in the hope that the client has
+       * finished with that one.
+       */
+
+      dptr_close_oldest(True);
 
+      /* Now try again... */
+      dptr->dnum = bitmap_find(dptr_bmap, 0);
 
-  /* as a 2nd option, grab the oldest not marked for expect_close */
-  if (i == -1) {
-    old=dircounter+1;
-    oldi= -1;
-    for (i=0;i<NUMDIRPTRS;i++)
-      if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
-       old = dirptrs[i].lastused;
-       oldi = i;
+      if(dptr->dnum == -1 || dptr->dnum > 254) {
+        DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
+        free((char *)dptr);
+        return -1;
       }
-    i = oldi;
-  }
+    }
+  } else {
+
+    /*
+     * This is a new-style trans2 request. Allocate from
+     * a range that will return 256 - MAX_DIRECTORY_HANDLES.
+     */
+
+    dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+    if(dptr->dnum == -1 || dptr->dnum < 255) {
 
-  /* a 3rd option - grab the oldest one */
-  if (i == -1) {
-    old=dircounter+1;
-    oldi= -1;
-    for (i=0;i<NUMDIRPTRS;i++)
-      if (dirptrs[i].lastused < old) {
-       old = dirptrs[i].lastused;
-       oldi = i;
+      /*
+       * Try and close the oldest handle close in the hope that
+       * the client has finished with that one. This will only
+       * happen in the case of the Win98 client bug where it leaks
+       * directory handles.
+       */
+
+      dptr_close_oldest(False);
+
+      /* Now try again... */
+      dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+      if(dptr->dnum == -1 || dptr->dnum < 255) {
+        DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
+        free((char *)dptr);
+        return -1;
       }
-    i = oldi;
+    }
   }
 
-  if (i == -1) {
-    DEBUG(0,("Error - all dirptrs in use??\n"));
-    return(-1);
-  }
+  bitmap_set(dptr_bmap, dptr->dnum);
+
+  dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
 
-  if (dirptrs[i].valid)
-    dptr_close(i);
+  dptr->ptr = conn->dirptr;
+  string_set(&dptr->path,path);
+  dptr->conn = conn;
+  dptr->spid = spid;
+  dptr->expect_close = expect_close;
+  dptr->wcard = NULL; /* Only used in lanman2 searches */
+  dptr->attr = 0; /* Only used in lanman2 searches */
 
-  dirptrs[i].ptr = conn->dirptr;
-  string_set(&dirptrs[i].path,path);
-  dirptrs[i].lastused = dircounter++;
-  dirptrs[i].finished = False;
-  dirptrs[i].conn = conn;
-  dirptrs[i].pid = pid;
-  dirptrs[i].expect_close = expect_close;
-  dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
-  dirptrs[i].attr = 0; /* Only used in lanman2 searches */
-  dirptrs[i].valid = True;
+  DLIST_ADD(dirptrs, dptr);
 
   DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
-          i,path,expect_close));  
+          dptr->dnum,path,expect_close));  
 
-  return(i);
+  return(dptr->dnum);
 }
 
 #define DPTR_MASK ((uint32)(((uint32)1)<<31))
 
 /****************************************************************************
-fill the 5 byte server reserved dptr field
+ Fill the 5 byte server reserved dptr field.
 ****************************************************************************/
+
 BOOL dptr_fill(char *buf1,unsigned int key)
 {
   unsigned char *buf = (unsigned char *)buf1;
-  void *p = dptr_get(key,0);
+  void *p = dptr_ptr(key);
   uint32 offset;
   if (!p) {
     DEBUG(1,("filling null dirptr %d\n",key));
@@ -364,20 +518,22 @@ BOOL dptr_fill(char *buf1,unsigned int key)
 
 
 /****************************************************************************
-return True is the offset is at zero
+ Return True if the offset is at zero.
 ****************************************************************************/
+
 BOOL dptr_zero(char *buf)
 {
   return((IVAL(buf,1)&~DPTR_MASK) == 0);
 }
 
 /****************************************************************************
-fetch the dir ptr and seek it given the 5 byte server field
+ Fetch the dir ptr and seek it given the 5 byte server field.
 ****************************************************************************/
+
 void *dptr_fetch(char *buf,int *num)
 {
   unsigned int key = *(unsigned char *)buf;
-  void *p = dptr_get(key,dircounter++);
+  void *p = dptr_ptr(key);
   uint32 offset;
   if (!p) {
     DEBUG(3,("fetched null dirptr %d\n",key));
@@ -392,11 +548,12 @@ void *dptr_fetch(char *buf,int *num)
 }
 
 /****************************************************************************
-fetch the dir ptr.
+ Fetch the dir ptr.
 ****************************************************************************/
+
 void *dptr_fetch_lanman2(int dptr_num)
 {
-  void *p = dptr_get(dptr_num,dircounter++);
+  void *p = dptr_ptr(dptr_num);
 
   if (!p) {
     DEBUG(3,("fetched null dirptr %d\n",dptr_num));
@@ -407,8 +564,9 @@ void *dptr_fetch_lanman2(int dptr_num)
 }
 
 /****************************************************************************
-check a filetype for being valid
+ Check a filetype for being valid.
 ****************************************************************************/
+
 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
 {
   if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
@@ -417,8 +575,9 @@ BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int di
 }
 
 /****************************************************************************
-  get a directory entry
+ Get an 8.3 directory entry.
 ****************************************************************************/
+
 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
                    SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
 {
@@ -437,64 +596,71 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
               strequal(conn->dirpath,".") ||
               strequal(conn->dirpath,"/"));
   
-  needslash = 
-        ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+  needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
 
   if (!conn->dirptr)
     return(False);
   
   while (!found)
-    {
-      dname = ReadDirName(conn->dirptr);
+  {
+    BOOL filename_is_mask = False;
+    dname = ReadDirName(conn->dirptr);
 
-      DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
-              (long)conn->dirptr,TellDir(conn->dirptr)));
+    DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
+          (long)conn->dirptr,TellDir(conn->dirptr)));
       
-      if (dname == NULL) 
-       return(False);
+    if (dname == NULL) 
+      return(False);
       
-      pstrcpy(filename,dname);      
-
-      if ((strcmp(filename,mask) == 0) ||
-         (name_map_mangle(filename,True,SNUM(conn)) &&
-          mask_match(filename,mask,False,False)))
-       {
-         if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
-           continue;
-
-         pstrcpy(fname,filename);
-         *path = 0;
-         pstrcpy(path,conn->dirpath);
-          if(needslash)
-           pstrcat(path,"/");
-         pstrcpy(pathreal,path);
-         pstrcat(path,fname);
-         pstrcat(pathreal,dname);
-         if (conn->vfs_ops.stat(dos_to_unix(pathreal, False), &sbuf) != 0) 
-           {
-             DEBUG(5,("Couldn't stat 1 [%s]\n",path));
-             continue;
-           }
-
-         if (check_descend &&
-             !strequal(fname,".") && !strequal(fname,".."))
-           continue;
+    pstrcpy(filename,dname);      
+
+    if ((filename_is_mask = (strcmp(filename,mask) == 0)) ||
+        (name_map_mangle(filename,True,False,SNUM(conn)) &&
+         mask_match(filename,mask,False,False)))
+    {
+      if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
+        continue;
+
+      pstrcpy(fname,filename);
+      *path = 0;
+      pstrcpy(path,conn->dirpath);
+      if(needslash)
+        pstrcat(path,"/");
+      pstrcpy(pathreal,path);
+      pstrcat(path,fname);
+      pstrcat(pathreal,dname);
+      if (dos_stat(pathreal,&sbuf) != 0) 
+      {
+        DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
+        continue;
+      }
+
+      if (check_descend && !strequal(fname,".") && !strequal(fname,".."))
+        continue;
          
-         *mode = dos_mode(conn,pathreal,&sbuf);
+      *mode = dos_mode(conn,pathreal,&sbuf);
+
+      if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) 
+      {
+        DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
+        continue;
+      }
 
-         if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
-           DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
-           continue;
-         }
+      if (!filename_is_mask)
+      {
+        /* Now we can allow the mangled cache to be updated */
+        pstrcpy(filename,dname);
+        name_map_mangle(filename,True,True,SNUM(conn));
+      }
 
-         *size = sbuf.st_size;
-         *date = sbuf.st_mtime;
+      *size = sbuf.st_size;
+      *date = sbuf.st_mtime;
 
-         DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
+      DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
          
-         found = True;
-       }
+      found = True;
     }
+  }
 
   return(found);
 }
@@ -512,25 +678,26 @@ typedef struct
 
 
 /*******************************************************************
-open a directory
+ Open a directory.
 ********************************************************************/
+
 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
 {
   Dir *dirp;
   char *n;
-  DIR *p = conn->vfs_ops.opendir(name);
+  DIR *p = dos_opendir(name);
   int used=0;
 
   if (!p) return(NULL);
   dirp = (Dir *)malloc(sizeof(Dir));
   if (!dirp) {
-    conn->vfs_ops.closedir(p);
+    closedir(p);
     return(NULL);
   }
   dirp->pos = dirp->numentries = dirp->mallocsize = 0;
   dirp->data = dirp->current = NULL;
 
-  while ((n = vfs_readdirname(conn, p)))
+  while ((n = dos_readdirname(p)))
   {
     int l = strlen(n)+1;
 
@@ -554,14 +721,15 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
     dirp->numentries++;
   }
 
-  conn->vfs_ops.closedir(p);
+  closedir(p);
   return((void *)dirp);
 }
 
 
 /*******************************************************************
-close a directory
+ Close a directory.
 ********************************************************************/
+
 void CloseDir(void *p)
 {
   Dir *dirp = (Dir *)p;
@@ -571,8 +739,9 @@ void CloseDir(void *p)
 }
 
 /*******************************************************************
-read from a directory
+ Read from a directory.
 ********************************************************************/
+
 char *ReadDirName(void *p)
 {
   char *ret;
@@ -589,8 +758,9 @@ char *ReadDirName(void *p)
 
 
 /*******************************************************************
-seek a dir
+ Seek a dir.
 ********************************************************************/
+
 BOOL SeekDir(void *p,int pos)
 {
   Dir *dirp = (Dir *)p;
@@ -608,8 +778,9 @@ BOOL SeekDir(void *p,int pos)
 }
 
 /*******************************************************************
-tell a dir position
+ Tell a dir position.
 ********************************************************************/
+
 int TellDir(void *p)
 {
   Dir *dirp = (Dir *)p;