LCOV - code coverage report
Current view: top level - source4/torture/smb2 - dir.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 529 838 63.1 %
Date: 2024-04-21 15:09:00 Functions: 15 19 78.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 dir list test suite
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    Copyright (C) Zachary Loafman 2009
       8             :    Copyright (C) Aravind Srinivasan 2009
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "libcli/smb2/smb2.h"
      26             : #include "libcli/smb2/smb2_calls.h"
      27             : #include "libcli/smb_composite/smb_composite.h"
      28             : #include "libcli/raw/libcliraw.h"
      29             : #include "libcli/raw/raw_proto.h"
      30             : #include "libcli/libcli.h"
      31             : 
      32             : #include "torture/torture.h"
      33             : #include "torture/smb2/proto.h"
      34             : #include "torture/util.h"
      35             : 
      36             : #include "system/filesys.h"
      37             : #include "lib/util/tsort.h"
      38             : 
      39             : #define DNAME   "smb2_dir"
      40             : #define NFILES  100
      41             : 
      42             : struct file_elem {
      43             :         char *name;
      44             :         NTTIME create_time;
      45             :         bool found;
      46             : };
      47             : 
      48          12 : static NTSTATUS populate_tree(struct torture_context *tctx,
      49             :                               TALLOC_CTX *mem_ctx,
      50             :                               struct smb2_tree *tree,
      51             :                               struct file_elem *files,
      52             :                               int nfiles,
      53             :                               struct smb2_handle *h_out)
      54             : {
      55           0 :         struct smb2_create create;
      56          12 :         char **strs = NULL;
      57           0 :         NTSTATUS status;
      58          12 :         bool ret = true;
      59           0 :         int i;
      60             : 
      61          12 :         smb2_deltree(tree, DNAME);
      62             : 
      63          12 :         ZERO_STRUCT(create);
      64          12 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
      65          12 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      66          12 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
      67          12 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
      68             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
      69             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
      70          12 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
      71          12 :         create.in.fname = DNAME;
      72             : 
      73          12 :         status = smb2_create(tree, mem_ctx, &create);
      74          12 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
      75          12 :         *h_out = create.out.file.handle;
      76             : 
      77          12 :         ZERO_STRUCT(create);
      78          12 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
      79          12 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
      80          12 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
      81             : 
      82          12 :         strs = generate_unique_strs(mem_ctx, 8, nfiles);
      83          12 :         if (strs == NULL) {
      84           0 :                 status = NT_STATUS_OBJECT_NAME_COLLISION;
      85           0 :                 goto done;
      86             :         }
      87        3612 :         for (i = 0; i < nfiles; i++) {
      88        3600 :                 files[i].name = strs[i];
      89        7200 :                 create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
      90        3600 :                     DNAME, files[i].name);
      91        3600 :                 status = smb2_create(tree, mem_ctx, &create);
      92        3600 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
      93        3600 :                 files[i].create_time = create.out.create_time;
      94        3600 :                 smb2_util_close(tree, create.out.file.handle);
      95             :         }
      96          12 :  done:
      97          12 :         if (!ret) {
      98           0 :                 return status;
      99             :         }
     100             : 
     101          12 :         return status;
     102             : }
     103             : 
     104             : /*
     105             :   test find continue
     106             : */
     107             : 
     108           4 : static bool test_find(struct torture_context *tctx,
     109             :                       struct smb2_tree *tree)
     110             : {
     111           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     112           0 :         struct smb2_handle h;
     113           0 :         struct smb2_find f;
     114           0 :         union smb_search_data *d;
     115           4 :         struct file_elem files[NFILES] = {};
     116           0 :         NTSTATUS status;
     117           4 :         bool ret = true;
     118           0 :         unsigned int count;
     119           4 :         int i, j = 0, file_count = 0;
     120             : 
     121           4 :         status = populate_tree(tctx, mem_ctx, tree, files, NFILES, &h);
     122             : 
     123           4 :         ZERO_STRUCT(f);
     124           4 :         f.in.file.handle        = h;
     125           4 :         f.in.pattern            = "*";
     126           4 :         f.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
     127           4 :         f.in.max_response_size  = 0x100;
     128           4 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
     129             : 
     130           0 :         do {
     131          20 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
     132          20 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
     133           4 :                         break;
     134          16 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     135             : 
     136         424 :                 for (i = 0; i < count; i++) {
     137           0 :                         bool expected;
     138         408 :                         const char *found = d[i].both_directory_info.name.s;
     139         408 :                         NTTIME ct = d[i].both_directory_info.create_time;
     140             : 
     141         408 :                         if (!strcmp(found, ".") || !strcmp(found, ".."))
     142           8 :                                 continue;
     143             : 
     144         400 :                         expected = false;
     145       20200 :                         for (j = 0; j < NFILES; j++) {
     146       20200 :                                 if (strcmp(files[j].name, found) != 0) {
     147       19800 :                                         continue;
     148             :                                 }
     149             : 
     150         400 :                                 torture_assert_u64_equal_goto(tctx,
     151             :                                                         files[j].create_time,
     152             :                                                         ct, ret, done,
     153             :                                                         talloc_asprintf(tctx,
     154             :                                                         "file[%d]\n", j));
     155             : 
     156         400 :                                 files[j].found = true;
     157         400 :                                 expected = true;
     158         400 :                                 break;
     159             :                         }
     160             : 
     161         400 :                         if (expected)
     162         400 :                                 continue;
     163             : 
     164           0 :                         torture_result(tctx, TORTURE_FAIL,
     165             :                             "(%s): didn't expect %s\n",
     166             :                             __location__, found);
     167           0 :                         ret = false;
     168           0 :                         goto done;
     169             :                 }
     170             : 
     171          16 :                 file_count = file_count + i;
     172          16 :                 f.in.continue_flags = 0;
     173          16 :                 f.in.max_response_size  = 4096;
     174          16 :         } while (count != 0);
     175             : 
     176           4 :         torture_assert_int_equal_goto(tctx, file_count, NFILES + 2, ret, done,
     177             :                                       "");
     178             : 
     179         404 :         for (i = 0; i < NFILES; i++) {
     180         400 :                 if (files[j].found)
     181         400 :                         continue;
     182             : 
     183           0 :                 torture_result(tctx, TORTURE_FAIL,
     184             :                     "(%s): expected to find %s, but didn't\n",
     185             :                     __location__, files[j].name);
     186           0 :                 ret = false;
     187           0 :                 goto done;
     188             :         }
     189             : 
     190           4 :  done:
     191           4 :         smb2_deltree(tree, DNAME);
     192           4 :         talloc_free(mem_ctx);
     193             : 
     194           4 :         return ret;
     195             : }
     196             : 
     197             : /*
     198             :   test fixed enumeration
     199             : */
     200             : 
     201           4 : static bool test_fixed(struct torture_context *tctx,
     202             :                        struct smb2_tree *tree)
     203             : {
     204           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     205           0 :         struct smb2_create create;
     206           4 :         struct smb2_handle h = {{0}};
     207           4 :         struct smb2_handle h2 = {{0}};
     208           0 :         struct smb2_find f;
     209           0 :         union smb_search_data *d;
     210           4 :         struct file_elem files[NFILES] = {};
     211           0 :         NTSTATUS status;
     212           4 :         bool ret = true;
     213           0 :         unsigned int count;
     214           0 :         int i;
     215             : 
     216           4 :         status = populate_tree(tctx, mem_ctx, tree, files, NFILES, &h);
     217             : 
     218           4 :         ZERO_STRUCT(create);
     219           4 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
     220           4 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     221           4 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
     222           4 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     223             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
     224             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
     225           4 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
     226           4 :         create.in.fname = DNAME;
     227             : 
     228           4 :         status = smb2_create(tree, mem_ctx, &create);
     229           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     230           4 :         h2 = create.out.file.handle;
     231             : 
     232           4 :         ZERO_STRUCT(f);
     233           4 :         f.in.file.handle        = h;
     234           4 :         f.in.pattern            = "*";
     235           4 :         f.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
     236           4 :         f.in.max_response_size  = 0x100;
     237           4 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
     238             : 
     239             :         /* Start enumeration on h, then delete all from h2 */
     240           4 :         status = smb2_find_level(tree, tree, &f, &count, &d);
     241           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     242             : 
     243           4 :         f.in.file.handle        = h2;
     244             : 
     245           0 :         do {
     246          20 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
     247          20 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
     248           4 :                         break;
     249          16 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     250             : 
     251         424 :                 for (i = 0; i < count; i++) {
     252         408 :                         const char *found = d[i].both_directory_info.name.s;
     253         408 :                         char *path = talloc_asprintf(mem_ctx, "%s\\%s",
     254             :                             DNAME, found);
     255             : 
     256         408 :                         if (!strcmp(found, ".") || !strcmp(found, ".."))
     257           8 :                                 continue;
     258             : 
     259         400 :                         status = smb2_util_unlink(tree, path);
     260         400 :                         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     261             :                                                         "");
     262             : 
     263         400 :                         talloc_free(path);
     264             :                 }
     265             : 
     266          16 :                 f.in.continue_flags = 0;
     267          16 :                 f.in.max_response_size  = 4096;
     268          16 :         } while (count != 0);
     269             : 
     270             :         /* Now finish h enumeration. */
     271           4 :         f.in.file.handle = h;
     272             : 
     273           0 :         do {
     274           8 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
     275           8 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
     276           4 :                         break;
     277           4 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     278             : 
     279           8 :                 for (i = 0; i < count; i++) {
     280           4 :                         const char *found = d[i].both_directory_info.name.s;
     281             : 
     282           4 :                         if (!strcmp(found, ".") || !strcmp(found, ".."))
     283           4 :                                 continue;
     284             : 
     285           0 :                         torture_result(tctx, TORTURE_FAIL,
     286             :                                        "(%s): didn't expect %s (count=%u)\n",
     287             :                                        __location__, found, count);
     288           0 :                         ret = false;
     289           0 :                         goto done;
     290             :                 }
     291             : 
     292           4 :                 f.in.continue_flags = 0;
     293           4 :                 f.in.max_response_size  = 4096;
     294           4 :         } while (count != 0);
     295             : 
     296           0 :  done:
     297           4 :         smb2_util_close(tree, h);
     298           4 :         smb2_util_close(tree, h2);
     299           4 :         smb2_deltree(tree, DNAME);
     300           4 :         talloc_free(mem_ctx);
     301             : 
     302           4 :         return ret;
     303             : }
     304             : 
     305             : static struct {
     306             :         const char *name;
     307             :         uint8_t level;
     308             :         enum smb_search_data_level data_level;
     309             :         int name_offset;
     310             :         int resume_key_offset;
     311             :         uint32_t capability_mask;
     312             :         NTSTATUS status;
     313             :         union smb_search_data data;
     314             : } levels[] = {
     315             :         {
     316             :                 .name              = "SMB2_FIND_DIRECTORY_INFO",
     317             :                 .level             = SMB2_FIND_DIRECTORY_INFO,
     318             :                 .data_level        = RAW_SEARCH_DATA_DIRECTORY_INFO,
     319             :                 .name_offset       = offsetof(union smb_search_data,
     320             :                                               directory_info.name.s),
     321             :                 .resume_key_offset = offsetof(union smb_search_data,
     322             :                                               directory_info.file_index),
     323             :         },
     324             :         {
     325             :                 .name              = "SMB2_FIND_FULL_DIRECTORY_INFO",
     326             :                 .level             = SMB2_FIND_FULL_DIRECTORY_INFO,
     327             :                 .data_level        = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
     328             :                 .name_offset       = offsetof(union smb_search_data,
     329             :                                               full_directory_info.name.s),
     330             :                 .resume_key_offset = offsetof(union smb_search_data,
     331             :                                               full_directory_info.file_index),
     332             :         },
     333             :         {
     334             :                 .name              = "SMB2_FIND_NAME_INFO",
     335             :                 .level             = SMB2_FIND_NAME_INFO,
     336             :                 .data_level        = RAW_SEARCH_DATA_NAME_INFO,
     337             :                 .name_offset       = offsetof(union smb_search_data,
     338             :                                               name_info.name.s),
     339             :                 .resume_key_offset = offsetof(union smb_search_data,
     340             :                                               name_info.file_index),
     341             :         },
     342             :         {
     343             :                 .name              = "SMB2_FIND_BOTH_DIRECTORY_INFO",
     344             :                 .level             = SMB2_FIND_BOTH_DIRECTORY_INFO,
     345             :                 .data_level        = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
     346             :                 .name_offset       = offsetof(union smb_search_data,
     347             :                                               both_directory_info.name.s),
     348             :                 .resume_key_offset = offsetof(union smb_search_data,
     349             :                                               both_directory_info.file_index),
     350             :         },
     351             :         {
     352             :                 .name              = "SMB2_FIND_ID_FULL_DIRECTORY_INFO",
     353             :                 .level             = SMB2_FIND_ID_FULL_DIRECTORY_INFO,
     354             :                 .data_level        = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO,
     355             :                 .name_offset       = offsetof(union smb_search_data,
     356             :                                               id_full_directory_info.name.s),
     357             :                 .resume_key_offset = offsetof(union smb_search_data,
     358             :                                               id_full_directory_info.file_index),
     359             :         },
     360             :         {
     361             :                 .name              = "SMB2_FIND_ID_BOTH_DIRECTORY_INFO",
     362             :                 .level             = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
     363             :                 .data_level        = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO,
     364             :                 .name_offset       = offsetof(union smb_search_data,
     365             :                                               id_both_directory_info.name.s),
     366             :                 .resume_key_offset = offsetof(union smb_search_data,
     367             :                                               id_both_directory_info.file_index),
     368             :         }
     369             : };
     370             : 
     371             : /*
     372             :   extract the name from a smb_data structure and level
     373             : */
     374     8791344 : static const char *extract_name(union smb_search_data *data,
     375             :                                 uint8_t level,
     376             :                                 enum smb_search_data_level data_level)
     377             : {
     378           0 :         int i;
     379    19230832 :         for (i=0;i<ARRAY_SIZE(levels);i++) {
     380    19230832 :                 if (level == levels[i].level &&
     381     8791344 :                     data_level == levels[i].data_level) {
     382     8791344 :                         return *(const char **)(levels[i].name_offset + (char *)data);
     383             :                 }
     384             :         }
     385           0 :         return NULL;
     386             : }
     387             : 
     388             : /* find a level in the table by name */
     389           0 : static union smb_search_data *find(const char *name)
     390             : {
     391           0 :         int i;
     392           0 :         for (i=0;i<ARRAY_SIZE(levels);i++) {
     393           0 :                 if (NT_STATUS_IS_OK(levels[i].status) &&
     394           0 :                     strcmp(levels[i].name, name) == 0) {
     395           0 :                         return &levels[i].data;
     396             :                 }
     397             :         }
     398           0 :         return NULL;
     399             : }
     400             : 
     401           0 : static bool fill_level_data(TALLOC_CTX *mem_ctx,
     402             :                             union smb_search_data *data,
     403             :                             union smb_search_data *d,
     404             :                             unsigned int count,
     405             :                             uint8_t level,
     406             :                             enum smb_search_data_level data_level)
     407             : {
     408           0 :         int i;
     409           0 :         const char *sname = NULL;
     410           0 :         for (i=0; i < count ; i++) {
     411           0 :                 sname = extract_name(&d[i], level, data_level);
     412           0 :                 if (sname == NULL)
     413           0 :                         return false;
     414           0 :                 if (!strcmp(sname, ".") || !strcmp(sname, ".."))
     415           0 :                         continue;
     416           0 :                 *data = d[i];
     417             :         }
     418           0 :         return true;
     419             : }
     420             : 
     421             : 
     422           0 : NTSTATUS torture_single_file_search(struct smb2_tree *tree,
     423             :                                     TALLOC_CTX *mem_ctx,
     424             :                                     const char *pattern,
     425             :                                     uint8_t level,
     426             :                                     enum smb_search_data_level data_level,
     427             :                                     int idx,
     428             :                                     union smb_search_data *d,
     429             :                                     unsigned int *count,
     430             :                                     struct smb2_handle *h)
     431             : {
     432           0 :         struct smb2_find f;
     433           0 :         NTSTATUS status;
     434             : 
     435           0 :         ZERO_STRUCT(f);
     436           0 :         f.in.file.handle        = *h;
     437           0 :         f.in.pattern            = pattern;
     438           0 :         f.in.continue_flags     = SMB2_CONTINUE_FLAG_RESTART;
     439           0 :         f.in.max_response_size  = 0x100;
     440           0 :         f.in.level              = level;
     441             : 
     442           0 :         status = smb2_find_level(tree, tree, &f, count, &d);
     443           0 :         if (NT_STATUS_IS_OK(status))
     444           0 :                 fill_level_data(mem_ctx, &levels[idx].data, d, *count, level,
     445             :                                 data_level);
     446           0 :         return status;
     447             : }
     448             : 
     449             : /*
     450             :    basic testing of all File Information Classes using a single file
     451             : */
     452           4 : static bool test_one_file(struct torture_context *tctx,
     453             :                           struct smb2_tree *tree)
     454             : {
     455           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     456           4 :         bool ret = true;
     457           4 :         const char *fname =  "torture_search.txt";
     458           0 :         NTSTATUS status;
     459           0 :         int i;
     460           0 :         unsigned int count;
     461           0 :         union smb_fileinfo all_info2, alt_info, internal_info;
     462           0 :         union smb_search_data *s;
     463           0 :         union smb_search_data d;
     464           0 :         struct smb2_handle h, h2;
     465             : 
     466           4 :         status = torture_smb2_testdir(tree, DNAME, &h);
     467           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     468             : 
     469           4 :         status = smb2_create_complex_file(tctx, tree, DNAME "\\torture_search.txt",
     470             :                                           &h2);
     471           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     472             : 
     473             :         /* call all the File Information Classes */
     474           0 :         for (i=0;i<ARRAY_SIZE(levels);i++) {
     475           0 :                 torture_comment(tctx, "Testing %s %d\n", levels[i].name,
     476           0 :                                 levels[i].level);
     477             : 
     478           0 :                 levels[i].status = torture_single_file_search(tree, mem_ctx,
     479           0 :                                    fname, levels[i].level, levels[i].data_level,
     480             :                                    i, &d, &count, &h);
     481           0 :                 torture_assert_ntstatus_ok_goto(tctx, levels[i].status, ret,
     482             :                                                 done, "");
     483             :         }
     484             : 
     485             :         /* get the all_info file into to check against */
     486           0 :         all_info2.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
     487           0 :         all_info2.generic.in.file.handle = h2;
     488           0 :         status = smb2_getinfo_file(tree, tctx, &all_info2);
     489           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     490             :                                         "RAW_FILEINFO_ALL_INFO failed");
     491             : 
     492           0 :         alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
     493           0 :         alt_info.generic.in.file.handle = h2;
     494           0 :         status = smb2_getinfo_file(tree, tctx, &alt_info);
     495           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     496             :                                         "RAW_FILEINFO_ALT_NAME_INFO failed");
     497             : 
     498           0 :         internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
     499           0 :         internal_info.generic.in.file.handle = h2;
     500           0 :         status = smb2_getinfo_file(tree, tctx, &internal_info);
     501           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     502             :                                         "RAW_FILEINFO_INTERNAL_INFORMATION "
     503             :                                         "failed");
     504             : 
     505             : #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
     506             :         s = find(name); \
     507             :         if (s) { \
     508             :                 if ((s->sname1.field1) != (v.sname2.out.field2)) { \
     509             :                         torture_result(tctx, TORTURE_FAIL, \
     510             :                             "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
     511             :                             __location__, \
     512             :                             #sname1, #field1, (int)s->sname1.field1, \
     513             :                             #sname2, #field2, (int)v.sname2.out.field2); \
     514             :                         ret = false; \
     515             :                 } \
     516             :         }} while (0)
     517             : 
     518             : #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
     519             :         s = find(name); \
     520             :         if (s) { \
     521             :                 if (s->sname1.field1 != \
     522             :                     (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
     523             :                         torture_result(tctx, TORTURE_FAIL, \
     524             :                             "(%s) %s/%s [%s] != %s/%s [%s]\n", \
     525             :                             __location__, \
     526             :                             #sname1, #field1, \
     527             :                             timestring(tctx, s->sname1.field1), \
     528             :                             #sname2, #field2, \
     529             :                             nt_time_string(tctx, v.sname2.out.field2)); \
     530             :                         ret = false; \
     531             :                 } \
     532             :         }} while (0)
     533             : 
     534             : #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
     535             :         s = find(name); \
     536             :         if (s) { \
     537             :                 if (s->sname1.field1 != v.sname2.out.field2) { \
     538             :                         torture_result(tctx, TORTURE_FAIL, \
     539             :                             "(%s) %s/%s [%s] != %s/%s [%s]\n", \
     540             :                             __location__, \
     541             :                             #sname1, #field1, \
     542             :                             nt_time_string(tctx, s->sname1.field1), \
     543             :                             #sname2, #field2, \
     544             :                             nt_time_string(tctx, v.sname2.out.field2)); \
     545             :                         ret = false; \
     546             :                 } \
     547             :         }} while (0)
     548             : 
     549             : #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
     550             :         s = find(name); \
     551             :         if (s) { \
     552             :                 if (!s->sname1.field1 || \
     553             :                     strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
     554             :                         torture_result(tctx, TORTURE_FAIL, \
     555             :                             "(%s) %s/%s [%s] != %s/%s [%s]\n", \
     556             :                             __location__, \
     557             :                             #sname1, #field1, s->sname1.field1, \
     558             :                             #sname2, #field2, v.sname2.out.field2.s); \
     559             :                         ret = false; \
     560             :                 } \
     561             :         }} while (0)
     562             : 
     563             : #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
     564             :         s = find(name); \
     565             :         if (s) { \
     566             :                 if (!s->sname1.field1.s || \
     567             :                     strcmp(s->sname1.field1.s, v.sname2.out.field2.s)) { \
     568             :                         torture_result(tctx, TORTURE_FAIL, \
     569             :                             "(%s) %s/%s [%s] != %s/%s [%s]\n", \
     570             :                             __location__, \
     571             :                             #sname1, #field1, s->sname1.field1.s, \
     572             :                             #sname2, #field2, v.sname2.out.field2.s); \
     573             :                         ret = false; \
     574             :                 } \
     575             :         }} while (0)
     576             : 
     577             : #define CHECK_NAME(name, sname1, field1, fname, flags) do { \
     578             :         s = find(name); \
     579             :         if (s) { \
     580             :                 if (!s->sname1.field1.s || \
     581             :                     strcmp(s->sname1.field1.s, fname)) { \
     582             :                         torture_result(tctx, TORTURE_FAIL, \
     583             :                             "(%s) %s/%s [%s] != %s\n", \
     584             :                             __location__, \
     585             :                             #sname1, #field1, s->sname1.field1.s, fname); \
     586             :                         ret = false; \
     587             :                 } \
     588             :         }} while (0)
     589             : 
     590             : #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
     591             :         s = find(name); \
     592             :         if (s) { \
     593             :                 if (!s->sname1.field1 || \
     594             :                     strcmp(s->sname1.field1, fname)) { \
     595             :                         torture_result(tctx, TORTURE_FAIL, \
     596             :                            "(%s) %s/%s [%s] != %s\n", \
     597             :                             __location__, \
     598             :                             #sname1, #field1, s->sname1.field1, fname); \
     599             :                         ret = false; \
     600             :                 } \
     601             :         }} while (0)
     602             : 
     603             :         /* check that all the results are as expected */
     604           0 :         CHECK_VAL("SMB2_FIND_DIRECTORY_INFO",            directory_info,         attrib, all_info2, all_info2, attrib);
     605           0 :         CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO",       full_directory_info,    attrib, all_info2, all_info2, attrib);
     606           0 :         CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO",       both_directory_info,    attrib, all_info2, all_info2, attrib);
     607           0 :         CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO",    id_full_directory_info, attrib, all_info2, all_info2, attrib);
     608           0 :         CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",    id_both_directory_info, attrib, all_info2, all_info2, attrib);
     609             : 
     610           0 :         CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO",         directory_info,         write_time, all_info2, all_info2, write_time);
     611           0 :         CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO",    full_directory_info,    write_time, all_info2, all_info2, write_time);
     612           0 :         CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO",    both_directory_info,    write_time, all_info2, all_info2, write_time);
     613           0 :         CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info2, all_info2, write_time);
     614           0 :         CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info2, all_info2, write_time);
     615             : 
     616           0 :         CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO",         directory_info,         create_time, all_info2, all_info2, create_time);
     617           0 :         CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO",    full_directory_info,    create_time, all_info2, all_info2, create_time);
     618           0 :         CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO",    both_directory_info,    create_time, all_info2, all_info2, create_time);
     619           0 :         CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info2, all_info2, create_time);
     620           0 :         CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info2, all_info2, create_time);
     621             : 
     622           0 :         CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO",         directory_info,         access_time, all_info2, all_info2, access_time);
     623           0 :         CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO",    full_directory_info,    access_time, all_info2, all_info2, access_time);
     624           0 :         CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO",    both_directory_info,    access_time, all_info2, all_info2, access_time);
     625           0 :         CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info2, all_info2, access_time);
     626           0 :         CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info2, all_info2, access_time);
     627             : 
     628           0 :         CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO",         directory_info,         change_time, all_info2, all_info2, change_time);
     629           0 :         CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO",    full_directory_info,    change_time, all_info2, all_info2, change_time);
     630           0 :         CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO",    both_directory_info,    change_time, all_info2, all_info2, change_time);
     631           0 :         CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info2, all_info2, change_time);
     632           0 :         CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info2, all_info2, change_time);
     633             : 
     634           0 :         CHECK_VAL("SMB2_FIND_DIRECTORY_INFO",            directory_info,         size, all_info2, all_info2, size);
     635           0 :         CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO",       full_directory_info,    size, all_info2, all_info2, size);
     636           0 :         CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO",       both_directory_info,    size, all_info2, all_info2, size);
     637           0 :         CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO",    id_full_directory_info, size, all_info2, all_info2, size);
     638           0 :         CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",    id_both_directory_info, size, all_info2, all_info2, size);
     639             : 
     640           0 :         CHECK_VAL("SMB2_FIND_DIRECTORY_INFO",            directory_info,         alloc_size, all_info2, all_info2, alloc_size);
     641           0 :         CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO",       full_directory_info,    alloc_size, all_info2, all_info2, alloc_size);
     642           0 :         CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO",       both_directory_info,    alloc_size, all_info2, all_info2, alloc_size);
     643           0 :         CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO",    id_full_directory_info, alloc_size, all_info2, all_info2, alloc_size);
     644           0 :         CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",    id_both_directory_info, alloc_size, all_info2, all_info2, alloc_size);
     645             : 
     646           0 :         CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO",       full_directory_info,    ea_size, all_info2, all_info2, ea_size);
     647           0 :         CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO",       both_directory_info,    ea_size, all_info2, all_info2, ea_size);
     648           0 :         CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO",    id_full_directory_info, ea_size, all_info2, all_info2, ea_size);
     649           0 :         CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",    id_both_directory_info, ea_size, all_info2, all_info2, ea_size);
     650             : 
     651           0 :         CHECK_NAME("SMB2_FIND_DIRECTORY_INFO",           directory_info,         name, fname, STR_TERMINATE_ASCII);
     652           0 :         CHECK_NAME("SMB2_FIND_FULL_DIRECTORY_INFO",      full_directory_info,    name, fname, STR_TERMINATE_ASCII);
     653           0 :         CHECK_NAME("SMB2_FIND_NAME_INFO",                name_info,              name, fname, STR_TERMINATE_ASCII);
     654           0 :         CHECK_NAME("SMB2_FIND_BOTH_DIRECTORY_INFO",      both_directory_info,    name, fname, STR_TERMINATE_ASCII);
     655           0 :         CHECK_NAME("SMB2_FIND_ID_FULL_DIRECTORY_INFO",   id_full_directory_info, name, fname, STR_TERMINATE_ASCII);
     656           0 :         CHECK_NAME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",   id_both_directory_info, name, fname, STR_TERMINATE_ASCII);
     657             : 
     658           0 :         CHECK_WSTR("SMB2_FIND_BOTH_DIRECTORY_INFO",      both_directory_info,    short_name, alt_info, alt_name_info, fname, STR_UNICODE);
     659             : 
     660           0 :         CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO",    id_full_directory_info, file_id, internal_info, internal_information, file_id);
     661           0 :         CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO",    id_both_directory_info, file_id, internal_info, internal_information, file_id);
     662             : 
     663           0 : done:
     664           4 :         smb2_util_close(tree, h);
     665           4 :         smb2_util_unlink(tree, fname);
     666           4 :         talloc_free(mem_ctx);
     667             : 
     668           4 :         return ret;
     669             : }
     670             : 
     671             : 
     672             : struct multiple_result {
     673             :         TALLOC_CTX *tctx;
     674             :         int count;
     675             :         union smb_search_data *list;
     676             : };
     677             : 
     678         548 : bool fill_result(void *private_data,
     679             :                  union smb_search_data *file,
     680             :                  int count,
     681             :                  uint8_t level,
     682             :                  enum smb_search_data_level data_level)
     683             : {
     684           0 :         int i;
     685           0 :         const char *sname;
     686         548 :         struct multiple_result *data = (struct multiple_result *)private_data;
     687             : 
     688      460380 :         for (i=0; i<count; i++) {
     689      459832 :                 sname = extract_name(&file[i], level, data_level);
     690      459832 :                 if (!strcmp(sname, ".") || !(strcmp(sname, "..")))
     691         984 :                         continue;
     692      458848 :                 data->count++;
     693      458848 :                 data->list = talloc_realloc(data->tctx,
     694             :                                             data->list,
     695             :                                             union smb_search_data,
     696             :                                             data->count);
     697      458848 :                 data->list[data->count-1] = file[i];
     698             :         }
     699         548 :         return true;
     700             : }
     701             : 
     702             : enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART, CONT_REOPEN};
     703             : 
     704         484 : static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
     705             :                                      TALLOC_CTX *tctx,
     706             :                                      const char *pattern,
     707             :                                      uint8_t level,
     708             :                                      enum smb_search_data_level data_level,
     709             :                                      enum continue_type cont_type,
     710             :                                      void *data,
     711             :                                      struct smb2_handle *h)
     712             : {
     713           0 :         struct smb2_find f;
     714         484 :         bool ret = true;
     715         484 :         unsigned int count = 0;
     716           0 :         union smb_search_data *d;
     717           0 :         NTSTATUS status;
     718         484 :         struct multiple_result *result = (struct multiple_result *)data;
     719             : 
     720         484 :         ZERO_STRUCT(f);
     721         484 :         f.in.file.handle        = *h;
     722         484 :         f.in.pattern            = pattern;
     723         484 :         f.in.max_response_size  = 1024*1024;
     724         484 :         f.in.level              = level;
     725             : 
     726             :         /* The search should start from the beginning every time */
     727         484 :         f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
     728         484 :         if (cont_type == CONT_REOPEN) {
     729          20 :                 f.in.continue_flags = SMB2_CONTINUE_FLAG_REOPEN;
     730             :         }
     731             : 
     732           0 :         do {
     733         968 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
     734         968 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
     735         484 :                         break;
     736         484 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     737         484 :                 if (!fill_result(result, d, count, level, data_level)) {
     738           0 :                         return NT_STATUS_UNSUCCESSFUL;
     739             :                 }
     740             : 
     741         484 :                 if (count == 0 || result == NULL || result->count == 0) {
     742           0 :                         return NT_STATUS_UNSUCCESSFUL;
     743             :                 }
     744             : 
     745             :                 /*
     746             :                  * After the first iteration is complete set the CONTINUE
     747             :                  * FLAGS appropriately
     748             :                  */
     749         484 :                 switch (cont_type) {
     750          20 :                         case CONT_INDEX:
     751          20 :                                 f.in.continue_flags = SMB2_CONTINUE_FLAG_INDEX;
     752           0 :                                 switch (data_level) {
     753           4 :                                         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
     754           4 :                                                 f.in.file_index =
     755           4 :                                                         result->list[result->count-1].both_directory_info.file_index;
     756           4 :                                                 break;
     757           4 :                                         case RAW_SEARCH_DATA_DIRECTORY_INFO:
     758           4 :                                                 f.in.file_index =
     759           4 :                                                         result->list[result->count-1].directory_info.file_index;
     760           4 :                                                 break;
     761           4 :                                         case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
     762           4 :                                                 f.in.file_index =
     763           4 :                                                         result->list[result->count-1].full_directory_info.file_index;
     764           4 :                                                 break;
     765           4 :                                         case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
     766           4 :                                                 f.in.file_index =
     767           4 :                                                         result->list[result->count-1].id_full_directory_info.file_index;
     768           4 :                                                 break;
     769           4 :                                         case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
     770           4 :                                                 f.in.file_index =
     771           4 :                                                         result->list[result->count-1].id_both_directory_info.file_index;
     772           4 :                                                 break;
     773           0 :                                         default:
     774           0 :                                                 return NT_STATUS_INVALID_PARAMETER;
     775             :                                 }
     776          20 :                                 break;
     777          20 :                         case CONT_SINGLE:
     778          20 :                                 f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
     779          20 :                                 break;
     780         444 :                         case CONT_RESTART:
     781             :                         default:
     782             :                                 /* we should prevent staying in the loop
     783             :                                  * forever */
     784         444 :                                 f.in.continue_flags = 0;
     785         444 :                                 break;
     786             :                 }
     787         484 :         } while (count != 0);
     788           0 : done:
     789         484 :         if (!ret) {
     790           0 :                 return status;
     791             :         }
     792         484 :         return status;
     793             : }
     794             : 
     795             : 
     796             : static enum smb_search_data_level compare_data_level;
     797             : uint8_t level_sort;
     798             : 
     799     3937756 : static int search_compare(union smb_search_data *d1,
     800             :                           union smb_search_data *d2)
     801             : {
     802           0 :         const char *s1, *s2;
     803             : 
     804     3937756 :         s1 = extract_name(d1, level_sort, compare_data_level);
     805     3937756 :         s2 = extract_name(d2, level_sort, compare_data_level);
     806     3937756 :         return strcmp_safe(s1, s2);
     807             : }
     808             : 
     809             : /*
     810             :    basic testing of search calls using many files
     811             : */
     812           4 : static bool test_many_files(struct torture_context *tctx,
     813             :                             struct smb2_tree *tree)
     814             : {
     815           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     816           4 :         const int num_files = 700;
     817           0 :         int i, t;
     818           0 :         char *fname;
     819           4 :         bool ret = true;
     820           0 :         NTSTATUS status;
     821           0 :         struct multiple_result result;
     822           0 :         struct smb2_create create;
     823           0 :         struct smb2_handle h;
     824           0 :         struct {
     825             :                 const char *name;
     826             :                 const char *cont_name;
     827             :                 uint8_t level;
     828             :                 enum smb_search_data_level data_level;
     829             :                 enum continue_type cont_type;
     830           4 :         } search_types[] = {
     831             :                 {"SMB2_FIND_BOTH_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_SINGLE},
     832             :                 {"SMB2_FIND_BOTH_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_INDEX},
     833             :                 {"SMB2_FIND_BOTH_DIRECTORY_INFO",    "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_RESTART},
     834             :                 {"SMB2_FIND_BOTH_DIRECTORY_INFO",    "REOPEN",  SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_REOPEN},
     835             :                 {"SMB2_FIND_DIRECTORY_INFO",         "SINGLE",  SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_SINGLE},
     836             :                 {"SMB2_FIND_DIRECTORY_INFO",         "INDEX",   SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_INDEX},
     837             :                 {"SMB2_FIND_DIRECTORY_INFO",         "RESTART", SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_RESTART},
     838             :                 {"SMB2_FIND_DIRECTORY_INFO",         "REOPEN",  SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_REOPEN},
     839             :                 {"SMB2_FIND_FULL_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_SINGLE},
     840             :                 {"SMB2_FIND_FULL_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_INDEX},
     841             :                 {"SMB2_FIND_FULL_DIRECTORY_INFO",    "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_RESTART},
     842             :                 {"SMB2_FIND_FULL_DIRECTORY_INFO",    "REOPEN",  SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_REOPEN},
     843             :                 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_SINGLE},
     844             :                 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_INDEX},
     845             :                 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESTART},
     846             :                 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "REOPEN",  SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_REOPEN},
     847             :                 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_SINGLE},
     848             :                 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_INDEX},
     849             :                 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART},
     850             :                 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "REOPEN",  SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_REOPEN},
     851             :         };
     852             : 
     853           4 :         smb2_deltree(tree, DNAME);
     854           4 :         status = torture_smb2_testdir(tree, DNAME, &h);
     855           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     856             : 
     857           4 :         torture_comment(tctx, "Testing with %d files\n", num_files);
     858           4 :         ZERO_STRUCT(create);
     859           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
     860           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     861           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     862             : 
     863        2804 :         for (i=num_files-1;i>=0;i--) {
     864        2800 :                 fname = talloc_asprintf(mem_ctx, DNAME "\\t%03d-%d.txt", i, i);
     865        2800 :                 create.in.fname = talloc_asprintf(mem_ctx, "%s", fname);
     866        2800 :                 status = smb2_create(tree, mem_ctx, &create);
     867        2800 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     868        2800 :                 smb2_util_close(tree, create.out.file.handle);
     869        2800 :                 talloc_free(fname);
     870             :         }
     871             : 
     872          84 :         for (t=0;t<ARRAY_SIZE(search_types);t++) {
     873          80 :                 ZERO_STRUCT(result);
     874          80 :                 result.tctx = talloc_new(tctx);
     875             : 
     876          80 :                 torture_comment(tctx,
     877             :                                 "Continue %s via %s\n", search_types[t].name,
     878             :                                 search_types[t].cont_name);
     879          80 :                 status = multiple_smb2_search(tree, tctx, "*",
     880          80 :                                               search_types[t].level,
     881             :                                               search_types[t].data_level,
     882             :                                               search_types[t].cont_type,
     883             :                                               &result, &h);
     884             : 
     885          80 :                 torture_assert_int_equal_goto(tctx, result.count, num_files,
     886             :                                               ret, done, "");
     887             : 
     888          80 :                 compare_data_level = search_types[t].data_level;
     889          80 :                 level_sort = search_types[t].level;
     890             : 
     891          80 :                 TYPESAFE_QSORT(result.list, result.count, search_compare);
     892             : 
     893       56080 :                 for (i=0;i<result.count;i++) {
     894           0 :                         const char *s;
     895       56000 :                         s = extract_name(&result.list[i],
     896       56000 :                                          search_types[t].level,
     897             :                                          compare_data_level);
     898       56000 :                         fname = talloc_asprintf(mem_ctx, "t%03d-%d.txt", i, i);
     899       56000 :                         torture_assert_str_equal_goto(tctx, s, fname, ret,
     900             :                                                       done, "Incorrect name");
     901       56000 :                         talloc_free(fname);
     902             :                 }
     903          80 :                 talloc_free(result.tctx);
     904             :         }
     905             : 
     906           4 : done:
     907           4 :         smb2_util_close(tree, h);
     908           4 :         smb2_deltree(tree, DNAME);
     909           4 :         talloc_free(mem_ctx);
     910             : 
     911           4 :         return ret;
     912             : }
     913             : 
     914             : /*
     915             :   check an individual file result
     916             : */
     917           0 : static bool check_result(struct torture_context *tctx,
     918             :                          struct multiple_result *result,
     919             :                          const char *name,
     920             :                          bool exist,
     921             :                          uint32_t attrib)
     922             : {
     923           0 :         int i;
     924           0 :         for (i=0;i<result->count;i++) {
     925           0 :                 if (strcmp(name,
     926           0 :                            result->list[i].both_directory_info.name.s) == 0) {
     927           0 :                         break;
     928             :                 }
     929             :         }
     930           0 :         if (i == result->count) {
     931           0 :                 if (exist) {
     932           0 :                         torture_result(tctx, TORTURE_FAIL,
     933             :                             "failed: '%s' should exist with attribute %s\n",
     934           0 :                             name, attrib_string(result->list, attrib));
     935           0 :                         return false;
     936             :                 }
     937           0 :                 return true;
     938             :         }
     939             : 
     940           0 :         if (!exist) {
     941           0 :                 torture_result(tctx, TORTURE_FAIL,
     942             :                     "failed: '%s' should NOT exist (has attribute %s)\n",
     943           0 :                     name, attrib_string(result->list,
     944           0 :                     result->list[i].both_directory_info.attrib));
     945           0 :                 return false;
     946             :         }
     947             : 
     948           0 :         if ((result->list[i].both_directory_info.attrib&0xFFF) != attrib) {
     949           0 :                 torture_result(tctx, TORTURE_FAIL,
     950             :                     "failed: '%s' should have attribute 0x%x (has 0x%x)\n",
     951           0 :                     name, attrib, result->list[i].both_directory_info.attrib);
     952           0 :                 return false;
     953             :         }
     954           0 :         return true;
     955             : }
     956             : 
     957             : /*
     958             :    test what happens when the directory is modified during a search
     959             : */
     960           4 : static bool test_modify_search(struct torture_context *tctx,
     961             :                                struct smb2_tree *tree)
     962             : {
     963           0 :         struct multiple_result result;
     964           0 :         union smb_setfileinfo sfinfo;
     965           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     966           0 :         struct smb2_create create;
     967           0 :         struct smb2_handle h;
     968           0 :         struct smb2_find f;
     969           0 :         union smb_search_data *d;
     970           4 :         struct file_elem files[703] = {};
     971           4 :         int num_files = ARRAY_SIZE(files)-3;
     972           0 :         NTSTATUS status;
     973           4 :         bool ret = true;
     974           0 :         int i;
     975           0 :         unsigned int count;
     976             : 
     977           4 :         smb2_deltree(tree, DNAME);
     978             : 
     979           4 :         status = torture_smb2_testdir(tree, DNAME, &h);
     980           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     981             : 
     982           4 :         torture_comment(tctx, "Creating %d files\n", num_files);
     983             : 
     984           4 :         ZERO_STRUCT(create);
     985           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
     986           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     987           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
     988             : 
     989        2804 :         for (i = num_files-1; i >= 0; i--) {
     990        2800 :                 files[i].name = talloc_asprintf(mem_ctx, "t%03d-%d.txt", i, i);
     991        2800 :                 create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
     992             :                                                   DNAME, files[i].name);
     993        2800 :                 status = smb2_create(tree, mem_ctx, &create);
     994        2800 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
     995        2800 :                 smb2_util_close(tree, create.out.file.handle);
     996             :         }
     997             : 
     998           4 :         torture_comment(tctx, "pulling the first two files\n");
     999           4 :         ZERO_STRUCT(result);
    1000           4 :         result.tctx = talloc_new(tctx);
    1001             : 
    1002           4 :         ZERO_STRUCT(f);
    1003           4 :         f.in.file.handle        = h;
    1004           4 :         f.in.pattern            = "*";
    1005           4 :         f.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
    1006           4 :         f.in.max_response_size  = 0x100;
    1007           4 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
    1008             : 
    1009           0 :         do {
    1010          16 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
    1011          16 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
    1012           0 :                         break;
    1013          16 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1014          16 :                 if (!fill_result(&result, d, count, f.in.level,
    1015             :                                  RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO)) {
    1016           0 :                         ret = false;
    1017           0 :                         goto done;
    1018             :                 }
    1019          16 :         } while (result.count < 2);
    1020             : 
    1021           4 :         torture_comment(tctx, "Changing attributes and deleting\n");
    1022             : 
    1023           4 :         ZERO_STRUCT(create);
    1024           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1025           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1026           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1027             : 
    1028           4 :         files[num_files].name = talloc_asprintf(mem_ctx, "T003-03.txt.2");
    1029           4 :         create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s", DNAME,
    1030             :                                           files[num_files].name);
    1031           4 :         status = smb2_create(tree, mem_ctx, &create);
    1032           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1033           4 :         smb2_util_close(tree, create.out.file.handle);
    1034             : 
    1035           4 :         ZERO_STRUCT(create);
    1036           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1037           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1038           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1039             : 
    1040           4 :         files[num_files + 1].name = talloc_asprintf(mem_ctx, "T013-13.txt.2");
    1041           8 :         create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s", DNAME,
    1042           4 :                                           files[num_files + 1].name);
    1043           4 :         status = smb2_create(tree, mem_ctx, &create);
    1044           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1045           4 :         smb2_util_close(tree, create.out.file.handle);
    1046             : 
    1047           4 :         files[num_files + 2].name = talloc_asprintf(mem_ctx, "T013-13.txt.3");
    1048           4 :         status = smb2_create_complex_file(tctx, tree, DNAME "\\T013-13.txt.3", &h);
    1049           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1050             : 
    1051           0 :         smb2_util_unlink(tree, DNAME "\\T014-14.txt");
    1052           0 :         smb2_util_setatr(tree, DNAME "\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN);
    1053           0 :         smb2_util_setatr(tree, DNAME "\\T016-16.txt", FILE_ATTRIBUTE_NORMAL);
    1054           0 :         smb2_util_setatr(tree, DNAME "\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM);
    1055           0 :         smb2_util_setatr(tree, DNAME "\\T018-18.txt", 0);
    1056           0 :         smb2_util_setatr(tree, DNAME "\\T039-39.txt", FILE_ATTRIBUTE_HIDDEN);
    1057           0 :         smb2_util_setatr(tree, DNAME "\\T000-0.txt", FILE_ATTRIBUTE_HIDDEN);
    1058           0 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
    1059           0 :         sfinfo.generic.in.file.path = DNAME "\\T013-13.txt.3";
    1060           0 :         sfinfo.disposition_info.in.delete_on_close = 1;
    1061           0 :         status = smb2_composite_setpathinfo(tree, &sfinfo);
    1062           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1063             : 
    1064             :         /* Reset the numfiles to include the new files and start the
    1065             :          * search from the beginning */
    1066           0 :         num_files = num_files + 2;
    1067           0 :         f.in.pattern = "*";
    1068           0 :         f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
    1069           0 :         result.count = 0;
    1070             : 
    1071           0 :         do {
    1072           0 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
    1073           0 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
    1074           0 :                         break;
    1075           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1076           0 :                 if (!fill_result(&result, d, count, f.in.level,
    1077             :                                  RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO)) {
    1078           0 :                         ret = false;
    1079           0 :                         goto done;
    1080             :                 }
    1081           0 :                 f.in.continue_flags = 0;
    1082           0 :                 f.in.max_response_size  = 4096;
    1083           0 :         } while (count != 0);
    1084             : 
    1085             : 
    1086           0 :         ret &= check_result(tctx, &result, "t039-39.txt", true, FILE_ATTRIBUTE_HIDDEN);
    1087           0 :         ret &= check_result(tctx, &result, "t000-0.txt", true, FILE_ATTRIBUTE_HIDDEN);
    1088           0 :         ret &= check_result(tctx, &result, "t014-14.txt", false, 0);
    1089           0 :         ret &= check_result(tctx, &result, "t015-15.txt", true, FILE_ATTRIBUTE_HIDDEN);
    1090           0 :         ret &= check_result(tctx, &result, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL);
    1091           0 :         ret &= check_result(tctx, &result, "t017-17.txt", true, FILE_ATTRIBUTE_SYSTEM);
    1092           0 :         ret &= check_result(tctx, &result, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE);
    1093           0 :         ret &= check_result(tctx, &result, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE);
    1094           0 :         ret &= check_result(tctx, &result, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE);
    1095           0 :         ret &= check_result(tctx, &result, "T003-3.txt.2", false, 0);
    1096           0 :         ret &= check_result(tctx, &result, "T013-13.txt.3", true, FILE_ATTRIBUTE_NORMAL);
    1097             : 
    1098           0 :         if (!ret) {
    1099           0 :                 for (i=0;i<result.count;i++) {
    1100           0 :                         torture_warning(tctx, "%s %s (0x%x)\n",
    1101           0 :                                result.list[i].both_directory_info.name.s,
    1102             :                                attrib_string(tctx,
    1103           0 :                                result.list[i].both_directory_info.attrib),
    1104           0 :                                result.list[i].both_directory_info.attrib);
    1105             :                 }
    1106             :         }
    1107           0 :  done:
    1108           4 :         smb2_util_close(tree, h);
    1109           4 :         smb2_deltree(tree, DNAME);
    1110           4 :         talloc_free(mem_ctx);
    1111             : 
    1112           4 :         return ret;
    1113             : }
    1114             : 
    1115             : /*
    1116             :    testing if directories always come back sorted
    1117             : */
    1118           4 : static bool test_sorted(struct torture_context *tctx,
    1119             :                         struct smb2_tree *tree)
    1120             : {
    1121           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1122           4 :         const int num_files = 700;
    1123           0 :         int i;
    1124           4 :         struct file_elem files[700] = {};
    1125           4 :         bool ret = true;
    1126           0 :         NTSTATUS status;
    1127           0 :         struct multiple_result result;
    1128           0 :         struct smb2_handle h;
    1129             : 
    1130           4 :         torture_comment(tctx, "Testing if directories always come back "
    1131             :            "sorted\n");
    1132           4 :         status = populate_tree(tctx, mem_ctx, tree, files, num_files, &h);
    1133           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1134             : 
    1135           4 :         ZERO_STRUCT(result);
    1136           4 :         result.tctx = tctx;
    1137             : 
    1138           4 :         status = multiple_smb2_search(tree, tctx, "*",
    1139             :                                       SMB2_FIND_BOTH_DIRECTORY_INFO,
    1140             :                                       RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
    1141             :                                       SMB2_CONTINUE_FLAG_SINGLE,
    1142             :                                       &result, &h);
    1143             : 
    1144           4 :         torture_assert_int_equal_goto(tctx, result.count, num_files, ret, done,
    1145             :                                       "");
    1146             : 
    1147          12 :         for (i=0;i<num_files-1;i++) {
    1148           0 :                 const char *name1, *name2;
    1149          12 :                 name1 = result.list[i].both_directory_info.name.s;
    1150          12 :                 name2 = result.list[i+1].both_directory_info.name.s;
    1151          12 :                 if (strcasecmp_m(name1, name2) > 0) {
    1152           4 :                         torture_comment(tctx, "non-alphabetical order at entry "
    1153             :                             "%d '%s' '%s'\n", i, name1, name2);
    1154           4 :                         torture_comment(tctx,
    1155             :                             "Server does not produce sorted directory listings"
    1156             :                             "(not an error)\n");
    1157           4 :                         goto done;
    1158             :                 }
    1159             :         }
    1160           0 :         talloc_free(result.list);
    1161           4 : done:
    1162           4 :         smb2_util_close(tree, h);
    1163           4 :         smb2_deltree(tree, DNAME);
    1164           4 :         talloc_free(mem_ctx);
    1165             : 
    1166           4 :         return ret;
    1167             : }
    1168             : 
    1169             : /* test the behavior of file_index field in the SMB2_FIND struct */
    1170           4 : static bool test_file_index(struct torture_context *tctx,
    1171             :                             struct smb2_tree *tree)
    1172             : {
    1173           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1174           4 :         const int num_files = 100;
    1175           4 :         int resume_index = 4;
    1176           0 :         int i;
    1177           0 :         char *fname;
    1178           4 :         bool ret = true;
    1179           0 :         NTSTATUS status;
    1180           0 :         struct multiple_result result;
    1181           0 :         struct smb2_create create;
    1182           0 :         struct smb2_find f;
    1183           0 :         struct smb2_handle h;
    1184           0 :         union smb_search_data *d;
    1185           0 :         unsigned count;
    1186             : 
    1187           4 :         smb2_deltree(tree, DNAME);
    1188             : 
    1189           4 :         status = torture_smb2_testdir(tree, DNAME, &h);
    1190           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1191             : 
    1192           4 :         torture_comment(tctx, "Testing the behavior of file_index flag\n");
    1193             : 
    1194           4 :         ZERO_STRUCT(create);
    1195           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1196           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1197           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1198         404 :         for (i = num_files-1; i >= 0; i--) {
    1199         400 :                 fname = talloc_asprintf(mem_ctx, DNAME "\\file%u.txt", i);
    1200         400 :                 create.in.fname = fname;
    1201         400 :                 status = smb2_create(tree, mem_ctx, &create);
    1202         400 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1203         400 :                 talloc_free(fname);
    1204         400 :                 smb2_util_close(tree, create.out.file.handle);
    1205             :         }
    1206             : 
    1207           4 :         ZERO_STRUCT(result);
    1208           4 :         result.tctx = tctx;
    1209             : 
    1210           4 :         ZERO_STRUCT(f);
    1211           4 :         f.in.file.handle        = h;
    1212           4 :         f.in.pattern            = "*";
    1213           4 :         f.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE;
    1214           4 :         f.in.max_response_size  = 0x1000;
    1215           4 :         f.in.level              = SMB2_FIND_FULL_DIRECTORY_INFO;
    1216             : 
    1217           0 :         do {
    1218          48 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
    1219          48 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
    1220           0 :                         break;
    1221          48 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1222          48 :                 if (!fill_result(&result, d, count, f.in.level,
    1223             :                                  RAW_SEARCH_DATA_FULL_DIRECTORY_INFO)) {
    1224           0 :                         ret = false;
    1225           0 :                         goto done;
    1226             :                 }
    1227          48 :         } while(result.count < 10);
    1228             : 
    1229           4 :         if (result.list[0].full_directory_info.file_index == 0) {
    1230           4 :                 torture_skip_goto(tctx, done,
    1231             :                                 "Talking to a server that doesn't provide a "
    1232             :                                 "file index.\nWindows servers using NTFS do "
    1233             :                                 "not provide a file_index. Skipping test\n");
    1234             :         } else {
    1235             :                 /* We are not talking to a Windows based server.  Windows
    1236             :                  * servers using NTFS do not provide a file_index.  Windows
    1237             :                  * servers using FAT do provide a file index, however in both
    1238             :                  * cases they do not honor a file index on a resume request.
    1239             :                  * See MS-FSCC <62> and MS-SMB2 <54> for more information. */
    1240             : 
    1241             :                 /* Set the file_index flag to point to the fifth file from the
    1242             :                  * previous enumeration and try to start the subsequent
    1243             :                  * searches from that point */
    1244           0 :                 f.in.file_index =
    1245           0 :                     result.list[resume_index].full_directory_info.file_index;
    1246           0 :                 f.in.continue_flags = SMB2_CONTINUE_FLAG_INDEX;
    1247             : 
    1248             :                 /* get the name of the next expected file */
    1249           0 :                 fname = talloc_asprintf(mem_ctx, DNAME "\\%s",
    1250           0 :                         result.list[resume_index].full_directory_info.name.s);
    1251             : 
    1252           0 :                 ZERO_STRUCT(result);
    1253           0 :                 result.tctx = tctx;
    1254           0 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
    1255           0 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
    1256           0 :                         goto done;
    1257           0 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1258           0 :                 if (!fill_result(&result, d, count, f.in.level,
    1259             :                                  RAW_SEARCH_DATA_FULL_DIRECTORY_INFO)) {
    1260           0 :                         ret = false;
    1261           0 :                         goto done;
    1262             :                 }
    1263           0 :                 if (strcmp(fname,
    1264           0 :                         result.list[0].full_directory_info.name.s)) {
    1265           0 :                         torture_comment(tctx, "Next expected file: %s but the "
    1266             :                             "server returned %s\n", fname,
    1267           0 :                             result.list[0].full_directory_info.name.s);
    1268           0 :                         torture_comment(tctx,
    1269             :                                         "Not an error. Resuming using a file "
    1270             :                                         "index is an optional feature of the "
    1271             :                                         "protocol.\n");
    1272           0 :                         goto done;
    1273             :                 }
    1274             :         }
    1275           0 : done:
    1276           4 :         smb2_util_close(tree, h);
    1277           4 :         smb2_deltree(tree, DNAME);
    1278           4 :         talloc_free(mem_ctx);
    1279             : 
    1280           4 :         return ret;
    1281             : }
    1282             : 
    1283             : /*
    1284             :  * Tests directory enumeration in a directory containing >1000 files with
    1285             :  * names of varying lengths.
    1286             :  */
    1287           4 : static bool test_large_files(struct torture_context *tctx,
    1288             :                              struct smb2_tree *tree)
    1289             : {
    1290           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1291           4 :         const int num_files = 2000;
    1292           4 :         int max_len = 200;
    1293             :         /* These should be evenly divisible */
    1294           4 :         int num_at_len = num_files / max_len;
    1295           4 :         struct file_elem files[2000] = {};
    1296           4 :         size_t len = 1;
    1297           4 :         bool ret = true;
    1298           0 :         NTSTATUS status;
    1299           0 :         struct smb2_create create;
    1300           0 :         struct smb2_find f;
    1301           4 :         struct smb2_handle h = {{0}};
    1302           0 :         union smb_search_data *d;
    1303           4 :         int i, j = 0, file_count = 0;
    1304           4 :         char **strs = NULL;
    1305           0 :         unsigned count;
    1306           0 :         struct timespec ts1, ts2;
    1307             : 
    1308           4 :         torture_comment(tctx,
    1309             :             "Testing directory enumeration in a directory with >1000 files\n");
    1310             : 
    1311           4 :         smb2_deltree(tree, DNAME);
    1312             : 
    1313           4 :         ZERO_STRUCT(create);
    1314           4 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    1315           4 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1316           4 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
    1317           4 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1318             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
    1319             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
    1320           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1321           4 :         create.in.fname = DNAME;
    1322             : 
    1323           4 :         status = smb2_create(tree, mem_ctx, &create);
    1324           4 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1325           4 :         h = create.out.file.handle;
    1326             : 
    1327           4 :         ZERO_STRUCT(create);
    1328           4 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1329           4 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1330           4 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1331             : 
    1332        8004 :         for (i = 0; i < num_files; i++) {
    1333        8000 :                 if (i % num_at_len == 0) {
    1334         800 :                     strs = generate_unique_strs(mem_ctx, len, num_at_len);
    1335         800 :                     len++;
    1336             :                 }
    1337        8000 :                 files[i].name = strs[i % num_at_len];
    1338        8000 :                 create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
    1339             :                     DNAME, files[i].name);
    1340        8000 :                 status = smb2_create(tree, mem_ctx, &create);
    1341        8000 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1342        8000 :                 smb2_util_close(tree, create.out.file.handle);
    1343             :         }
    1344             : 
    1345           4 :         ZERO_STRUCT(f);
    1346           4 :         f.in.file.handle        = h;
    1347           4 :         f.in.pattern            = "*";
    1348           4 :         f.in.max_response_size  = 0x100;
    1349           4 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
    1350             : 
    1351           4 :         clock_gettime_mono(&ts1);
    1352             : 
    1353           0 :         do {
    1354         620 :                 status = smb2_find_level(tree, tree, &f, &count, &d);
    1355         620 :                 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
    1356           4 :                         break;
    1357         616 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    1358             : 
    1359        8624 :                 for (i = 0; i < count; i++) {
    1360           0 :                         bool expected;
    1361        8008 :                         const char *found = d[i].both_directory_info.name.s;
    1362             : 
    1363        8008 :                         if (!strcmp(found, ".") || !strcmp(found, ".."))
    1364           8 :                                 continue;
    1365             : 
    1366        8000 :                         expected = false;
    1367     8004000 :                         for (j = 0; j < 2000; j++) {
    1368     8004000 :                                 if (!strcmp(files[j].name, found)) {
    1369        8000 :                                         files[j].found = true;
    1370        8000 :                                         expected = true;
    1371        8000 :                                         break;
    1372             :                                 }
    1373             :                         }
    1374             : 
    1375        8000 :                         if (expected)
    1376        8000 :                                 continue;
    1377             : 
    1378           0 :                         torture_result(tctx, TORTURE_FAIL,
    1379             :                             "(%s): didn't expect %s\n",
    1380             :                             __location__, found);
    1381           0 :                         ret = false;
    1382           0 :                         goto done;
    1383             :                 }
    1384         616 :                 file_count = file_count + i;
    1385         616 :                 f.in.continue_flags = 0;
    1386         616 :                 f.in.max_response_size  = 4096;
    1387         616 :         } while (count != 0);
    1388             : 
    1389           4 :         torture_assert_int_equal_goto(tctx, file_count, num_files + 2, ret,
    1390             :                                       done, "");
    1391             : 
    1392           4 :         clock_gettime_mono(&ts2);
    1393             : 
    1394        8004 :         for (i = 0; i < num_files; i++) {
    1395        8000 :                 if (files[j].found)
    1396        8000 :                         continue;
    1397             : 
    1398           0 :                 torture_result(tctx, TORTURE_FAIL,
    1399             :                     "(%s): expected to find %s, but didn't\n",
    1400             :                     __location__, files[j].name);
    1401           0 :                 ret = false;
    1402           0 :                 goto done;
    1403             :         }
    1404             : 
    1405           4 :         torture_comment(tctx, "Directory enumeration completed in %.3f s.\n",
    1406             :                         timespec_elapsed2(&ts1, &ts2));
    1407             : 
    1408           4 : done:
    1409           4 :         smb2_util_close(tree, h);
    1410           4 :         smb2_deltree(tree, DNAME);
    1411           4 :         talloc_free(mem_ctx);
    1412             : 
    1413           4 :         return ret;
    1414             : }
    1415             : 
    1416             : /*
    1417             :  * basic testing of search calls using many files,
    1418             :  * including renaming files
    1419             :  */
    1420             : #define NUM_FILES 1000
    1421           4 : static bool test_1k_files_rename(struct torture_context *tctx,
    1422             :                             struct smb2_tree *tree)
    1423             : {
    1424           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1425           4 :         const int num_files = NUM_FILES;
    1426           4 :         int rename_index = 0;
    1427           0 :         int i, j;
    1428           4 :         char *fname_list[NUM_FILES] = {0};
    1429           4 :         bool ret = true;
    1430           0 :         NTSTATUS status;
    1431           0 :         struct multiple_result result;
    1432           0 :         struct smb2_create create;
    1433           0 :         struct smb2_create dir;
    1434           0 :         struct smb2_handle dir_handle;
    1435           0 :         struct smb2_create open;
    1436           0 :         union smb_setfileinfo sinfo;
    1437           0 :         struct timespec ts1, ts2;
    1438           0 :         bool reopen;
    1439             : 
    1440           4 :         reopen = torture_setting_bool(tctx, "1k_files_rename_reopendir", false);
    1441             : 
    1442           4 :         torture_comment(tctx, "Testing with %d files\n", num_files);
    1443             : 
    1444           4 :         smb2_deltree(tree, DNAME);
    1445             : 
    1446           4 :         dir = (struct smb2_create) {
    1447             :                 .in.desired_access = SEC_DIR_LIST,
    1448             :                 .in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY,
    1449             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
    1450             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
    1451             :                 .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
    1452             :                 .in.fname = DNAME,
    1453             :         };
    1454             : 
    1455           4 :         status = smb2_create(tree, tree, &dir);
    1456           4 :         torture_assert_ntstatus_ok(tctx, status,
    1457             :                                    "Could not create test directory");
    1458             : 
    1459           4 :         dir_handle = dir.out.file.handle;
    1460             : 
    1461             :         /* Create 1k files, store in array for later rename */
    1462             : 
    1463           4 :         torture_comment(tctx, "Create files.\n");
    1464           4 :         create = (struct smb2_create) {
    1465             :                 .in.desired_access = SEC_RIGHTS_FILE_ALL,
    1466             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
    1467             :                 .in.create_disposition = NTCREATEX_DISP_CREATE,
    1468             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
    1469             :         };
    1470             : 
    1471        4004 :         for (i = num_files - 1; i >= 0; i--) {
    1472        4000 :                 fname_list[i] = talloc_asprintf(mem_ctx, DNAME "\\t%03d.txt", i);
    1473        4000 :                 torture_assert_not_null_goto(tctx, fname_list[i], ret, done,
    1474             :                                              "talloc_asprintf failed");
    1475             : 
    1476        4000 :                 create.in.fname = fname_list[i];
    1477             : 
    1478        4000 :                 status = smb2_create(tree, mem_ctx, &create);
    1479        4000 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1480             :                                                 "smb2_create failed\n");
    1481             : 
    1482        4000 :                 status = smb2_util_close(tree, create.out.file.handle);
    1483        4000 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1484             :                                                 "smb2_util_close failed\n");
    1485             :         }
    1486             : 
    1487           4 :         open = (struct smb2_create) {
    1488             :                 .in.desired_access = SEC_RIGHTS_FILE_ALL | SEC_STD_DELETE,
    1489             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
    1490             :                 .in.create_disposition = NTCREATEX_DISP_OPEN,
    1491             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
    1492             :         };
    1493             : 
    1494           4 :         clock_gettime_mono(&ts1);
    1495             : 
    1496         404 :         for (j = 0; j < 100; j++) {
    1497         400 :                 ZERO_STRUCT(result);
    1498         400 :                 result.tctx = talloc_new(tctx);
    1499             : 
    1500         400 :                 torture_comment(tctx, "Iteration: %02d of 100.\n", j);
    1501             : 
    1502         400 :                 if (reopen) {
    1503           0 :                         torture_comment(
    1504             :                                 tctx, "Close and reopen test directory \n");
    1505           0 :                         smb2_util_close(tree, dir_handle);
    1506             : 
    1507           0 :                         status = smb2_create(tree, tree, &dir);
    1508           0 :                         torture_assert_ntstatus_ok_goto(
    1509             :                                 tctx, status, ret, done,
    1510             :                                 "Could not reopen test directory");
    1511             : 
    1512           0 :                         dir_handle = dir.out.file.handle;
    1513             :                 }
    1514             : 
    1515         400 :                 status = multiple_smb2_search(tree, tctx, "*",
    1516             :                                 SMB2_FIND_FULL_DIRECTORY_INFO,
    1517             :                                 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
    1518             :                                 100,
    1519             :                                 &result, &dir_handle);
    1520         400 :                 torture_assert_int_equal_goto(tctx, result.count, num_files,
    1521             :                                 ret, done, "Wrong number of files");
    1522             : 
    1523             :                 /* Check name validity of all files*/
    1524         400 :                 compare_data_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO;
    1525         400 :                 level_sort = SMB2_FIND_FULL_DIRECTORY_INFO;
    1526             : 
    1527         400 :                 TYPESAFE_QSORT(result.list, result.count, search_compare);
    1528             : 
    1529      400400 :                 for (i = 0; i < result.count; i++) {
    1530      400000 :                         const char *s = NULL;
    1531      400000 :                         char *dname_s = NULL;
    1532             : 
    1533      400000 :                         s = extract_name(&result.list[i],
    1534             :                                         SMB2_FIND_FULL_DIRECTORY_INFO,
    1535             :                                         RAW_SEARCH_DATA_FULL_DIRECTORY_INFO);
    1536      400000 :                         dname_s = talloc_asprintf(mem_ctx, DNAME "\\%s", s);
    1537      400000 :                         torture_assert_not_null_goto(tctx, dname_s, ret, done,
    1538             :                                                      "talloc_asprintf failed");
    1539             : 
    1540      400000 :                         torture_assert_str_equal_goto(tctx, dname_s, fname_list[i], ret,
    1541             :                                         done, "Incorrect name\n");
    1542      400000 :                         TALLOC_FREE(dname_s);
    1543             :                 }
    1544             : 
    1545         400 :                 TALLOC_FREE(result.tctx);
    1546             : 
    1547             :                 /* Rename one file */
    1548         400 :                 open.in.fname = fname_list[rename_index];
    1549             : 
    1550         400 :                 status = smb2_create(tree, tctx, &open);
    1551         400 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1552             :                                                 "Failed open\n");
    1553             : 
    1554         400 :                 sinfo = (union smb_setfileinfo) {
    1555             :                         .rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION,
    1556             :                         .rename_information.in.file.handle = open.out.file.handle,
    1557             :                 };
    1558             : 
    1559         400 :                 TALLOC_FREE(fname_list[rename_index]);
    1560         400 :                 fname_list[rename_index] = talloc_asprintf(
    1561             :                         mem_ctx, DNAME "\\t%03d-rename.txt", rename_index);
    1562         400 :                 sinfo.rename_information.in.new_name = fname_list[rename_index];
    1563             : 
    1564         400 :                 torture_comment(tctx, "Renaming test file to: %s\n",
    1565             :                                 sinfo.rename_information.in.new_name);
    1566             : 
    1567         400 :                 status = smb2_setinfo_file(tree, &sinfo);
    1568         400 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1569             :                                                 "Failed setinfo/rename\n");
    1570             : 
    1571         400 :                 rename_index++;
    1572         400 :                 smb2_util_close(tree, open.out.file.handle);
    1573             :         }
    1574             : 
    1575           4 :         clock_gettime_mono(&ts2);
    1576             : 
    1577           4 :         torture_comment(tctx, "\nDirectory enumeration completed in %.3f s.\n",
    1578             :                         timespec_elapsed2(&ts1, &ts2));
    1579             : 
    1580           4 : done:
    1581           4 :         TALLOC_FREE(mem_ctx);
    1582           4 :         smb2_util_close(tree, dir_handle);
    1583           4 :         smb2_deltree(tree, DNAME);
    1584           4 :         return ret;
    1585             : }
    1586             : #undef NUM_FILES
    1587             : 
    1588        2354 : struct torture_suite *torture_smb2_dir_init(TALLOC_CTX *ctx)
    1589             : {
    1590         125 :         struct torture_suite *suite =
    1591        2354 :             torture_suite_create(ctx, "dir");
    1592             : 
    1593        2354 :         torture_suite_add_1smb2_test(suite, "find", test_find);
    1594        2354 :         torture_suite_add_1smb2_test(suite, "fixed", test_fixed);
    1595        2354 :         torture_suite_add_1smb2_test(suite, "one", test_one_file);
    1596        2354 :         torture_suite_add_1smb2_test(suite, "many", test_many_files);
    1597        2354 :         torture_suite_add_1smb2_test(suite, "modify", test_modify_search);
    1598        2354 :         torture_suite_add_1smb2_test(suite, "sorted", test_sorted);
    1599        2354 :         torture_suite_add_1smb2_test(suite, "file-index", test_file_index);
    1600        2354 :         torture_suite_add_1smb2_test(suite, "large-files", test_large_files);
    1601        2354 :         torture_suite_add_1smb2_test(suite, "1kfiles_rename", test_1k_files_rename);
    1602             : 
    1603        2354 :         suite->description = talloc_strdup(suite, "SMB2-DIR tests");
    1604             : 
    1605        2354 :         return suite;
    1606             : }

Generated by: LCOV version 1.14