summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/posix/pvfs_open.c3
-rw-r--r--source4/ntvfs/posix/pvfs_search.c160
-rw-r--r--source4/ntvfs/posix/vfs_posix.h3
3 files changed, 166 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 74f9b44c5c..5482bb3562 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -266,6 +266,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
f->access_mask = access_mask;
f->brl_handle = NULL;
f->notify_buffer = NULL;
+ f->search = NULL;
f->handle->pvfs = pvfs;
f->handle->name = talloc_steal(f->handle, name);
@@ -698,6 +699,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
f->access_mask = access_mask;
f->impersonation = io->generic.in.impersonation;
f->notify_buffer = NULL;
+ f->search = NULL;
f->handle->pvfs = pvfs;
f->handle->name = talloc_steal(f->handle, name);
@@ -1126,6 +1128,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
f->access_mask = access_mask;
f->impersonation = io->generic.in.impersonation;
f->notify_buffer = NULL;
+ f->search = NULL;
f->handle->pvfs = pvfs;
f->handle->fd = -1;
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index 794d223060..58cc1e04f3 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -58,6 +58,7 @@ static void pvfs_search_timer(struct event_context *ev, struct timed_event *te,
static void pvfs_search_setup_timer(struct pvfs_search_state *search)
{
struct event_context *ev = search->pvfs->ntvfs->ctx->event_ctx;
+ if (search->handle == -1) return;
talloc_free(search->te);
search->te = event_add_timed(ev, search,
timeval_current_ofs(search->pvfs->search.inactivity_time, 0),
@@ -595,6 +596,159 @@ static NTSTATUS pvfs_search_next_trans2(struct ntvfs_module_context *ntvfs,
return NT_STATUS_OK;
}
+static NTSTATUS pvfs_search_first_smb2(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, const struct smb2_find *io,
+ void *search_private,
+ BOOL (*callback)(void *, union smb_search_data *))
+{
+ struct pvfs_dir *dir;
+ struct pvfs_state *pvfs = ntvfs->private_data;
+ struct pvfs_search_state *search;
+ uint_t reply_count;
+ uint16_t max_count;
+ const char *pattern;
+ NTSTATUS status;
+ struct pvfs_filename *name;
+ struct pvfs_file *f;
+
+ f = pvfs_find_fd(pvfs, req, io->in.file.ntvfs);
+ if (!f) {
+ return NT_STATUS_FILE_CLOSED;
+ }
+
+ /* its only valid for directories */
+ if (f->handle->fd != -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!(f->access_mask & SEC_DIR_LIST)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (f->search) {
+ talloc_free(f->search);
+ f->search = NULL;
+ }
+
+ if (strequal(io->in.pattern, "")) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ if (strchr_m(io->in.pattern, '\\')) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ if (strchr_m(io->in.pattern, '/')) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (strequal("", f->handle->name->original_name)) {
+ pattern = talloc_asprintf(req, "\\%s", io->in.pattern);
+ NT_STATUS_HAVE_NO_MEMORY(pattern);
+ } else {
+ pattern = talloc_asprintf(req, "\\%s\\%s",
+ f->handle->name->original_name,
+ io->in.pattern);
+ NT_STATUS_HAVE_NO_MEMORY(pattern);
+ }
+
+ /* resolve the cifs name to a posix name */
+ status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (!name->has_wildcard && !name->exists) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ /* we initially make search a child of the request, then if we
+ need to keep it long term we steal it for the private
+ structure */
+ search = talloc(req, struct pvfs_search_state);
+ NT_STATUS_HAVE_NO_MEMORY(search);
+
+ /* do the actual directory listing */
+ status = pvfs_list_start(pvfs, name, search, &dir);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ search->pvfs = pvfs;
+ search->handle = -1;
+ search->dir = dir;
+ search->current_index = 0;
+ search->search_attrib = 0;
+ search->must_attrib = 0;
+ search->last_used = 0;
+ search->num_ea_names = 0;
+ search->ea_names = NULL;
+ search->te = NULL;
+
+ if (io->in.continue_flags & SMB2_CONTINUE_FLAG_SINGLE) {
+ max_count = 1;
+ } else {
+ max_count = UINT16_MAX;
+ }
+
+ status = pvfs_search_fill(pvfs, req, max_count, search, io->data_level,
+ &reply_count, search_private, callback);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* not matching any entries is an error */
+ if (reply_count == 0) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ f->search = talloc_steal(f, search);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pvfs_search_next_smb2(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, const struct smb2_find *io,
+ void *search_private,
+ BOOL (*callback)(void *, union smb_search_data *))
+{
+ struct pvfs_state *pvfs = ntvfs->private_data;
+ struct pvfs_search_state *search;
+ uint_t reply_count;
+ uint16_t max_count;
+ NTSTATUS status;
+ struct pvfs_file *f;
+
+ f = pvfs_find_fd(pvfs, req, io->in.file.ntvfs);
+ if (!f) {
+ return NT_STATUS_FILE_CLOSED;
+ }
+
+ /* its only valid for directories */
+ if (f->handle->fd != -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* if there's no search started on the dir handle, it's like a search_first */
+ search = f->search;
+ if (!search) {
+ return pvfs_search_first_smb2(ntvfs, req, io, search_private, callback);
+ }
+
+ if (io->in.continue_flags & SMB2_CONTINUE_FLAG_RESTART) {
+ search->current_index = 0;
+ }
+
+ if (io->in.continue_flags & SMB2_CONTINUE_FLAG_SINGLE) {
+ max_count = 1;
+ } else {
+ max_count = UINT16_MAX;
+ }
+
+ status = pvfs_search_fill(pvfs, req, max_count, search, io->data_level,
+ &reply_count, search_private, callback);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* not matching any entries is an error */
+ if (reply_count == 0) {
+ return STATUS_NO_MORE_FILES;
+ }
+
+ return NT_STATUS_OK;
+}
+
/*
list files in a directory matching a wildcard pattern
*/
@@ -611,6 +765,9 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
case RAW_SEARCH_TRANS2:
return pvfs_search_first_trans2(ntvfs, req, io, search_private, callback);
+
+ case RAW_SEARCH_SMB2:
+ return pvfs_search_first_smb2(ntvfs, req, &io->smb2, search_private, callback);
}
return NT_STATUS_INVALID_LEVEL;
@@ -632,6 +789,9 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
case RAW_SEARCH_TRANS2:
return pvfs_search_next_trans2(ntvfs, req, io, search_private, callback);
+
+ case RAW_SEARCH_SMB2:
+ return pvfs_search_next_smb2(ntvfs, req, &io->smb2, search_private, callback);
}
return NT_STATUS_INVALID_LEVEL;
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 63ee3395f8..eb738920f4 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -181,6 +181,9 @@ struct pvfs_file {
/* for directories, a buffer of pending notify events */
struct pvfs_notify_buffer *notify_buffer;
+
+ /* for directories, the state of an incomplete SMB2 Find */
+ struct pvfs_search_state *search;
};
/* the state of a search started with pvfs_search_first() */