summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/posix/pvfs_dirlist.c63
-rw-r--r--source4/ntvfs/posix/pvfs_search.c10
2 files changed, 50 insertions, 23 deletions
diff --git a/source4/ntvfs/posix/pvfs_dirlist.c b/source4/ntvfs/posix/pvfs_dirlist.c
index 1ef6e408c3..5c67b2d189 100644
--- a/source4/ntvfs/posix/pvfs_dirlist.c
+++ b/source4/ntvfs/posix/pvfs_dirlist.c
@@ -25,15 +25,24 @@
#include "vfs_posix.h"
#include "system/dir.h"
+#define NAME_CACHE_SIZE 100
+
+struct name_cache_entry {
+ char *name;
+ off_t offset;
+};
+
struct pvfs_dir {
struct pvfs_state *pvfs;
BOOL no_wildcard;
- char *last_name;
+ char *single_name;
const char *pattern;
off_t offset;
DIR *dir;
const char *unix_path;
BOOL end_of_search;
+ struct name_cache_entry *name_cache;
+ uint32_t name_cache_index;
};
/*
@@ -55,8 +64,8 @@ static NTSTATUS pvfs_list_no_wildcard(struct pvfs_state *pvfs, struct pvfs_filen
return NT_STATUS_NO_MEMORY;
}
- dir->last_name = talloc_strdup(dir, pattern);
- if (!dir->last_name) {
+ dir->single_name = talloc_strdup(dir, pattern);
+ if (!dir->single_name) {
return NT_STATUS_NO_MEMORY;
}
@@ -88,7 +97,7 @@ NTSTATUS pvfs_list_start(struct pvfs_state *pvfs, struct pvfs_filename *name,
char *pattern;
struct pvfs_dir *dir;
- (*dirp) = talloc_p(mem_ctx, struct pvfs_dir);
+ (*dirp) = talloc_zero_p(mem_ctx, struct pvfs_dir);
if (*dirp == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -126,9 +135,15 @@ NTSTATUS pvfs_list_start(struct pvfs_state *pvfs, struct pvfs_filename *name,
dir->pvfs = pvfs;
dir->no_wildcard = False;
- dir->last_name = NULL;
dir->end_of_search = False;
dir->offset = 0;
+ dir->name_cache = talloc_zero_array_p(dir,
+ struct name_cache_entry,
+ NAME_CACHE_SIZE);
+ if (dir->name_cache == NULL) {
+ talloc_free(dir);
+ return NT_STATUS_NO_MEMORY;
+ }
talloc_set_destructor(dir, pvfs_dirlist_destructor);
@@ -147,7 +162,7 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
dir->end_of_search = True;
if (*ofs != 0) return NULL;
(*ofs)++;
- return dir->last_name;
+ return dir->single_name;
}
if (*ofs != dir->offset) {
@@ -157,6 +172,7 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
while ((de = readdir(dir->dir))) {
const char *dname = de->d_name;
+ struct name_cache_entry *e;
if (ms_fnmatch(dir->pattern, dname,
dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) {
@@ -173,10 +189,15 @@ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
dir->offset = telldir(dir->dir);
(*ofs) = dir->offset;
- if (dir->last_name) talloc_free(dir->last_name);
- dir->last_name = talloc_strdup(dir, de->d_name);
+ dir->name_cache_index = (dir->name_cache_index+1) % NAME_CACHE_SIZE;
+ e = &dir->name_cache[dir->name_cache_index];
+
+ if (e->name) talloc_free(e->name);
+
+ e->name = talloc_strdup(dir, de->d_name);
+ e->offset = dir->offset;
- return dir->last_name;
+ return e->name;
}
dir->end_of_search = True;
@@ -248,16 +269,26 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
{
struct dirent *de;
NTSTATUS status;
+ int i;
status = pvfs_list_wakeup(dir, ofs);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- if (dir->last_name &&
- StrCaseCmp(name, dir->last_name) == 0) {
- *ofs = dir->offset;
- return NT_STATUS_OK;
+ for (i=dir->name_cache_index;i>=0;i--) {
+ struct name_cache_entry *e = &dir->name_cache[i];
+ if (e->name && StrCaseCmp(name, e->name) == 0) {
+ *ofs = e->offset;
+ return NT_STATUS_OK;
+ }
+ }
+ for (i=NAME_CACHE_SIZE-1;i>dir->name_cache_index;i--) {
+ struct name_cache_entry *e = &dir->name_cache[i];
+ if (e->name && StrCaseCmp(name, e->name) == 0) {
+ *ofs = e->offset;
+ return NT_STATUS_OK;
+ }
}
rewinddir(dir->dir);
@@ -266,8 +297,6 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
if (StrCaseCmp(name, de->d_name) == 0) {
dir->offset = telldir(dir->dir);
*ofs = dir->offset;
- if (dir->last_name) talloc_free(dir->last_name);
- dir->last_name = talloc_strdup(dir, de->d_name);
return NT_STATUS_OK;
}
}
@@ -276,7 +305,5 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
pvfs_list_hibernate(dir);
- /* it is not an error to give a bad name (it may have been deleted). Instead
- just continue from end of directory */
- return NT_STATUS_OK;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index 1c49701f04..c336035218 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -533,7 +533,11 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
if (io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
status = pvfs_list_seek(dir, io->t2fnext.in.last_name, &search->current_index);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (io->t2fnext.in.resume_key) {
+ search->current_index = io->t2fnext.in.resume_key;
+ } else {
+ return status;
+ }
}
} else if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) {
/* plain continue - nothing to do */
@@ -562,10 +566,6 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
talloc_free(search);
}
- if (reply_count == 0) {
- return NT_STATUS_NO_SUCH_FILE;
- }
-
return NT_STATUS_OK;
}