r5063: Shamelessly steal the Samba4 logic (and some code :-) for directory
authorJeremy Allison <jra@samba.org>
Fri, 28 Jan 2005 21:01:58 +0000 (21:01 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:55:13 +0000 (10:55 -0500)
evaluation. This stops us from reading the entire directory into
memory at one go, and allows partial reads. It also keeps almost
the same interface to the OpenDir/ReadDir etc. code (sorry James :-).
Next I will optimise the findfirst with exact match code. This speeds
up our interactive response for large directories, but not when a
missing (ie. negative) findfirst is done.
Jeremy

source/smbd/dir.c
source/smbd/filename.c
source/smbd/notify_hash.c
source/smbd/reply.c
source/smbd/trans2.c

index f721bf3ba8a53671f56c2f207f298287112921a5..ff240b7e5a31f0a1721284f0b0e6830e3f62be0a 100644 (file)
@@ -612,9 +612,10 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname
                return(False);
 
        while (!found) {
-               dname = ReadDirName(conn->dirptr);
+               long curoff = TellDir(conn->dirptr);
+               dname = ReadDirName(conn->dirptr, &curoff);
 
-               DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
+               DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
                        (long)conn->dirptr,TellDir(conn->dirptr)));
       
                if (dname == NULL) 
@@ -667,14 +668,6 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname
        return(found);
 }
 
-typedef struct {
-       int pos;
-       int numentries;
-       int mallocsize;
-       char *data;
-       char *current;
-} Dir;
-
 /*******************************************************************
  Check to see if a user can read a file. This is only approximate,
  it is used as part of the "hide unreadable" option. Don't
@@ -806,117 +799,74 @@ static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT
        return True;
 }
 
+#define NAME_CACHE_SIZE 100
+
+struct name_cache_entry {
+       char *name;
+       long offset;
+};
+
+typedef struct {
+       connection_struct *conn;
+       DIR *dir;
+       long offset;
+       char *dir_path;
+       struct name_cache_entry *name_cache;
+       unsigned int name_cache_index;
+       BOOL hide_unreadable;
+       BOOL hide_unwriteable;
+       BOOL hide_special;
+       BOOL use_veto;
+       BOOL finished;
+} Dir;
+
 /*******************************************************************
  Open a directory.
 ********************************************************************/
 
 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
 {
-       Dir *dirp;
-       const char *n;
-       DIR *p = SMB_VFS_OPENDIR(conn,name);
-       int used=0;
-
-       if (!p)
-               return(NULL);
-       dirp = SMB_MALLOC_P(Dir);
+       Dir *dirp = SMB_MALLOC_P(Dir);
        if (!dirp) {
-               DEBUG(0,("Out of memory in OpenDir\n"));
-               SMB_VFS_CLOSEDIR(conn,p);
-               return(NULL);
+               return NULL;
        }
-       dirp->pos = dirp->numentries = dirp->mallocsize = 0;
-       dirp->data = dirp->current = NULL;
-
-       while (True) {
-               int l;
-               BOOL normal_entry = True;
-               SMB_STRUCT_STAT st;
-               char *entry = NULL;
-
-               if (used == 0) {
-                       n = ".";
-                       normal_entry = False;
-               } else if (used == 2) {
-                       n = "..";
-                       normal_entry = False;
-               } else {
-                       n = vfs_readdirname(conn, p);
-                       if (n == NULL)
-                               break;
-                       if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
-                               continue;
-                       normal_entry = True;
-               }
+       ZERO_STRUCTP(dirp);
 
-               ZERO_STRUCT(st);
-               l = strlen(n)+1;
+       dirp->conn = conn;
+       dirp->use_veto = use_veto;
 
-               /* If it's a vetoed file, pretend it doesn't even exist */
-               if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
-                       continue;
+       dirp->dir_path = SMB_STRDUP(name);
+       if (!dirp->dir_path) {
+               goto fail;
+       }
+       dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
+       if (!dirp->dir) {
+               DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
+               goto fail;
+       }
 
-               /* Honour _hide unreadable_ option */
-               if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
-                       int ret=0;
-      
-                       if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-                               ret = user_can_read_file(conn, entry, &st);
-                       }
-                       if (!ret) {
-                               SAFE_FREE(entry);
-                               continue;
-                       }
-               }
+       dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
+       if (!dirp->name_cache) {
+               goto fail;
+       }
 
