r4067: no matches in findnext is not an error
[samba.git] / source / ntvfs / posix / pvfs_search.c
index 1d1d973d3ffce291644ddda6a1c997b0c1336c18..4ee81503c0a991c7412b1544792b8a5558450bb2 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "include/includes.h"
+#include "includes.h"
 #include "vfs_posix.h"
+#include "system/time.h"
+#include "system/filesys.h"
+
+
+/* the state of a search started with pvfs_search_first() */
+struct pvfs_search_state {
+       struct pvfs_state *pvfs;
+       uint16_t handle;
+       uint_t current_index;
+       uint16_t search_attrib;
+       uint16_t must_attrib;
+       struct pvfs_dir *dir;
+       time_t last_used;
+};
+
+
+/* place a reasonable limit on old-style searches as clients tend to
+   not send search close requests */
+#define MAX_OLD_SEARCHES 2000
+
+/*
+  destroy an open search
+*/
+static int pvfs_search_destructor(void *ptr)
+{
+       struct pvfs_search_state *search = ptr;
+       idr_remove(search->pvfs->idtree_search, search->handle);
+       return 0;
+}
 
 /*
   fill in a single search result for a given info level
@@ -36,34 +65,38 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
 {
        struct pvfs_filename *name;
        NTSTATUS status;
+       const char *shortname;
 
        status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       if (!pvfs_match_attrib(pvfs, name, search->search_attrib)) {
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       status = pvfs_match_attrib(pvfs, name, search->search_attrib, search->must_attrib);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        switch (level) {
        case RAW_SEARCH_SEARCH:
        case RAW_SEARCH_FFIRST:
        case RAW_SEARCH_FUNIQUE:
+               shortname = pvfs_short_name(pvfs, name, name);
                file->search.attrib           = name->dos.attrib;
                file->search.write_time       = nt_time_to_unix(name->dos.write_time);
                file->search.size             = name->st.st_size;
-               file->search.name             = fname;
-               file->search.id.reserved      = 8;
+               file->search.name             = shortname;
+               file->search.id.reserved      = search->handle >> 8;
                memset(file->search.id.name, ' ', sizeof(file->search.id.name));
-               memcpy(file->search.id.name, fname, MIN(strlen(fname)+1, sizeof(file->search.id.name)));
-               file->search.id.handle        = search->handle;
-               file->search.id.server_cookie = dir_index+1;
+               memcpy(file->search.id.name, shortname, 
+                      MIN(strlen(shortname)+1, sizeof(file->search.id.name)));
+               file->search.id.handle        = search->handle & 0xFF;
+               file->search.id.server_cookie = dir_index;
                file->search.id.client_cookie = 0;
                return NT_STATUS_OK;
 
        case RAW_SEARCH_STANDARD:
-               file->standard.resume_key   = dir_index+1;
+               file->standard.resume_key   = dir_index;
                file->standard.create_time  = nt_time_to_unix(name->dos.create_time);
                file->standard.access_time  = nt_time_to_unix(name->dos.access_time);
                file->standard.write_time   = nt_time_to_unix(name->dos.write_time);
@@ -74,7 +107,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                return NT_STATUS_OK;
 
        case RAW_SEARCH_EA_SIZE:
-               file->ea_size.resume_key   = dir_index+1;
+               file->ea_size.resume_key   = dir_index;
                file->ea_size.create_time  = nt_time_to_unix(name->dos.create_time);
                file->ea_size.access_time  = nt_time_to_unix(name->dos.access_time);
                file->ea_size.write_time   = nt_time_to_unix(name->dos.write_time);
@@ -86,7 +119,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                return NT_STATUS_OK;
 
        case RAW_SEARCH_DIRECTORY_INFO:
-               file->directory_info.file_index   = dir_index+1;
+               file->directory_info.file_index   = dir_index;
                file->directory_info.create_time  = name->dos.create_time;
                file->directory_info.access_time  = name->dos.access_time;
                file->directory_info.write_time   = name->dos.write_time;
@@ -98,7 +131,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                return NT_STATUS_OK;
 
        case RAW_SEARCH_FULL_DIRECTORY_INFO:
-               file->full_directory_info.file_index   = dir_index+1;
+               file->full_directory_info.file_index   = dir_index;
                file->full_directory_info.create_time  = name->dos.create_time;
                file->full_directory_info.access_time  = name->dos.access_time;
                file->full_directory_info.write_time   = name->dos.write_time;
@@ -116,7 +149,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                return NT_STATUS_OK;
 
        case RAW_SEARCH_BOTH_DIRECTORY_INFO:
-               file->both_directory_info.file_index   = dir_index+1;
+               file->both_directory_info.file_index   = dir_index;
                file->both_directory_info.create_time  = name->dos.create_time;
                file->both_directory_info.access_time  = name->dos.access_time;
                file->both_directory_info.write_time   = name->dos.write_time;
@@ -125,12 +158,12 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                file->both_directory_info.alloc_size   = name->dos.alloc_size;
                file->both_directory_info.attrib       = name->dos.attrib;
                file->both_directory_info.ea_size      = name->dos.ea_size;
-               file->both_directory_info.short_name.s = pvfs_short_name(pvfs, name);
+               file->both_directory_info.short_name.s = pvfs_short_name(pvfs, file, name);
                file->both_directory_info.name.s       = fname;
                return NT_STATUS_OK;
 
        case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
-               file->id_full_directory_info.file_index   = dir_index+1;
+               file->id_full_directory_info.file_index   = dir_index;
                file->id_full_directory_info.create_time  = name->dos.create_time;
                file->id_full_directory_info.access_time  = name->dos.access_time;
                file->id_full_directory_info.write_time   = name->dos.write_time;
@@ -144,7 +177,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                return NT_STATUS_OK;
 
        case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
-               file->id_both_directory_info.file_index   = dir_index+1;
+               file->id_both_directory_info.file_index   = dir_index;
                file->id_both_directory_info.create_time  = name->dos.create_time;
                file->id_both_directory_info.access_time  = name->dos.access_time;
                file->id_both_directory_info.write_time   = name->dos.write_time;
@@ -154,7 +187,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                file->id_both_directory_info.attrib       = name->dos.attrib;
                file->id_both_directory_info.ea_size      = name->dos.ea_size;
                file->id_both_directory_info.file_id      = name->dos.file_id;
-               file->id_both_directory_info.short_name.s = pvfs_short_name(pvfs, name);
+               file->id_both_directory_info.short_name.s = pvfs_short_name(pvfs, file, name);
                file->id_both_directory_info.name.s       = fname;
                return NT_STATUS_OK;
 
@@ -177,97 +210,97 @@ static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
                                 void *search_private, 
                                 BOOL (*callback)(void *, union smb_search_data *))
 {
-       int i;
        struct pvfs_dir *dir = search->dir;
        NTSTATUS status;
 
        *reply_count = 0;
 
-       for (i = search->current_index; i < dir->count;i++) {
+       if (max_count == 0) {
+               max_count = 1;
+       }
+
+       while ((*reply_count) < max_count) {
                union smb_search_data *file;
+               const char *name;
+               uint_t ofs = search->current_index;
+
+               name = pvfs_list_next(dir, &search->current_index);
+               if (name == NULL) break;
 
                file = talloc_p(mem_ctx, union smb_search_data);
                if (!file) {
                        return NT_STATUS_NO_MEMORY;
                }
 
-               status = fill_search_info(pvfs, level, dir->unix_path, dir->names[i], 
-                                         search, i, file);
-               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-                       talloc_free(file);
-                       continue;
-               }
-
+               status = fill_search_info(pvfs, level, 
+                                         pvfs_list_unix_path(dir), name, 
+                                         search, search->current_index, file);
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(file);
-                       search->current_index = i;
-                       return status;
+                       continue;
                }
 
                if (!callback(search_private, file)) {
                        talloc_free(file);
+                       search->current_index = ofs;
                        break;
                }
+
                (*reply_count)++;
                talloc_free(file);
-
-               /* note that this deliberately allows a reply_count of
-                  1 for a max_count of 0. w2k3 allows this too. */
-               if (*reply_count >= max_count) break;
        }
 
