r3276: - allow for more than 256 open old style searches (limit currently set at...
authorAndrew Tridgell <tridge@samba.org>
Wed, 27 Oct 2004 01:11:44 +0000 (01:11 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:04:48 +0000 (13:04 -0500)
- auto-cleanup old searches that the client forgot to close (common with old searches)

- expanded the RAW-SEARCH test to test more than 256 old searches, and
  old search rewind (w2k3 fails this - it appears to not support rewind
  on old style searches)

source/ntvfs/posix/pvfs_search.c
source/ntvfs/posix/vfs_posix.h
source/torture/raw/search.c

index 0df3ebee0f72ebd4ce8cf49f8fe5ce4e5b0f3172..43d0f946b7f6c4959301fb1f4742463ac1da916c 100644 (file)
 #include "vfs_posix.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
 */
@@ -68,11 +84,11 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                file->search.write_time       = nt_time_to_unix(name->dos.write_time);
                file->search.size             = name->st.st_size;
                file->search.name             = shortname;
-               file->search.id.reserved      = 8;
+               file->search.id.reserved      = search->handle >> 8;
                memset(file->search.id.name, ' ', sizeof(file->search.id.name));
                memcpy(file->search.id.name, shortname, 
                       MIN(strlen(shortname)+1, sizeof(file->search.id.name)));
-               file->search.id.handle        = search->handle;
+               file->search.id.handle        = search->handle & 0xFF;
                file->search.id.server_cookie = dir_index;
                file->search.id.client_cookie = 0;
                return NT_STATUS_OK;
@@ -237,6 +253,29 @@ static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+/*
+  we've run out of search handles - cleanup those that the client forgot
+  to close
+*/
+static void pvfs_search_cleanup(struct pvfs_state *pvfs)
+{
+       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);
+               }
+       }
+}
+
+
 /* 
    list files in a directory matching a wildcard pattern - old SMBsearch interface
 */
@@ -284,7 +323,11 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
 
        /* we need to give a handle back to the client so it
           can continue a search */
-       id = idr_get_new(pvfs->idtree_search, search, UINT8_MAX);
+       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;
        }
@@ -295,6 +338,7 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
        search->current_index = 0;
        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);
 
@@ -329,7 +373,7 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
        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;
 
        search = idr_find(pvfs->idtree_search, handle);
@@ -339,6 +383,7 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
        }
 
        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);
@@ -423,6 +468,7 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
        search->current_index = 0;
        search->search_attrib = search_attrib;
        search->must_attrib = 0;
+       search->last_used = 0;
 
        talloc_set_destructor(search, pvfs_search_destructor);
 
index 19408848fdcc693ce7192b4beffe0d6ec15c7372..231d9a2d0823fe8e9306b68fc04546c99f889af2 100644 (file)
@@ -75,16 +75,6 @@ struct pvfs_filename {
 };
 
 