-               /* Honour _hide unwriteable_ option */
-               if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
-                       int ret=0;
-      
-                       if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-                               ret = user_can_write_file(conn, entry, &st);
-                       }
-                       if (!ret) {
-                               SAFE_FREE(entry);
-                               continue;
-                       }
-               }
+       dirp->hide_unreadable = lp_hideunreadable(SNUM(conn));
+       dirp->hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
+       dirp->hide_special = lp_hide_special_files(SNUM(conn));
 
-               /* Honour _hide_special_ option */
-               if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
-                       int ret=0;
-      
-                       if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-                               ret = file_is_special(conn, entry, &st);
-                       }
-                       if (ret) {
-                               SAFE_FREE(entry);
-                               continue;
-                       }
-               }
+       return((void *)dirp);
 
-               SAFE_FREE(entry);
+  fail:
 
-               if (used + l > dirp->mallocsize) {
-                       int s = MAX(used+l,used+2000);
-                       char *r;
-                       r = (char *)SMB_REALLOC(dirp->data,s);
-                       if (!r) {
-                               DEBUG(0,("Out of memory in OpenDir\n"));
-                                       break;
-                       }
-                       dirp->data = r;
-                       dirp->mallocsize = s;
-                       dirp->current = dirp->data;
+       if (dirp) {
+               if (dirp->dir) {
+                       SMB_VFS_CLOSEDIR(conn,dirp->dir);
                }
-
-               safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize);
-               used += l;
-               dirp->numentries++;
+               SAFE_FREE(dirp->dir_path);
+               SAFE_FREE(dirp->name_cache);
+               SAFE_FREE(dirp);
        }
-
-       SMB_VFS_CLOSEDIR(conn,p);
-       return((void *)dirp);
+       return NULL;
 }
 
 
@@ -924,65 +874,195 @@ void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
  Close a directory.
 ********************************************************************/
 
-void CloseDir(void *p)
+int CloseDir(void *p)
 {
-       if (!p)
-               return;    
-       SAFE_FREE(((Dir *)p)->data);
-       SAFE_FREE(p);
+       int i, ret = 0;
+       Dir *dirp = (Dir *)p;
+
+       if (dirp->dir) {
+               ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
+       }
+       SAFE_FREE(dirp->dir_path);
+       if (dirp->name_cache) {
+               for (i = 0; i < NAME_CACHE_SIZE; i++) {
+                       SAFE_FREE(dirp->name_cache[i].name);
+               }
+       }
+       SAFE_FREE(dirp->name_cache);
+       SAFE_FREE(dirp);
+       return ret;
 }
 
 /*******************************************************************
Read from a directory.
Set a directory into an inactive state.
 ********************************************************************/
 
-const char *ReadDirName(void *p)
+static void SleepDir(Dir *dirp)
 {
-       char *ret;
-       Dir *dirp = (Dir *)p;
-
-       if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
-               return(NULL);
+       if (dirp->dir) {
+               SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
+               dirp->dir = 0;
+       }
+       dirp->offset = 0;
+}
 
-       ret = dirp->current;
-       dirp->current = skip_string(dirp->current,1);
-       dirp->pos++;
+/*******************************************************************
+ Wake a directory into a known state.
+********************************************************************/
 
