Fix include paths to new location of libutil.
[bbaumbach/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_search.c
index 794d2230608f8b2137f43c0159ac39ebe06689fb..b84684573189be632b946af9abfb483e59e846dd 100644 (file)
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "librpc/gen_ndr/security.h"
 #include "smbd/service_stream.h"
 #include "lib/events/events.h"
-#include "dlinklist.h"
+#include "../lib/util/dlinklist.h"
 
 /* place a reasonable limit on old-style searches as clients tend to
    not send search close requests */
 #define MAX_OLD_SEARCHES 2000
+#define MAX_SEARCH_HANDLES (UINT16_MAX - 1)
+#define INVALID_SEARCH_HANDLE UINT16_MAX
 
 /*
   destroy an open search
@@ -58,6 +59,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 == INVALID_SEARCH_HANDLE) return;
        talloc_free(search->te);
        search->te = event_add_timed(ev, search, 
                                     timeval_current_ofs(search->pvfs->search.inactivity_time, 0), 
@@ -72,14 +74,17 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                                 const char *unix_path,
                                 const char *fname, 
                                 struct pvfs_search_state *search,
-                                uint32_t dir_index,
+                                off_t dir_offset,
                                 union smb_search_data *file)
 {
        struct pvfs_filename *name;
        NTSTATUS status;
        const char *shortname;
+       uint32_t dir_index = (uint32_t)dir_offset; /* truncated - see the code 
+                                                     in pvfs_list_seek_ofs() for 
+                                                     how we cope with this */
 
-       status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name);
+       status = pvfs_resolve_partial(pvfs, file, unix_path, fname, 0, &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -232,7 +237,7 @@ static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
                                 enum smb_search_data_level level,
                                 uint_t *reply_count,
                                 void *search_private, 
-                                BOOL (*callback)(void *, union smb_search_data *))
+                                bool (*callback)(void *, const union smb_search_data *))
 {
        struct pvfs_dir *dir = search->dir;
        NTSTATUS status;
@@ -246,7 +251,7 @@ static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
        while ((*reply_count) < max_count) {
                union smb_search_data *file;
                const char *name;
-               uint_t ofs = search->current_index;
+               off_t ofs = search->current_index;
 
                name = pvfs_list_next(dir, &search->current_index);
                if (name == NULL) break;
@@ -308,7 +313,7 @@ static void pvfs_search_cleanup(struct pvfs_state *pvfs)
 static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
                                      struct ntvfs_request *req, union smb_search_first *io, 
                                      void *search_private, 
-                                     BOOL (*callback)(void *, union smb_search_data *))
+                                     bool (*callback)(void *, const union smb_search_data *))
 {
        struct pvfs_dir *dir;
        struct pvfs_state *pvfs = ntvfs->private_data;
@@ -398,7 +403,7 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
 static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
                                     struct ntvfs_request *req, union smb_search_next *io, 
                                     void *search_private, 
-                                    BOOL (*callback)(void *, union smb_search_data *))
+                                    bool (*callback)(void *, const union smb_search_data *))
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
@@ -416,10 +421,15 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       search->current_index = io->search_next.in.id.server_cookie;
-       search->last_used = time(NULL);
        dir = search->dir;
 
+       status = pvfs_list_seek_ofs(dir, io->search_next.in.id.server_cookie, 
+                                   &search->current_index);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       search->last_used = time(NULL);
+
        status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.data_level,
                                  &reply_count, search_private, callback);
        if (!NT_STATUS_IS_OK(status)) {
@@ -442,7 +452,7 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
 static NTSTATUS pvfs_search_first_trans2(struct ntvfs_module_context *ntvfs,
                                         struct ntvfs_request *req, union smb_search_first *io, 
                                         void *search_private, 
-                                        BOOL (*callback)(void *, union smb_search_data *))
+                                        bool (*callback)(void *, const union smb_search_data *))
 {
        struct pvfs_dir *dir;
        struct pvfs_state *pvfs = ntvfs->private_data;
@@ -487,7 +497,7 @@ static NTSTATUS pvfs_search_first_trans2(struct ntvfs_module_context *ntvfs,
                return status;
        }
 
-       id = idr_get_new(pvfs->search.idtree, search, UINT16_MAX);
+       id = idr_get_new(pvfs->search.idtree, search, MAX_SEARCH_HANDLES);
        if (id == -1) {
                return NT_STATUS_INSUFFICIENT_RESOURCES;
        }
@@ -538,7 +548,7 @@ static NTSTATUS pvfs_search_first_trans2(struct ntvfs_module_context *ntvfs,
 static NTSTATUS pvfs_search_next_trans2(struct ntvfs_module_context *ntvfs,
                                        struct ntvfs_request *req, union smb_search_next *io, 
                                        void *search_private, 
-                                       BOOL (*callback)(void *, union smb_search_data *))
+                                       bool (*callback)(void *, const union smb_search_data *))
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
@@ -554,23 +564,24 @@ static NTSTATUS pvfs_search_next_trans2(struct ntvfs_module_context *ntvfs,
                /* we didn't find the search handle */
                return NT_STATUS_INVALID_HANDLE;
        }
-
+       
        dir = search->dir;
+       
+       status = NT_STATUS_OK;
 
        /* work out what type of continuation is being used */
        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)) {
-                       if (io->t2fnext.in.resume_key) {
-                               search->current_index = io->t2fnext.in.resume_key;
-                       } else {
-                               return status;
-                       }
+               if (!NT_STATUS_IS_OK(status) && io->t2fnext.in.resume_key) {
+                       status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
+                                                   &search->current_index);
                }
-       } else if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) {
-               /* plain continue - nothing to do */
-       } else {
-               search->current_index = io->t2fnext.in.resume_key;
+       } else if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE)) {
+               status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
+                                           &search->current_index);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        search->num_ea_names = io->t2fnext.in.num_names;
@@ -595,13 +606,166 @@ 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 *, const 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          = INVALID_SEARCH_HANDLE;
+       search->dir             = dir;
+       search->current_index   = 0;
+       search->search_attrib   = 0x0000FFFF;
+       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 *, const 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
 */
 NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
                           struct ntvfs_request *req, union smb_search_first *io, 
                           void *search_private, 
-                          BOOL (*callback)(void *, union smb_search_data *))
+                          bool (*callback)(void *, const union smb_search_data *))
 {
        switch (io->generic.level) {
        case RAW_SEARCH_SEARCH:
@@ -611,6 +775,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;
@@ -620,7 +787,7 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
                          struct ntvfs_request *req, union smb_search_next *io, 
                          void *search_private, 
-                         BOOL (*callback)(void *, union smb_search_data *))
+                         bool (*callback)(void *, const union smb_search_data *))
 {
        switch (io->generic.level) {
        case RAW_SEARCH_SEARCH:
@@ -632,6 +799,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;
@@ -644,7 +814,7 @@ NTSTATUS pvfs_search_close(struct ntvfs_module_context *ntvfs,
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_search_state *search;
-       uint16_t handle = 0;
+       uint16_t handle = INVALID_SEARCH_HANDLE;
 
        switch (io->generic.level) {
        case RAW_FINDCLOSE_GENERIC: