summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/posix/pvfs_search.c54
-rw-r--r--source4/ntvfs/posix/vfs_posix.h13
-rw-r--r--source4/torture/raw/search.c180
3 files changed, 219 insertions, 28 deletions
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index 0df3ebee0f..43d0f946b7 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -24,6 +24,22 @@
#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);
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 19408848fd..231d9a2d08 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -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_ */
diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index c8f21de8d8..04c1f8db57 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -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);