-       return(ret);
+static int WakeDir(Dir *dirp, long offset)
+{
+       if (!dirp->dir) {
+               dirp->dir = SMB_VFS_OPENDIR(dirp->conn, dirp->dir_path);
+               if (!dirp->dir) {
+                       DEBUG(0,("WakeDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
+                       dirp->finished = True;
+                       return -1;
+               }
+       }
+       if (offset != dirp->offset) {
+               SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
+               dirp->offset = SMB_VFS_TELLDIR(dirp->conn, dirp->dir);
+               if (dirp->offset != offset) {
+                       DEBUG(0,("WakeDir: in path %s. offset changed %ld -> %ld\n",
+                               dirp->dir_path, offset, dirp->offset ));
+                       return -1;
+               }
+       }
+       return 0;
 }
 
 /*******************************************************************
Seek a dir.
Read from a directory. Also return current offset.
 ********************************************************************/
 
-BOOL SeekDir(void *p,int pos)
+const char *ReadDirName(void *p, long *poffset)
 {
+       const char *n;
        Dir *dirp = (Dir *)p;
+       connection_struct *conn = dirp->conn;
 
-       if (!dirp)
-               return(False);
+       if (WakeDir(dirp, *poffset) == -1) {
+               return NULL;
+       }
+
+       while ((n = vfs_readdirname(conn, dirp->dir))) {
+               struct name_cache_entry *e;
+
+               if (!((strcmp(".",n) == 0) || (strcmp("..",n) == 0))) {
+                       /* If it's a vetoed file, pretend it doesn't even exist */
+                       if (dirp->use_veto && IS_VETO_PATH(conn, n)) {
+                               continue;
+                       }
+
+                       if (dirp->hide_unreadable || dirp->hide_unwriteable || dirp->hide_special) {
+                               SMB_STRUCT_STAT st;
+                               ZERO_STRUCT(st);
+                               char *entry = NULL;
+
+                               if (asprintf(&entry, "%s/%s/%s", conn->origpath, dirp->dir_path, n) == -1) {
+                                       return NULL;
+                               }
+                               /* Honour _hide unreadable_ option */
+                               if (dirp->hide_unreadable && !user_can_read_file(conn, entry, &st)) {
+                                       SAFE_FREE(entry);
+                                       continue;
+                               }
+                               /* Honour _hide unwriteable_ option */
+                               if (dirp->hide_unwriteable && !user_can_write_file(conn, entry, &st)) {
+                                       SAFE_FREE(entry);
+                                       continue;
+                               }
+                               /* Honour _hide_special_ option */
+                               if (dirp->hide_special && !file_is_special(conn, entry, &st)) {
+                                       SAFE_FREE(entry);
+                                       continue;
+                               }
+                               SAFE_FREE(entry);
+                       }
+               }
+
+               dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
+               if (dirp->offset == -1) {
+                       return NULL;
+               }
+               dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
 
-       if (pos < dirp->pos) {
-               dirp->current = dirp->data;
-               dirp->pos = 0;
+               e = &dirp->name_cache[dirp->name_cache_index];
+               SAFE_FREE(e->name);
+               e->name = SMB_STRDUP(n);
+               *poffset = e->offset= dirp->offset;
+               return e->name;
        }
 
-       while (dirp->pos < pos && ReadDirName(p))
-               ;
+       dirp->finished = True;
+       SleepDir(dirp);
+       return NULL;
+}
+
+/*******************************************************************
+ Seek a dir.
+********************************************************************/
 
-       return (dirp->pos == pos);
+BOOL SeekDir(void *p,long offset)
+{
+       Dir *dirp = (Dir *)p;
+       return (WakeDir(dirp, offset) != -1);
 }
 
 /*******************************************************************
  Tell a dir position.
 ********************************************************************/
 
-int TellDir(void *p)
+long TellDir(void *p)
 {
        Dir *dirp = (Dir *)p;
+       return(dirp->offset);
+}
 
-       if (!dirp)
-               return(-1);
-  
-       return(dirp->pos);
+/*******************************************************************
+ Find an entry by name. Leave us at the offset after it.
+********************************************************************/
+
+BOOL SearchDir(void *p, const char *name, long *poffset, BOOL case_sensitive)
+{
+       int i;
+       Dir *dirp = (Dir *)p;
+       const char *entry;
+       connection_struct *conn = dirp->conn;
+
+       /* Re-create dir but don't seek. */
+       if (WakeDir(dirp, dirp->offset) == -1) {
+               return False;
+       }
+
+       /* Search back in the name cache. */
+       for (i = dirp->name_cache_index; i >= 0; i--) {
+               struct name_cache_entry *e = &dirp->name_cache[i];
+               if (e->name && (case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+                       *poffset = e->offset;
+                       WakeDir(dirp, e->offset);
+                       return True;
+               }
+       }
+       for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
+               struct name_cache_entry *e = &dirp->name_cache[i];
+               if (e->name && (case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+                       *poffset = e->offset;
+                       WakeDir(dirp, e->offset);
+                       return True;
+               }
+       }
+
+       /* Not found in the name cache. Rewind directory and start from scratch. */
+       SMB_VFS_REWINDDIR(conn, dirp->dir);
+       *poffset = 0;
+       while ((entry = ReadDirName(dirp, poffset))) {
+               if (case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
+                       return True;
+               }
+       }
+
+       SleepDir(dirp);
+       return False;
 }
index 279c9dd3c45bddd3b3c251cd6d9c9a5700768a15..fa8ddfd6ca996d01e10488f0714fa8412a30c848 100644 (file)
@@ -435,6 +435,7 @@ static BOOL scan_directory(connection_struct *conn, const char *path, char *name
        void *cur_dir;
        const char *dname;
        BOOL mangled;
+       long curpos;
 
        mangled = mangle_is_mangled(name);
 
@@ -459,7 +460,8 @@ static BOOL scan_directory(connection_struct *conn, const char *path, char *name
        }
 
        /* now scan for matching names */
-       while ((dname = ReadDirName(cur_dir))) {
+       curpos = 0;
+       while ((dname = ReadDirName(cur_dir, &curpos))) {
 
                /* Is it dot or dot dot. */
                if ((dname[0] == '.') && (!dname[1] || (dname[1] == '.' && !dname[2]))) {
index 843580f6edfc1df3e2b93e1a8750dd1233ed8524..80e8fee54a777fac835b64b9561e370bd5187c0f 100644 (file)
@@ -45,6 +45,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
        size_t remaining_len;
        size_t fullname_len;
        void *dp;
+       long offset;
 
        ZERO_STRUCTP(data);
 
@@ -88,7 +89,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
        remaining_len = sizeof(full_name) - fullname_len - 1;
        p = &full_name[fullname_len];
        
-       while ((fname = ReadDirName(dp))) {
+       offset = 0;
+       while ((fname = ReadDirName(dp, &offset))) {
                if(strequal(fname, ".") || strequal(fname, ".."))
                        continue;               
 
index 26a0c9e7a9b7225725eae2f315618da839d8dfdd..86ee331e6b2f8d71efb57330dbecb54eb8a32973 100644 (file)
@@ -1614,11 +1614,12 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                
                if (dirptr) {
                        error = NT_STATUS_NO_SUCH_FILE;
-                       
+                       long offset = 0;
+
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
 
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dirptr, &offset))) {
                                pstring fname;
                                BOOL sys_direntry = False;
                                pstrcpy(fname,dname);
@@ -3361,12 +3362,13 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
        const char *dname = NULL;
        BOOL ret = False;
+       long offset = 0;
        void *dirptr = OpenDir(conn, directory, False);
 
        if(dirptr == NULL)
                return True;
 
-       while((dname = ReadDirName(dirptr))) {
+       while((dname = ReadDirName(dirptr, &offset))) {
                pstring fullname;
                SMB_STRUCT_STAT st;
 
@@ -3428,8 +3430,8 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                void *dirptr = OpenDir(conn, directory, False);
 
                if(dirptr != NULL) {
-                       int dirpos = TellDir(dirptr);
-                       while ((dname = ReadDirName(dirptr))) {
+                       long dirpos = TellDir(dirptr);
+                       while ((dname = ReadDirName(dirptr,&dirpos))) {
                                if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
                                        continue;
                                if(!IS_VETO_PATH(conn, dname)) {
@@ -3440,7 +3442,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
 
                        if(all_veto_files) {
                                SeekDir(dirptr,dirpos);
-                               while ((dname = ReadDirName(dirptr))) {
+                               while ((dname = ReadDirName(dirptr,&dirpos))) {
                                        pstring fullname;
                                        SMB_STRUCT_STAT st;
 
@@ -3984,13 +3986,14 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        dirptr = OpenDir(conn, directory, True);
                
                if (dirptr) {
+                       long offset = 0;
                        error = NT_STATUS_NO_SUCH_FILE;
 /*                     Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */
                        
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
                        
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dirptr, &offset))) {
                                pstring fname;
                                BOOL sysdir_entry = False;
 
@@ -4337,12 +4340,13 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        dirptr = OpenDir(conn, directory, True);
 
                if (dirptr) {
+                       long offset = 0;
                        error = ERRbadfile;
 
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
 
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dirptr, &offset))) {
                                pstring fname;
                                pstrcpy(fname,dname);
     
index 7269ab91579a16ae8e0e924ab02b83ffaa696858..8d3055f6cf4a8b64c52898657de5a6b67a28c0ba 100644 (file)
@@ -837,7 +837,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        pstring fname;
        char *p, *q, *pdata = *ppdata;
        uint32 reskey=0;
-       int prev_dirpos=0;
+       long prev_dirpos=0;
        int mode=0;
        SMB_OFF_T file_size = 0;
        SMB_BIG_UINT allocation_size = 0;
@@ -866,10 +866,9 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
        while (!found) {
                BOOL got_match;
-
                /* Needed if we run out of space */
-               prev_dirpos = TellDir(conn->dirptr);
-               dname = ReadDirName(conn->dirptr);
+               long curr_dirpos = prev_dirpos = TellDir(conn->dirptr);
+               dname = ReadDirName(conn->dirptr,&curr_dirpos);
 
                /*
                 * Due to bugs in NT client redirectors we are not using
@@ -880,8 +879,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                reskey = 0;
 
-               DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
-                       (long)conn->dirptr,TellDir(conn->dirptr)));
+               DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n",
+                       (long)conn->dirptr,curr_dirpos));
       
                if (!dname) 
                        return(False);
@@ -1649,7 +1648,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
        /* Get the attr mask from the dptr */
        dirtype = dptr_attr(dptr_num);
 
-       DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
+       DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
                dptr_num, mask, dirtype, 
                (long)conn->dirptr,
                TellDir(conn->dirptr)));
@@ -1671,6 +1670,16 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
         */
 
        if(*resume_name && !continue_bit) {
+               long current_pos = 0;
+               /*
+                * Remember, mangle_map is called by
+                * get_lanman2_dir_entry(), so the resume name
+                * could be mangled. Ensure we check the unmangled name.
+                */
+
+               if (mangle_is_mangled(resume_name)) {
+                       mangle_check_cache(resume_name, sizeof(resume_name)-1);
+               }
 
                /*
                 * Fix for NT redirector problem triggered by resume key indexes
@@ -1678,77 +1687,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                 * and instead look for the filename to continue from (also given
                 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
                 * findfirst/findnext (as is usual) then the directory pointer
-                * should already be at the correct place. Check this by scanning
-                * backwards looking for an exact (ie. case sensitive) filename match. 
-                * If we get to the beginning of the directory and haven't found it then scan
-                * forwards again looking for a match. JRA.
+                * should already be at the correct place.
                 */
 
-               int current_pos, start_pos;
-               const char *dname = NULL;
-               pstring dname_pstring;
-               void *dirptr = conn->dirptr;
-               start_pos = TellDir(dirptr);
-               for(current_pos = start_pos; current_pos >= 0; current_pos--) {
-                       DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
-
-                       SeekDir(dirptr, current_pos);
-                       dname = ReadDirName(dirptr);
-                       if (dname) {
-                               /*
-                                * Remember, mangle_map is called by
-                                * get_lanman2_dir_entry(), so the resume name
-                                * could be mangled. Ensure we do the same
-                                * here.
-                                */
-                               
-                               /* make sure we get a copy that mangle_map can modify */
-
-                               pstrcpy(dname_pstring, dname);
-                               mangle_map( dname_pstring, False, True, SNUM(conn));
-                               
-                               if(strcsequal( resume_name, dname_pstring)) {
-                                       SeekDir(dirptr, current_pos+1);
-                                       DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                                       break;
-                               }
-                       }
-               }
-
-               /*
-                * Scan forward from start if not found going backwards.
-                */
-
-               if(current_pos < 0) {
-                       DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
-                       SeekDir(dirptr, start_pos);
-                       for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
-
-                               /*
-                                * Remember, mangle_map is called by
-                                * get_lanman2_dir_entry(), so the resume name
-                                * could be mangled. Ensure we do the same
-                                * here.
-                                */
-
-                               if(dname) {
-                                       /* make sure we get a copy that mangle_map can modify */
-                                       
-                                       pstrcpy(dname_pstring, dname);
-                                       mangle_map(dname_pstring, False, True, SNUM(conn));
-
-                                       if(strcsequal( resume_name, dname_pstring)) {
-                                               SeekDir(dirptr, current_pos+1);
-                                               DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                                               break;
-                                       }
-                               }
-                       } /* end for */
-               } /* end if current_pos */
-               /* Can't find the name. Just resume from where we were... */
-               if (dname == 0) {
-                       SeekDir(dirptr, start_pos);
-               }
+               finished = !SearchDir(conn->dirptr, resume_name, &current_pos, True);
        } /* end if resume_name && !continue_bit */
 
        for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {