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

Generated by: LCOV version 1.13