LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_search.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 357 471 75.8 %
Date: 2024-04-21 15:09:00 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - directory search functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "vfs_posix.h"
      24             : #include "system/time.h"
      25             : #include "librpc/gen_ndr/security.h"
      26             : #include "samba/service_stream.h"
      27             : #include "lib/events/events.h"
      28             : #include "../lib/util/dlinklist.h"
      29             : #include "lib/util/idtree.h"
      30             : 
      31             : /* place a reasonable limit on old-style searches as clients tend to
      32             :    not send search close requests */
      33             : #define MAX_OLD_SEARCHES 2000
      34             : #define MAX_SEARCH_HANDLES (UINT16_MAX - 1)
      35             : #define INVALID_SEARCH_HANDLE UINT16_MAX
      36             : 
      37             : /*
      38             :   destroy an open search
      39             : */
      40        7079 : static int pvfs_search_destructor(struct pvfs_search_state *search)
      41             : {
      42        7079 :         DLIST_REMOVE(search->pvfs->search.list, search);
      43        7079 :         idr_remove(search->pvfs->search.idtree, search->handle);
      44        7079 :         return 0;
      45             : }
      46             : 
      47             : /*
      48             :   called when a search timer goes off
      49             : */
      50           0 : static void pvfs_search_timer(struct tevent_context *ev, struct tevent_timer *te, 
      51             :                                       struct timeval t, void *ptr)
      52             : {
      53           0 :         struct pvfs_search_state *search = talloc_get_type(ptr, struct pvfs_search_state);
      54           0 :         talloc_free(search);
      55           0 : }
      56             : 
      57             : /*
      58             :   setup a timer to destroy a open search after a inactivity period
      59             : */
      60        8391 : static void pvfs_search_setup_timer(struct pvfs_search_state *search)
      61             : {
      62        8391 :         struct tevent_context *ev = search->pvfs->ntvfs->ctx->event_ctx;
      63        8391 :         if (search->handle == INVALID_SEARCH_HANDLE) return;
      64        7485 :         talloc_free(search->te);
      65        7485 :         search->te = tevent_add_timer(ev, search,
      66             :                                      timeval_current_ofs(search->pvfs->search.inactivity_time, 0), 
      67             :                                      pvfs_search_timer, search);
      68             : }
      69             : 
      70             : /*
      71             :   fill in a single search result for a given info level
      72             : */
      73      129299 : static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
      74             :                                  enum smb_search_data_level level,
      75             :                                  const char *unix_path,
      76             :                                  const char *fname, 
      77             :                                  struct pvfs_search_state *search,
      78             :                                  off_t dir_offset,
      79             :                                  union smb_search_data *file)
      80             : {
      81           0 :         struct pvfs_filename *name;
      82           0 :         NTSTATUS status;
      83           0 :         const char *shortname;
      84      129299 :         uint32_t dir_index = (uint32_t)dir_offset; /* truncated - see the code 
      85             :                                                       in pvfs_list_seek_ofs() for 
      86             :                                                       how we cope with this */
      87             : 
      88      129299 :         status = pvfs_resolve_partial(pvfs, file, unix_path, fname, 0, &name);
      89      129299 :         if (!NT_STATUS_IS_OK(status)) {
      90           0 :                 return status;
      91             :         }
      92             : 
      93      129299 :         status = pvfs_match_attrib(pvfs, name, search->search_attrib, search->must_attrib);
      94      129299 :         if (!NT_STATUS_IS_OK(status)) {
      95        6499 :                 return status;
      96             :         }
      97             : 
      98      122800 :         switch (level) {
      99        8771 :         case RAW_SEARCH_DATA_SEARCH:
     100        8771 :                 shortname = pvfs_short_name(pvfs, name, name);
     101        8771 :                 file->search.attrib           = name->dos.attrib;
     102        8771 :                 file->search.write_time       = nt_time_to_unix(name->dos.write_time);
     103        8771 :                 file->search.size             = name->st.st_size;
     104        8771 :                 file->search.name             = shortname;
     105        8771 :                 file->search.id.reserved      = search->handle >> 8;
     106        8771 :                 memset(file->search.id.name, ' ', sizeof(file->search.id.name));
     107         703 :                 memcpy(file->search.id.name, shortname, 
     108        8771 :                        MIN(strlen(shortname)+1, sizeof(file->search.id.name)));
     109        8771 :                 file->search.id.handle        = search->handle & 0xFF;
     110        8771 :                 file->search.id.server_cookie = dir_index;
     111        8771 :                 file->search.id.client_cookie = 0;
     112        8771 :                 return NT_STATUS_OK;
     113             : 
     114        2103 :         case RAW_SEARCH_DATA_STANDARD:
     115        2103 :                 file->standard.resume_key   = dir_index;
     116        2103 :                 file->standard.create_time  = nt_time_to_unix(name->dos.create_time);
     117        2103 :                 file->standard.access_time  = nt_time_to_unix(name->dos.access_time);
     118        2103 :                 file->standard.write_time   = nt_time_to_unix(name->dos.write_time);
     119        2103 :                 file->standard.size         = name->st.st_size;
     120        2103 :                 file->standard.alloc_size   = name->dos.alloc_size;
     121        2103 :                 file->standard.attrib       = name->dos.attrib;
     122        2103 :                 file->standard.name.s       = fname;
     123        2103 :                 return NT_STATUS_OK;
     124             : 
     125       18403 :         case RAW_SEARCH_DATA_EA_SIZE:
     126       18403 :                 file->ea_size.resume_key   = dir_index;
     127       18403 :                 file->ea_size.create_time  = nt_time_to_unix(name->dos.create_time);
     128       18403 :                 file->ea_size.access_time  = nt_time_to_unix(name->dos.access_time);
     129       18403 :                 file->ea_size.write_time   = nt_time_to_unix(name->dos.write_time);
     130       18403 :                 file->ea_size.size         = name->st.st_size;
     131       18403 :                 file->ea_size.alloc_size   = name->dos.alloc_size;
     132       18403 :                 file->ea_size.attrib       = name->dos.attrib;
     133       18403 :                 file->ea_size.ea_size      = name->dos.ea_size;
     134       18403 :                 file->ea_size.name.s       = fname;
     135       18403 :                 return NT_STATUS_OK;
     136             : 
     137           3 :         case RAW_SEARCH_DATA_EA_LIST:
     138           3 :                 file->ea_list.resume_key   = dir_index;
     139           3 :                 file->ea_list.create_time  = nt_time_to_unix(name->dos.create_time);
     140           3 :                 file->ea_list.access_time  = nt_time_to_unix(name->dos.access_time);
     141           3 :                 file->ea_list.write_time   = nt_time_to_unix(name->dos.write_time);
     142           3 :                 file->ea_list.size         = name->st.st_size;
     143           3 :                 file->ea_list.alloc_size   = name->dos.alloc_size;
     144           3 :                 file->ea_list.attrib       = name->dos.attrib;
     145           3 :                 file->ea_list.name.s       = fname;
     146           3 :                 return pvfs_query_ea_list(pvfs, file, name, -1, 
     147             :                                           search->num_ea_names,
     148             :                                           search->ea_names,
     149             :                                           &file->ea_list.eas);
     150             : 
     151        2124 :         case RAW_SEARCH_DATA_DIRECTORY_INFO:
     152        2124 :                 file->directory_info.file_index   = dir_index;
     153        2124 :                 file->directory_info.create_time  = name->dos.create_time;
     154        2124 :                 file->directory_info.access_time  = name->dos.access_time;
     155        2124 :                 file->directory_info.write_time   = name->dos.write_time;
     156        2124 :                 file->directory_info.change_time  = name->dos.change_time;
     157        2124 :                 file->directory_info.size         = name->st.st_size;
     158        2124 :                 file->directory_info.alloc_size   = name->dos.alloc_size;
     159        2124 :                 file->directory_info.attrib       = name->dos.attrib;
     160        2124 :                 file->directory_info.name.s       = fname;
     161        2124 :                 return NT_STATUS_OK;
     162             : 
     163        2277 :         case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
     164        2277 :                 file->full_directory_info.file_index   = dir_index;
     165        2277 :                 file->full_directory_info.create_time  = name->dos.create_time;
     166        2277 :                 file->full_directory_info.access_time  = name->dos.access_time;
     167        2277 :                 file->full_directory_info.write_time   = name->dos.write_time;
     168        2277 :                 file->full_directory_info.change_time  = name->dos.change_time;
     169        2277 :                 file->full_directory_info.size         = name->st.st_size;
     170        2277 :                 file->full_directory_info.alloc_size   = name->dos.alloc_size;
     171        2277 :                 file->full_directory_info.attrib       = name->dos.attrib;
     172        2277 :                 file->full_directory_info.ea_size      = name->dos.ea_size;
     173        2277 :                 file->full_directory_info.name.s       = fname;
     174        2277 :                 return NT_STATUS_OK;
     175             : 
     176       65956 :         case RAW_SEARCH_DATA_NAME_INFO:
     177       65956 :                 file->name_info.file_index   = dir_index;
     178       65956 :                 file->name_info.name.s       = fname;
     179       65956 :                 return NT_STATUS_OK;
     180             : 
     181       13907 :         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
     182       13907 :                 file->both_directory_info.file_index   = dir_index;
     183       13907 :                 file->both_directory_info.create_time  = name->dos.create_time;
     184       13907 :                 file->both_directory_info.access_time  = name->dos.access_time;
     185       13907 :                 file->both_directory_info.write_time   = name->dos.write_time;
     186       13907 :                 file->both_directory_info.change_time  = name->dos.change_time;
     187       13907 :                 file->both_directory_info.size         = name->st.st_size;
     188       13907 :                 file->both_directory_info.alloc_size   = name->dos.alloc_size;
     189       13907 :                 file->both_directory_info.attrib       = name->dos.attrib;
     190       13907 :                 file->both_directory_info.ea_size      = name->dos.ea_size;
     191       13907 :                 file->both_directory_info.short_name.s = pvfs_short_name(pvfs, file, name);
     192       13907 :                 file->both_directory_info.name.s       = fname;
     193       13907 :                 return NT_STATUS_OK;
     194             : 
     195        2103 :         case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
     196        2103 :                 file->id_full_directory_info.file_index   = dir_index;
     197        2103 :                 file->id_full_directory_info.create_time  = name->dos.create_time;
     198        2103 :                 file->id_full_directory_info.access_time  = name->dos.access_time;
     199        2103 :                 file->id_full_directory_info.write_time   = name->dos.write_time;
     200        2103 :                 file->id_full_directory_info.change_time  = name->dos.change_time;
     201        2103 :                 file->id_full_directory_info.size         = name->st.st_size;
     202        2103 :                 file->id_full_directory_info.alloc_size   = name->dos.alloc_size;
     203        2103 :                 file->id_full_directory_info.attrib       = name->dos.attrib;
     204        2103 :                 file->id_full_directory_info.ea_size      = name->dos.ea_size;
     205        2103 :                 file->id_full_directory_info.file_id      = name->dos.file_id;
     206        2103 :                 file->id_full_directory_info.name.s       = fname;
     207        2103 :                 return NT_STATUS_OK;
     208             : 
     209        3170 :         case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
     210        3170 :                 file->id_both_directory_info.file_index   = dir_index;
     211        3170 :                 file->id_both_directory_info.create_time  = name->dos.create_time;
     212        3170 :                 file->id_both_directory_info.access_time  = name->dos.access_time;
     213        3170 :                 file->id_both_directory_info.write_time   = name->dos.write_time;
     214        3170 :                 file->id_both_directory_info.change_time  = name->dos.change_time;
     215        3170 :                 file->id_both_directory_info.size         = name->st.st_size;
     216        3170 :                 file->id_both_directory_info.alloc_size   = name->dos.alloc_size;
     217        3170 :                 file->id_both_directory_info.attrib       = name->dos.attrib;
     218        3170 :                 file->id_both_directory_info.ea_size      = name->dos.ea_size;
     219        3170 :                 file->id_both_directory_info.file_id      = name->dos.file_id;
     220        3170 :                 file->id_both_directory_info.short_name.s = pvfs_short_name(pvfs, file, name);
     221        3170 :                 file->id_both_directory_info.name.s       = fname;
     222        3170 :                 return NT_STATUS_OK;
     223             : 
     224           5 :         case RAW_SEARCH_DATA_GENERIC:
     225             :         case RAW_SEARCH_DATA_UNIX_INFO:
     226             :         case RAW_SEARCH_DATA_UNIX_INFO2:
     227           5 :                 return NT_STATUS_INVALID_LEVEL;
     228             :         }
     229             : 
     230        3978 :         return NT_STATUS_INVALID_LEVEL;
     231             : }
     232             : 
     233             : 
     234             : /*
     235             :   the search fill loop
     236             : */
     237        8391 : static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 
     238             :                                  unsigned int max_count,
     239             :                                  struct pvfs_search_state *search,
     240             :                                  enum smb_search_data_level level,
     241             :                                  unsigned int *reply_count,
     242             :                                  void *search_private, 
     243             :                                  bool (*callback)(void *, const union smb_search_data *))
     244             : {
     245        8391 :         struct pvfs_dir *dir = search->dir;
     246           0 :         NTSTATUS status;
     247             : 
     248        8391 :         *reply_count = 0;
     249             : 
     250        8391 :         if (max_count == 0) {
     251           2 :                 max_count = 1;
     252             :         }
     253             : 
     254      137689 :         while ((*reply_count) < max_count) {
     255           0 :                 union smb_search_data *file;
     256           0 :                 const char *name;
     257      137088 :                 off_t ofs = search->current_index;
     258             : 
     259      137088 :                 name = pvfs_list_next(dir, &search->current_index);
     260      137088 :                 if (name == NULL) break;
     261             : 
     262      129299 :                 file = talloc(mem_ctx, union smb_search_data);
     263      129299 :                 if (!file) {
     264           0 :                         return NT_STATUS_NO_MEMORY;
     265             :                 }
     266             : 
     267      129299 :                 status = fill_search_info(pvfs, level, 
     268             :                                           pvfs_list_unix_path(dir), name, 
     269             :                                           search, search->current_index, file);
     270      129299 :                 if (!NT_STATUS_IS_OK(status)) {
     271       10482 :                         talloc_free(file);
     272       10482 :                         continue;
     273             :                 }
     274             : 
     275      118817 :                 if (!callback(search_private, file)) {
     276           1 :                         talloc_free(file);
     277           1 :                         search->current_index = ofs;
     278           1 :                         break;
     279             :                 }
     280             : 
     281      118816 :                 (*reply_count)++;
     282      118816 :                 talloc_free(file);
     283             :         }
     284             : 
     285        8391 :         pvfs_search_setup_timer(search);
     286             : 
     287        8391 :         return NT_STATUS_OK;
     288             : }
     289             : 
     290             : /*
     291             :   we've run out of search handles - cleanup those that the client forgot
     292             :   to close
     293             : */
     294           0 : static void pvfs_search_cleanup(struct pvfs_state *pvfs)
     295             : {
     296           0 :         int i;
     297           0 :         time_t t = time_mono(NULL);
     298             : 
     299           0 :         for (i=0;i<MAX_OLD_SEARCHES;i++) {
     300           0 :                 struct pvfs_search_state *search;
     301           0 :                 void *p = idr_find(pvfs->search.idtree, i);
     302             : 
     303           0 :                 if (p == NULL) return;
     304             : 
     305           0 :                 search = talloc_get_type(p, struct pvfs_search_state);
     306           0 :                 if (pvfs_list_eos(search->dir, search->current_index) &&
     307           0 :                     search->last_used != 0 &&
     308           0 :                     t > search->last_used + 30) {
     309             :                         /* its almost certainly been forgotten
     310             :                          about */
     311           0 :                         talloc_free(search);
     312             :                 }
     313             :         }
     314             : }
     315             : 
     316             : 
     317             : /* 
     318             :    list files in a directory matching a wildcard pattern - old SMBsearch interface
     319             : */
     320          33 : static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
     321             :                                       struct ntvfs_request *req, union smb_search_first *io, 
     322             :                                       void *search_private, 
     323             :                                       bool (*callback)(void *, const union smb_search_data *))
     324             : {
     325           0 :         struct pvfs_dir *dir;
     326          33 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     327             :                                   struct pvfs_state);
     328           0 :         struct pvfs_search_state *search;
     329           0 :         unsigned int reply_count;
     330           0 :         uint16_t search_attrib;
     331           0 :         const char *pattern;
     332           0 :         NTSTATUS status;
     333           0 :         struct pvfs_filename *name;
     334           0 :         int id;
     335             : 
     336          33 :         search_attrib = io->search_first.in.search_attrib;
     337          33 :         pattern       = io->search_first.in.pattern;
     338             : 
     339             :         /* resolve the cifs name to a posix name */
     340          33 :         status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
     341          33 :         if (!NT_STATUS_IS_OK(status)) {
     342           0 :                 return status;
     343             :         }
     344             : 
     345          33 :         if (!name->has_wildcard && !name->exists) {
     346           3 :                 return STATUS_NO_MORE_FILES;
     347             :         }
     348             : 
     349          30 :         status = pvfs_access_check_parent(pvfs, req, name, SEC_DIR_TRAVERSE | SEC_DIR_LIST);
     350          30 :         if (!NT_STATUS_IS_OK(status)) {
     351           0 :                 return status;
     352             :         }
     353             : 
     354             :         /* we initially make search a child of the request, then if we
     355             :            need to keep it long term we steal it for the private
     356             :            structure */
     357          30 :         search = talloc(req, struct pvfs_search_state);
     358          30 :         if (!search) {
     359           0 :                 return NT_STATUS_NO_MEMORY;
     360             :         }
     361             : 
     362             :         /* do the actual directory listing */
     363          30 :         status = pvfs_list_start(pvfs, name, search, &dir);
     364          30 :         if (!NT_STATUS_IS_OK(status)) {
     365           0 :                 return status;
     366             :         }
     367             : 
     368             :         /* we need to give a handle back to the client so it
     369             :            can continue a search */
     370          30 :         id = idr_get_new(pvfs->search.idtree, search, MAX_OLD_SEARCHES);
     371          30 :         if (id == -1) {
     372           0 :                 pvfs_search_cleanup(pvfs);
     373           0 :                 id = idr_get_new(pvfs->search.idtree, search, MAX_OLD_SEARCHES);
     374             :         }
     375          30 :         if (id == -1) {
     376           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     377             :         }
     378             : 
     379          30 :         search->pvfs = pvfs;
     380          30 :         search->handle = id;
     381          30 :         search->dir = dir;
     382          30 :         search->current_index = 0;
     383          30 :         search->search_attrib = search_attrib & 0xFF;
     384          30 :         search->must_attrib = (search_attrib>>8) & 0xFF;
     385          30 :         search->last_used = time_mono(NULL);
     386          30 :         search->te = NULL;
     387             : 
     388          30 :         DLIST_ADD(pvfs->search.list, search);
     389             : 
     390          30 :         talloc_set_destructor(search, pvfs_search_destructor);
     391             : 
     392          30 :         status = pvfs_search_fill(pvfs, req, io->search_first.in.max_count, search, io->generic.data_level,
     393             :                                   &reply_count, search_private, callback);
     394          30 :         if (!NT_STATUS_IS_OK(status)) {
     395           0 :                 return status;
     396             :         }
     397             : 
     398          30 :         io->search_first.out.count = reply_count;
     399             : 
     400             :         /* not matching any entries is an error */
     401          30 :         if (reply_count == 0) {
     402           0 :                 return STATUS_NO_MORE_FILES;
     403             :         }
     404             : 
     405          30 :         talloc_steal(pvfs, search);
     406             : 
     407          30 :         return NT_STATUS_OK;
     408             : }
     409             : 
     410             : /* continue a old style search */
     411          67 : static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
     412             :                                      struct ntvfs_request *req, union smb_search_next *io, 
     413             :                                      void *search_private, 
     414             :                                      bool (*callback)(void *, const union smb_search_data *))
     415             : {
     416          67 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     417             :                                   struct pvfs_state);
     418           0 :         void *p;
     419           0 :         struct pvfs_search_state *search;
     420           0 :         struct pvfs_dir *dir;
     421           0 :         unsigned int reply_count, max_count;
     422           0 :         uint16_t handle;
     423           0 :         NTSTATUS status;
     424             : 
     425          67 :         handle    = io->search_next.in.id.handle | (io->search_next.in.id.reserved<<8);
     426          67 :         max_count = io->search_next.in.max_count;
     427             : 
     428          67 :         p = idr_find(pvfs->search.idtree, handle);
     429          67 :         if (p == NULL) {
     430             :                 /* we didn't find the search handle */
     431           0 :                 return NT_STATUS_INVALID_HANDLE;
     432             :         }
     433             : 
     434          67 :         search = talloc_get_type(p, struct pvfs_search_state);
     435             : 
     436          67 :         dir = search->dir;
     437             : 
     438          67 :         status = pvfs_list_seek_ofs(dir, io->search_next.in.id.server_cookie, 
     439             :                                     &search->current_index);
     440          67 :         if (!NT_STATUS_IS_OK(status)) {
     441           0 :                 return status;
     442             :         }
     443          67 :         search->last_used = time_mono(NULL);
     444             : 
     445          67 :         status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.data_level,
     446             :                                   &reply_count, search_private, callback);
     447          67 :         if (!NT_STATUS_IS_OK(status)) {
     448           0 :                 return status;
     449             :         }
     450             : 
     451          67 :         io->search_next.out.count = reply_count;
     452             : 
     453             :         /* not matching any entries means end of search */
     454          67 :         if (reply_count == 0) {
     455           7 :                 talloc_free(search);
     456             :         }
     457             : 
     458          67 :         return NT_STATUS_OK;
     459             : }
     460             : 
     461             : /* 
     462             :    list files in a directory matching a wildcard pattern
     463             : */
     464        7079 : static NTSTATUS pvfs_search_first_trans2(struct ntvfs_module_context *ntvfs,
     465             :                                          struct ntvfs_request *req, union smb_search_first *io, 
     466             :                                          void *search_private, 
     467             :                                          bool (*callback)(void *, const union smb_search_data *))
     468             : {
     469           0 :         struct pvfs_dir *dir;
     470        7079 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     471             :                                   struct pvfs_state);
     472           0 :         struct pvfs_search_state *search;
     473           0 :         unsigned int reply_count;
     474           0 :         uint16_t search_attrib, max_count;
     475           0 :         const char *pattern;
     476           0 :         NTSTATUS status;
     477           0 :         struct pvfs_filename *name;
     478           0 :         int id;
     479             : 
     480        7079 :         search_attrib = io->t2ffirst.in.search_attrib;
     481        7079 :         pattern       = io->t2ffirst.in.pattern;
     482        7079 :         max_count     = io->t2ffirst.in.max_count;
     483             : 
     484             :         /* resolve the cifs name to a posix name */
     485        7079 :         status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
     486        7079 :         if (!NT_STATUS_IS_OK(status)) {
     487           2 :                 return status;
     488             :         }
     489             : 
     490        7077 :         if (!name->has_wildcard && !name->exists) {
     491          24 :                 return NT_STATUS_NO_SUCH_FILE;
     492             :         }
     493             : 
     494        7053 :         status = pvfs_access_check_parent(pvfs, req, name, SEC_DIR_TRAVERSE | SEC_DIR_LIST);
     495        7053 :         if (!NT_STATUS_IS_OK(status)) {
     496           4 :                 return status;
     497             :         }
     498             : 
     499             :         /* we initially make search a child of the request, then if we
     500             :            need to keep it long term we steal it for the private
     501             :            structure */
     502        7049 :         search = talloc(req, struct pvfs_search_state);
     503        7049 :         if (!search) {
     504           0 :                 return NT_STATUS_NO_MEMORY;
     505             :         }
     506             : 
     507             :         /* do the actual directory listing */
     508        7049 :         status = pvfs_list_start(pvfs, name, search, &dir);
     509        7049 :         if (!NT_STATUS_IS_OK(status)) {
     510           0 :                 return status;
     511             :         }
     512             : 
     513        7049 :         id = idr_get_new(pvfs->search.idtree, search, MAX_SEARCH_HANDLES);
     514        7049 :         if (id == -1) {
     515           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     516             :         }
     517             : 
     518        7049 :         search->pvfs = pvfs;
     519        7049 :         search->handle = id;
     520        7049 :         search->dir = dir;
     521        7049 :         search->current_index = 0;
     522        7049 :         search->search_attrib = search_attrib;
     523        7049 :         search->must_attrib = 0;
     524        7049 :         search->last_used = 0;
     525        7049 :         search->num_ea_names = io->t2ffirst.in.num_names;
     526        7049 :         search->ea_names = io->t2ffirst.in.ea_names;
     527        7049 :         search->te = NULL;
     528             : 
     529        7049 :         DLIST_ADD(pvfs->search.list, search);
     530        7049 :         talloc_set_destructor(search, pvfs_search_destructor);
     531             : 
     532        7049 :         status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.data_level,
     533             :                                   &reply_count, search_private, callback);
     534        7049 :         if (!NT_STATUS_IS_OK(status)) {
     535           0 :                 return status;
     536             :         }
     537             : 
     538             :         /* not matching any entries is an error */
     539        7049 :         if (reply_count == 0) {
     540        4230 :                 return NT_STATUS_NO_SUCH_FILE;
     541             :         }
     542             : 
     543        2819 :         io->t2ffirst.out.count = reply_count;
     544        2819 :         io->t2ffirst.out.handle = search->handle;
     545        2819 :         io->t2ffirst.out.end_of_search = pvfs_list_eos(dir, search->current_index) ? 1 : 0;
     546             : 
     547             :         /* work out if we are going to keep the search state
     548             :            and allow for a search continue */
     549        2819 :         if ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
     550        2621 :             ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && 
     551        2617 :              io->t2ffirst.out.end_of_search)) {
     552        2787 :                 talloc_free(search);
     553             :         } else {
     554          32 :                 talloc_steal(pvfs, search);
     555             :         }
     556             : 
     557        2819 :         return NT_STATUS_OK;
     558             : }
     559             : 
     560             : /* continue a search */
     561         339 : static NTSTATUS pvfs_search_next_trans2(struct ntvfs_module_context *ntvfs,
     562             :                                         struct ntvfs_request *req, union smb_search_next *io, 
     563             :                                         void *search_private, 
     564             :                                         bool (*callback)(void *, const union smb_search_data *))
     565             : {
     566         339 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     567             :                                   struct pvfs_state);
     568           0 :         void *p;
     569           0 :         struct pvfs_search_state *search;
     570           0 :         struct pvfs_dir *dir;
     571           0 :         unsigned int reply_count;
     572           0 :         uint16_t handle;
     573           0 :         NTSTATUS status;
     574             : 
     575         339 :         handle = io->t2fnext.in.handle;
     576             : 
     577         339 :         p = idr_find(pvfs->search.idtree, handle);
     578         339 :         if (p == NULL) {
     579             :                 /* we didn't find the search handle */
     580           0 :                 return NT_STATUS_INVALID_HANDLE;
     581             :         }
     582             : 
     583         339 :         search = talloc_get_type(p, struct pvfs_search_state);
     584             : 
     585         339 :         dir = search->dir;
     586             :         
     587         339 :         status = NT_STATUS_OK;
     588             : 
     589             :         /* work out what type of continuation is being used */
     590         339 :         if (io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
     591         241 :                 status = pvfs_list_seek(dir, io->t2fnext.in.last_name, &search->current_index);
     592         241 :                 if (!NT_STATUS_IS_OK(status) && io->t2fnext.in.resume_key) {
     593           0 :                         status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
     594             :                                                     &search->current_index);
     595             :                 }
     596          98 :         } else if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE)) {
     597          49 :                 status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
     598             :                                             &search->current_index);
     599             :         }
     600         339 :         if (!NT_STATUS_IS_OK(status)) {
     601           0 :                 return status;
     602             :         }
     603             : 
     604         339 :         search->num_ea_names = io->t2fnext.in.num_names;
     605         339 :         search->ea_names = io->t2fnext.in.ea_names;
     606             : 
     607         339 :         status = pvfs_search_fill(pvfs, req, io->t2fnext.in.max_count, search, io->generic.data_level,
     608             :                                   &reply_count, search_private, callback);
     609         339 :         if (!NT_STATUS_IS_OK(status)) {
     610           0 :                 return status;
     611             :         }
     612             : 
     613         339 :         io->t2fnext.out.count = reply_count;
     614         339 :         io->t2fnext.out.end_of_search = pvfs_list_eos(dir, search->current_index) ? 1 : 0;
     615             : 
     616             :         /* work out if we are going to keep the search state */
     617         339 :         if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
     618         339 :             ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && 
     619         160 :              io->t2fnext.out.end_of_search)) {
     620          28 :                 talloc_free(search);
     621             :         }
     622             : 
     623         339 :         return NT_STATUS_OK;
     624             : }
     625             : 
     626         467 : static NTSTATUS pvfs_search_first_smb2(struct ntvfs_module_context *ntvfs,
     627             :                                        struct ntvfs_request *req, const struct smb2_find *io, 
     628             :                                        void *search_private, 
     629             :                                        bool (*callback)(void *, const union smb_search_data *))
     630             : {
     631           0 :         struct pvfs_dir *dir;
     632         467 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     633             :                                   struct pvfs_state);
     634           0 :         struct pvfs_search_state *search;
     635           0 :         unsigned int reply_count;
     636           0 :         uint16_t max_count;
     637           0 :         const char *pattern;
     638           0 :         NTSTATUS status;
     639           0 :         struct pvfs_filename *name;
     640           0 :         struct pvfs_file *f;
     641             : 
     642         467 :         f = pvfs_find_fd(pvfs, req, io->in.file.ntvfs);
     643         467 :         if (!f) {
     644           0 :                 return NT_STATUS_FILE_CLOSED;
     645             :         }
     646             : 
     647             :         /* its only valid for directories */
     648         467 :         if (f->handle->fd != -1) {
     649           0 :                 return NT_STATUS_INVALID_PARAMETER;
     650             :         }
     651             : 
     652         467 :         if (!(f->access_mask & SEC_DIR_LIST)) {
     653           0 :                 return NT_STATUS_ACCESS_DENIED;
     654             :         }
     655             : 
     656         467 :         if (f->search) {
     657           0 :                 talloc_free(f->search);
     658           0 :                 f->search = NULL;
     659             :         }
     660             : 
     661         467 :         if (strequal(io->in.pattern, "")) {
     662           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
     663             :         }
     664         467 :         if (strchr_m(io->in.pattern, '\\')) {
     665           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
     666             :         }
     667         467 :         if (strchr_m(io->in.pattern, '/')) {
     668           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
     669             :         }
     670             : 
     671         467 :         if (strequal("", f->handle->name->original_name)) {
     672           1 :                 pattern = talloc_asprintf(req, "%s", io->in.pattern);
     673           1 :                 NT_STATUS_HAVE_NO_MEMORY(pattern);
     674             :         } else {
     675         466 :                 pattern = talloc_asprintf(req, "%s\\%s",
     676         466 :                                           f->handle->name->original_name,
     677         466 :                                           io->in.pattern);
     678         466 :                 NT_STATUS_HAVE_NO_MEMORY(pattern);
     679             :         }
     680             : 
     681             :         /* resolve the cifs name to a posix name */
     682         467 :         status = pvfs_resolve_name(pvfs, req, pattern, PVFS_RESOLVE_WILDCARD, &name);
     683         467 :         NT_STATUS_NOT_OK_RETURN(status);
     684             : 
     685         467 :         if (!name->has_wildcard && !name->exists) {
     686           0 :                 return NT_STATUS_NO_SUCH_FILE;
     687             :         }
     688             : 
     689             :         /* we initially make search a child of the request, then if we
     690             :            need to keep it long term we steal it for the private
     691             :            structure */
     692         467 :         search = talloc(req, struct pvfs_search_state);
     693         467 :         NT_STATUS_HAVE_NO_MEMORY(search);
     694             : 
     695             :         /* do the actual directory listing */
     696         467 :         status = pvfs_list_start(pvfs, name, search, &dir);
     697         467 :         NT_STATUS_NOT_OK_RETURN(status);
     698             : 
     699         467 :         search->pvfs         = pvfs;
     700         467 :         search->handle               = INVALID_SEARCH_HANDLE;
     701         467 :         search->dir          = dir;
     702         467 :         search->current_index        = 0;
     703         467 :         search->search_attrib        = 0x0000FFFF;
     704         467 :         search->must_attrib  = 0;
     705         467 :         search->last_used    = 0;
     706         467 :         search->num_ea_names = 0;
     707         467 :         search->ea_names     = NULL;
     708         467 :         search->te           = NULL;
     709             : 
     710         467 :         if (io->in.continue_flags & SMB2_CONTINUE_FLAG_SINGLE) {
     711           2 :                 max_count = 1;
     712             :         } else {
     713         465 :                 max_count = UINT16_MAX;
     714             :         }
     715             : 
     716         467 :         status = pvfs_search_fill(pvfs, req, max_count, search, io->data_level,
     717             :                                   &reply_count, search_private, callback);
     718         467 :         NT_STATUS_NOT_OK_RETURN(status);
     719             : 
     720             :         /* not matching any entries is an error */
     721         467 :         if (reply_count == 0) {
     722           0 :                 return NT_STATUS_NO_SUCH_FILE;
     723             :         }
     724             : 
     725         467 :         f->search = talloc_steal(f, search);
     726             : 
     727         467 :         return NT_STATUS_OK;
     728             : }
     729             : 
     730         906 : static NTSTATUS pvfs_search_next_smb2(struct ntvfs_module_context *ntvfs,
     731             :                                       struct ntvfs_request *req, const struct smb2_find *io, 
     732             :                                       void *search_private, 
     733             :                                       bool (*callback)(void *, const union smb_search_data *))
     734             : {
     735         906 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     736             :                                   struct pvfs_state);
     737           0 :         struct pvfs_search_state *search;
     738           0 :         unsigned int reply_count;
     739           0 :         uint16_t max_count;
     740           0 :         NTSTATUS status;
     741           0 :         struct pvfs_file *f;
     742             : 
     743         906 :         f = pvfs_find_fd(pvfs, req, io->in.file.ntvfs);
     744         906 :         if (!f) {
     745           0 :                 return NT_STATUS_FILE_CLOSED;
     746             :         }
     747             : 
     748             :         /* its only valid for directories */
     749         906 :         if (f->handle->fd != -1) {
     750           0 :                 return NT_STATUS_INVALID_PARAMETER;
     751             :         }
     752             : 
     753             :         /* if there's no search started on the dir handle, it's like a search_first */
     754         906 :         search = f->search;
     755         906 :         if (!search) {
     756         467 :                 return pvfs_search_first_smb2(ntvfs, req, io, search_private, callback);
     757             :         }
     758             : 
     759         439 :         if (io->in.continue_flags & SMB2_CONTINUE_FLAG_RESTART) {
     760           0 :                 search->current_index = 0;
     761             :         }
     762             : 
     763         439 :         if (io->in.continue_flags & SMB2_CONTINUE_FLAG_SINGLE) {
     764           0 :                 max_count = 1;
     765             :         } else {
     766         439 :                 max_count = UINT16_MAX;
     767             :         }
     768             : 
     769         439 :         status = pvfs_search_fill(pvfs, req, max_count, search, io->data_level,
     770             :                                   &reply_count, search_private, callback);
     771         439 :         NT_STATUS_NOT_OK_RETURN(status);
     772             : 
     773             :         /* not matching any entries is an error */
     774         439 :         if (reply_count == 0) {
     775         439 :                 return STATUS_NO_MORE_FILES;
     776             :         }
     777             : 
     778           0 :         return NT_STATUS_OK;
     779             : }
     780             : 
     781             : /* 
     782             :    list files in a directory matching a wildcard pattern
     783             : */
     784        7112 : NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
     785             :                            struct ntvfs_request *req, union smb_search_first *io, 
     786             :                            void *search_private, 
     787             :                            bool (*callback)(void *, const union smb_search_data *))
     788             : {
     789        7112 :         switch (io->generic.level) {
     790          33 :         case RAW_SEARCH_SEARCH:
     791             :         case RAW_SEARCH_FFIRST:
     792             :         case RAW_SEARCH_FUNIQUE:
     793          33 :                 return pvfs_search_first_old(ntvfs, req, io, search_private, callback);
     794             : 
     795        7079 :         case RAW_SEARCH_TRANS2:
     796        7079 :                 return pvfs_search_first_trans2(ntvfs, req, io, search_private, callback);
     797             : 
     798           0 :         case RAW_SEARCH_SMB2:
     799           0 :                 return pvfs_search_first_smb2(ntvfs, req, &io->smb2, search_private, callback);
     800             :         }
     801             : 
     802           0 :         return NT_STATUS_INVALID_LEVEL;
     803             : }
     804             : 
     805             : /* continue a search */
     806        1312 : NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
     807             :                           struct ntvfs_request *req, union smb_search_next *io, 
     808             :                           void *search_private, 
     809             :                           bool (*callback)(void *, const union smb_search_data *))
     810             : {
     811        1312 :         switch (io->generic.level) {
     812          67 :         case RAW_SEARCH_SEARCH:
     813             :         case RAW_SEARCH_FFIRST:
     814          67 :                 return pvfs_search_next_old(ntvfs, req, io, search_private, callback);
     815             : 
     816           0 :         case RAW_SEARCH_FUNIQUE:
     817           0 :                 return NT_STATUS_INVALID_LEVEL;
     818             : 
     819         339 :         case RAW_SEARCH_TRANS2:
     820         339 :                 return pvfs_search_next_trans2(ntvfs, req, io, search_private, callback);
     821             : 
     822         906 :         case RAW_SEARCH_SMB2:
     823         906 :                 return pvfs_search_next_smb2(ntvfs, req, &io->smb2, search_private, callback);
     824             :         }
     825             : 
     826           0 :         return NT_STATUS_INVALID_LEVEL;
     827             : }
     828             : 
     829             : 
     830             : /* close a search */
     831           1 : NTSTATUS pvfs_search_close(struct ntvfs_module_context *ntvfs,
     832             :                            struct ntvfs_request *req, union smb_search_close *io)
     833             : {
     834           1 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     835             :                                   struct pvfs_state);
     836           0 :         void *p;
     837           0 :         struct pvfs_search_state *search;
     838           1 :         uint16_t handle = INVALID_SEARCH_HANDLE;
     839             : 
     840           1 :         switch (io->generic.level) {
     841           0 :         case RAW_FINDCLOSE_GENERIC:
     842           0 :                 return NT_STATUS_INVALID_LEVEL;
     843             : 
     844           1 :         case RAW_FINDCLOSE_FCLOSE:
     845           1 :                 handle = io->fclose.in.id.handle;
     846           1 :                 break;
     847             : 
     848           0 :         case RAW_FINDCLOSE_FINDCLOSE:
     849           0 :                 handle = io->findclose.in.handle;
     850           0 :                 break;
     851             :         }
     852             : 
     853           1 :         p = idr_find(pvfs->search.idtree, handle);
     854           1 :         if (p == NULL) {
     855             :                 /* we didn't find the search handle */
     856           0 :                 return NT_STATUS_INVALID_HANDLE;
     857             :         }
     858             : 
     859           1 :         search = talloc_get_type(p, struct pvfs_search_state);
     860             : 
     861           1 :         talloc_free(search);
     862             : 
     863           1 :         return NT_STATUS_OK;
     864             : }
     865             : 

Generated by: LCOV version 1.14