root/source4/ntvfs/posix/pvfs_search.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pvfs_search_destructor
  2. pvfs_search_timer
  3. pvfs_search_setup_timer
  4. fill_search_info
  5. pvfs_search_fill
  6. pvfs_search_cleanup
  7. pvfs_search_first_old
  8. pvfs_search_next_old
  9. pvfs_search_first_trans2
  10. pvfs_search_next_trans2
  11. pvfs_search_first_smb2
  12. pvfs_search_next_smb2
  13. pvfs_search_first
  14. pvfs_search_next
  15. pvfs_search_close

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

/* [<][>][^][v][top][bottom][index][help] */