diff options
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 3 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 160 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 3 |
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() */ |