-/* 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;
-};
-
 /* open file state */
 struct pvfs_file {
        struct pvfs_file *next, *prev;
@@ -161,4 +151,7 @@ struct pvfs_mangle_context {
 #define PVFS_FLAG_STRICT_SYNC    (1<<5)
 #define PVFS_FLAG_STRICT_LOCKING (1<<6)
 
+/* forward declare some anonymous structures */
+struct pvfs_dir;
+
 #endif /* _VFS_POSIX_H_ */
index c8f21de8d8fc0d62c74ccb032c1c655090ce8f37..04c1f8db57bad574531800a66e8717cf78f3cb94 100644 (file)
@@ -913,37 +913,189 @@ done:
 }
 
 
+
 /* 
-   basic testing of all RAW_SEARCH_* calls using a single file
+   basic testing of many old style search calls using separate dirs
 */
-BOOL torture_raw_search(int dummy)
+static BOOL test_many_dirs(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 {
-       struct smbcli_state *cli;
+       const int num_dirs = 300;
+       int i, fnum, n;
+       char *fname, *dname;
        BOOL ret = True;
-       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+       union smb_search_data *file, *file2, *file3;
 
-       if (!torture_open_connection(&cli)) {
+       if (smbcli_deltree(cli->tree, BASEDIR) == -1 || 
+           NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
+               printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
                return False;
        }
 
-       mem_ctx = talloc_init("torture_search");
+       printf("Creating %d dirs\n", num_dirs);
 
-       if (!test_one_file(cli, mem_ctx)) {
-               ret = False;
+       for (i=0;i<num_dirs;i++) {
+               asprintf(&dname, BASEDIR "\\d%d", i);
+               status = smbcli_mkdir(cli->tree, dname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("(%s) Failed to create %s - %s\n", 
+                              __location__, dname, nt_errstr(status));
+                       ret = False;
+                       goto done;
+               }
+
+               for (n=0;n<3;n++) {
+                       asprintf(&fname, BASEDIR "\\d%d\\f%d-%d.txt", i, i, n);
+                       fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+                       if (fnum == -1) {
+                               printf("(%s) Failed to create %s - %s\n", 
+                                      __location__, fname, smbcli_errstr(cli->tree));
+                               ret = False;
+                               goto done;
+                       }
+                       free(fname);
+               }
+
+               free(dname);
+               smbcli_close(cli->tree, fnum);
        }
 
-       if (!test_many_files(cli, mem_ctx)) {
-               ret = False;
+       file  = talloc_zero_array_p(mem_ctx, union smb_search_data, num_dirs);
+       file2 = talloc_zero_array_p(mem_ctx, union smb_search_data, num_dirs);
+       file3 = talloc_zero_array_p(mem_ctx, union smb_search_data, num_dirs);
+
+       printf("Search first on %d dirs\n", num_dirs);
+
+       for (i=0;i<num_dirs;i++) {
+               union smb_search_first io;
+               io.generic.level = RAW_SEARCH_SEARCH;
+               io.search_first.in.max_count = 1;
+               io.search_first.in.search_attrib = 0;
+               io.search_first.in.pattern = talloc_asprintf(mem_ctx, BASEDIR "\\d%d\\*.txt", i);
+               fname = talloc_asprintf(mem_ctx, "f%d-", i);
+
+               io.search_first.out.count = 0;
+
+               status = smb_raw_search_first(cli->tree, mem_ctx,
+                                             &io, (void *)&file[i], single_search_callback);
+               if (io.search_first.out.count != 1) {
+                       printf("(%s) search first gave %d entries for dir %d - %s\n",
+                              __location__, io.search_first.out.count, i, nt_errstr(status));
+                       ret = False;
+                       goto done;
+               }
+               CHECK_STATUS(status, NT_STATUS_OK);
+               if (strncasecmp(file[i].search.name, fname, strlen(fname)) != 0) {
+                       printf("(%s) incorrect name '%s' expected '%s'[12].txt\n", 
+                              __location__, file[i].search.name, fname);
+                       ret = False;
+                       goto done;
+               }
+
+               talloc_free(fname);
        }
 
-       if (!test_sorted(cli, mem_ctx)) {
-               ret = False;
+       printf("Search next on %d dirs\n", num_dirs);
+
+       for (i=0;i<num_dirs;i++) {
+               union smb_search_next io2;
+
+               io2.generic.level = RAW_SEARCH_SEARCH;
+               io2.search_next.in.max_count = 1;
+               io2.search_next.in.search_attrib = 0;
+               io2.search_next.in.id = file[i].search.id;
+               fname = talloc_asprintf(mem_ctx, "f%d-", i);
+
+               io2.search_next.out.count = 0;
+
+               status = smb_raw_search_next(cli->tree, mem_ctx,
+                                            &io2, (void *)&file2[i], single_search_callback);
+               if (io2.search_next.out.count != 1) {
+                       printf("(%s) search next gave %d entries for dir %d - %s\n",
+                              __location__, io2.search_next.out.count, i, nt_errstr(status));
+                       ret = False;
+                       goto done;
+               }
+               CHECK_STATUS(status, NT_STATUS_OK);
+               if (strncasecmp(file2[i].search.name, fname, strlen(fname)) != 0) {
+                       printf("(%s) incorrect name '%s' expected '%s'[12].txt\n", 
+                              __location__, file2[i].search.name, fname);
+                       ret = False;
+                       goto done;
+               }
+
+               talloc_free(fname);
        }
 
-       if (!test_modify_search(cli, mem_ctx)) {
-               ret = False;
+
+       printf("Search next (rewind) on %d dirs\n", num_dirs);
+
+       for (i=0;i<num_dirs;i++) {
+               union smb_search_next io2;
+
+               io2.generic.level = RAW_SEARCH_SEARCH;
+               io2.search_next.in.max_count = 1;
+               io2.search_next.in.search_attrib = 0;
+               io2.search_next.in.id = file[i].search.id;
+               fname = talloc_asprintf(mem_ctx, "f%d-", i);
+               io2.search_next.out.count = 0;
+
+               status = smb_raw_search_next(cli->tree, mem_ctx,
+                                            &io2, (void *)&file3[i], single_search_callback);
+               if (io2.search_next.out.count != 1) {
+                       printf("(%s) search next gave %d entries for dir %d - %s\n",
+                              __location__, io2.search_next.out.count, i, nt_errstr(status));
+                       ret = False;
+                       goto done;
+               }
+               CHECK_STATUS(status, NT_STATUS_OK);
+
+               if (strncasecmp(file3[i].search.name, file2[i].search.name, 3) != 0) {
+                       printf("(%s) incorrect name '%s' on rewind at dir %d\n", 
+                              __location__, file2[i].search.name, i);
+                       ret = False;
+                       goto done;
+               }
+
+               if (strcmp(file3[i].search.name, file2[i].search.name) != 0) {
+                       printf("(%s) server did not rewind - got '%s' expected '%s'\n", 
+                              __location__, file3[i].search.name, file2[i].search.name);
+                       ret = False;
+                       goto done;
+               }
+
+               talloc_free(fname);
+       }
+
+
+done:
+       smb_raw_exit(cli->session);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+/* 
+   basic testing of all RAW_SEARCH_* calls using a single file
+*/
+BOOL torture_raw_search(int dummy)
+{
+       struct smbcli_state *cli;
+       BOOL ret = True;
+       TALLOC_CTX *mem_ctx;
+
+       if (!torture_open_connection(&cli)) {
+               return False;
        }
 
+       mem_ctx = talloc_init("torture_search");
+
+       ret &= test_one_file(cli, mem_ctx);
+       ret &= test_many_files(cli, mem_ctx);
+       ret &= test_sorted(cli, mem_ctx);
+       ret &= test_modify_search(cli, mem_ctx);
+       ret &= test_many_dirs(cli, mem_ctx);
+
        torture_close_connection(cli);
        talloc_destroy(mem_ctx);