-       search->current_index = i;
+       pvfs_list_hibernate(dir);
 
        return NT_STATUS_OK;
 }
 
 /*
-  return the next available search handle
+  we've run out of search handles - cleanup those that the client forgot
+  to close
 */
-static NTSTATUS pvfs_next_search_handle(struct pvfs_state *pvfs, uint16_t *handle, 
-                                       uint_t max_handles)
+static void pvfs_search_cleanup(struct pvfs_state *pvfs)
 {
-       struct pvfs_search_state *search;
-
-       if (pvfs->search.num_active_searches >= max_handles) {
-               return NT_STATUS_INSUFFICIENT_RESOURCES;
-       }
-
-       (*handle) = (pvfs->search.next_search_handle) & (max_handles-1);
-again:
-       for (search=pvfs->search.open_searches;search;search=search->next) {
-               if (*handle == search->handle) {
-                       *handle = ((*handle)+1) & (max_handles-1);
-                       goto again;
-               } 
+       int i;
+       time_t t = time(NULL);
+
+       for (i=0;i<MAX_OLD_SEARCHES;i++) {
+               struct pvfs_search_state *search = idr_find(pvfs->idtree_search, i);
+               if (search == NULL) return;
+               if (pvfs_list_eos(search->dir, search->current_index) &&
+                   search->last_used != 0 &&
+                   t > search->last_used + 30) {
+                       /* its almost certainly been forgotten
+                        about */
+                       talloc_free(search);
+               }
        }
-       pvfs->search.next_search_handle = ((*handle)+1) & (max_handles-1);
-
-       return NT_STATUS_OK;
 }
 
 
 /* 
    list files in a directory matching a wildcard pattern - old SMBsearch interface
 */
-static NTSTATUS pvfs_search_first_old(struct smbsrv_request *req, union smb_search_first *io, 
+static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
+                                     struct smbsrv_request *req, union smb_search_first *io, 
                                      void *search_private, 
                                      BOOL (*callback)(void *, union smb_search_data *))
 {
        struct pvfs_dir *dir;
-       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
        uint_t reply_count;
        uint16_t search_attrib;
        const char *pattern;
        NTSTATUS status;
        struct pvfs_filename *name;
+       int id;
 
        search_attrib = io->search_first.in.search_attrib;
        pattern       = io->search_first.in.pattern;
 
        /* resolve the cifs name to a posix name */
-       status = pvfs_resolve_name(pvfs, req, pattern, 0, &name);
+       status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -284,27 +317,32 @@ static NTSTATUS pvfs_search_first_old(struct smbsrv_request *req, union smb_sear
                return NT_STATUS_NO_MEMORY;
        }
 
-       dir = talloc_p(search, struct pvfs_dir);
-       if (!dir) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        /* do the actual directory listing */
-       status = pvfs_list(pvfs, name, dir);
+       status = pvfs_list_start(pvfs, name, search, &dir);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        /* we need to give a handle back to the client so it
           can continue a search */
-       status = pvfs_next_search_handle(pvfs, &search->handle, 0x100);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       id = idr_get_new(pvfs->idtree_search, search, MAX_OLD_SEARCHES);
+       if (id == -1) {
+               pvfs_search_cleanup(pvfs);
+               id = idr_get_new(pvfs->idtree_search, search, MAX_OLD_SEARCHES);
        }
-       
+       if (id == -1) {
+               return NT_STATUS_INSUFFICIENT_RESOURCES;
+       }
+
+       search->pvfs = pvfs;
+       search->handle = id;
        search->dir = dir;
        search->current_index = 0;
-       search->search_attrib = search_attrib;
+       search->search_attrib = search_attrib & 0xFF;
+       search->must_attrib = (search_attrib>>8) & 0xFF;
+       search->last_used = time(NULL);
+
+       talloc_set_destructor(search, pvfs_search_destructor);
 
        status = pvfs_search_fill(pvfs, req, io->search_first.in.max_count, search, io->generic.level,
                                  &reply_count, search_private, callback);
@@ -319,41 +357,42 @@ static NTSTATUS pvfs_search_first_old(struct smbsrv_request *req, union smb_sear
                return STATUS_NO_MORE_FILES;
        }
 
-       pvfs->search.num_active_searches++;
        talloc_steal(pvfs, search);
-       DLIST_ADD(pvfs->search.open_searches, search);
 
        return NT_STATUS_OK;
 }
 
 /* continue a old style search */
-static NTSTATUS pvfs_search_next_old(struct smbsrv_request *req, union smb_search_next *io, 
+static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
+                                    struct smbsrv_request *req, union smb_search_next *io, 
                                     void *search_private, 
                                     BOOL (*callback)(void *, union smb_search_data *))
 {
-       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
        struct pvfs_dir *dir;
        uint_t reply_count, max_count;
        uint16_t handle;
        NTSTATUS status;
 
-       handle    = io->search_next.in.id.handle;
+       handle    = io->search_next.in.id.handle | (io->search_next.in.id.reserved<<8);
        max_count = io->search_next.in.max_count;
 
-       for (search=pvfs->search.open_searches; search; search = search->next) {
-               if (search->handle == handle) break;
-       }
-       
-       if (!search) {
+       search = idr_find(pvfs->idtree_search, handle);
+       if (search == NULL) {
                /* we didn't find the search handle */
                return NT_STATUS_INVALID_HANDLE;
        }
 
        search->current_index = io->search_next.in.id.server_cookie;
-
+       search->last_used = time(NULL);
        dir = search->dir;
 
+       status = pvfs_list_wakeup(dir, &search->current_index);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.level,
                                  &reply_count, search_private, callback);
        if (!NT_STATUS_IS_OK(status)) {
@@ -364,7 +403,6 @@ static NTSTATUS pvfs_search_next_old(struct smbsrv_request *req, union smb_searc
 
        /* not matching any entries means end of search */
        if (reply_count == 0) {
-               DLIST_REMOVE(pvfs->search.open_searches, search);
                talloc_free(search);
        }
 
@@ -374,21 +412,23 @@ static NTSTATUS pvfs_search_next_old(struct smbsrv_request *req, union smb_searc
 /* 
    list files in a directory matching a wildcard pattern
 */
-NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *io, 
+NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
+                          struct smbsrv_request *req, union smb_search_first *io, 
                           void *search_private, 
                           BOOL (*callback)(void *, union smb_search_data *))
 {
        struct pvfs_dir *dir;
-       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
        uint_t reply_count;
        uint16_t search_attrib, max_count;
        const char *pattern;
        NTSTATUS status;
        struct pvfs_filename *name;
+       int id;
 
        if (io->generic.level >= RAW_SEARCH_SEARCH) {
-               return pvfs_search_first_old(req, io, search_private, callback);
+               return pvfs_search_first_old(ntvfs, req, io, search_private, callback);
        }
 
        search_attrib = io->t2ffirst.in.search_attrib;
@@ -396,7 +436,7 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
        max_count     = io->t2ffirst.in.max_count;
 
        /* resolve the cifs name to a posix name */
-       status = pvfs_resolve_name(pvfs, req, pattern, 0, &name);
+       status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -413,27 +453,26 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
                return NT_STATUS_NO_MEMORY;
        }
 
-       dir = talloc_p(search, struct pvfs_dir);
-       if (!dir) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        /* do the actual directory listing */
-       status = pvfs_list(pvfs, name, dir);
+       status = pvfs_list_start(pvfs, name, search, &dir);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       /* we need to give a handle back to the client so it
-          can continue a search */
-       status = pvfs_next_search_handle(pvfs, &search->handle, 0x10000);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       id = idr_get_new(pvfs->idtree_search, search, UINT16_MAX);
+       if (id == -1) {
+               return NT_STATUS_INSUFFICIENT_RESOURCES;
        }
-       
+
+       search->pvfs = pvfs;
+       search->handle = id;
        search->dir = dir;
        search->current_index = 0;
        search->search_attrib = search_attrib;
+       search->must_attrib = 0;
+       search->last_used = 0;
+
+       talloc_set_destructor(search, pvfs_search_destructor);
 
        status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.level,
                                  &reply_count, search_private, callback);
@@ -448,7 +487,7 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
 
        io->t2ffirst.out.count = reply_count;
        io->t2ffirst.out.handle = search->handle;
-       io->t2ffirst.out.end_of_search = (search->current_index == dir->count) ? 1 : 0;
+       io->t2ffirst.out.end_of_search = pvfs_list_eos(dir, search->current_index) ? 1 : 0;
 
        /* work out if we are going to keep the search state
           and allow for a search continue */
@@ -457,38 +496,33 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
             io->t2ffirst.out.end_of_search)) {
                talloc_free(search);
        } else {
-               pvfs->search.num_active_searches++;
                talloc_steal(pvfs, search);
-               DLIST_ADD(pvfs->search.open_searches, search);
        }
 
        return NT_STATUS_OK;
 }
 
 /* continue a search */
-NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io, 
+NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
+                         struct smbsrv_request *req, union smb_search_next *io, 
                          void *search_private, 
                          BOOL (*callback)(void *, union smb_search_data *))
 {
-       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
        struct pvfs_dir *dir;
        uint_t reply_count;
        uint16_t handle;
        NTSTATUS status;
-       int i;
 
        if (io->generic.level >= RAW_SEARCH_SEARCH) {
-               return pvfs_search_next_old(req, io, search_private, callback);
+               return pvfs_search_next_old(ntvfs, req, io, search_private, callback);
        }
 
        handle = io->t2fnext.in.handle;
 
-       for (search=pvfs->search.open_searches; search; search = search->next) {
-               if (search->handle == handle) break;
-       }
-       
-       if (!search) {
+       search = idr_find(pvfs->idtree_search, handle);
+       if (search == NULL) {
                /* we didn't find the search handle */
                return NT_STATUS_INVALID_HANDLE;
        }
@@ -497,20 +531,9 @@ NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
 
        /* work out what type of continuation is being used */
        if (io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
-               /* look backwards first */
-               for (i=search->current_index; i > 0; i--) {
-                       if (strcmp(io->t2fnext.in.last_name, dir->names[i-1]) == 0) {
-                               search->current_index = i;
-                               goto found;
-                       }
-               }
-
-               /* then look forwards */
-               for (i=search->current_index+1; i <= dir->count; i++) {
-                       if (strcmp(io->t2fnext.in.last_name, dir->names[i-1]) == 0) {
-                               search->current_index = i;
-                               goto found;
-                       }
+               status = pvfs_list_seek(dir, io->t2fnext.in.last_name, &search->current_index);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
        } else if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) {
                /* plain continue - nothing to do */
@@ -518,26 +541,24 @@ NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
                search->current_index = io->t2fnext.in.resume_key;
        }
 
-found: 
-       status = pvfs_search_fill(pvfs, req, io->t2fnext.in.max_count, search, io->generic.level,
-                                 &reply_count, search_private, callback);
+       status = pvfs_list_wakeup(dir, &search->current_index);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       /* not matching any entries is an error */
-       if (reply_count == 0) {
-               return NT_STATUS_NO_MORE_ENTRIES;
+       status = pvfs_search_fill(pvfs, req, io->t2fnext.in.max_count, search, io->generic.level,
+                                 &reply_count, search_private, callback);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        io->t2fnext.out.count = reply_count;
-       io->t2fnext.out.end_of_search = (search->current_index == dir->count) ? 1 : 0;
+       io->t2fnext.out.end_of_search = pvfs_list_eos(dir, search->current_index) ? 1 : 0;
 
        /* work out if we are going to keep the search state */
        if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
            ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && 
             io->t2fnext.out.end_of_search)) {
-               DLIST_REMOVE(pvfs->search.open_searches, search);
                talloc_free(search);
        }
 
@@ -545,9 +566,10 @@ found:
 }
 
 /* close a search */
-NTSTATUS pvfs_search_close(struct smbsrv_request *req, union smb_search_close *io)
+NTSTATUS pvfs_search_close(struct ntvfs_module_context *ntvfs,
+                          struct smbsrv_request *req, union smb_search_close *io)
 {
-       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
        uint16_t handle;
 
@@ -557,16 +579,12 @@ NTSTATUS pvfs_search_close(struct smbsrv_request *req, union smb_search_close *i
                handle = io->findclose.in.handle;
        }
 
-       for (search=pvfs->search.open_searches; search; search = search->next) {
-               if (search->handle == handle) break;
-       }
-       
-       if (!search) {
+       search = idr_find(pvfs->idtree_search, handle);
+       if (search == NULL) {
                /* we didn't find the search handle */
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       DLIST_REMOVE(pvfs->search.open_searches, search);
        talloc_free(search);
 
        return NT_STATUS_OK;