| 1 | /* 
 | 
|---|
| 2 |    Unix SMB/CIFS implementation.
 | 
|---|
| 3 |    RAW_SEARCH_* individual test suite
 | 
|---|
| 4 |    Copyright (C) Andrew Tridgell 2003
 | 
|---|
| 5 |    
 | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify
 | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by
 | 
|---|
| 8 |    the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 9 |    (at your option) any later version.
 | 
|---|
| 10 |    
 | 
|---|
| 11 |    This program is distributed in the hope that it will be useful,
 | 
|---|
| 12 |    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 13 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 14 |    GNU General Public License for more details.
 | 
|---|
| 15 |    
 | 
|---|
| 16 |    You should have received a copy of the GNU General Public License
 | 
|---|
| 17 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 18 | */
 | 
|---|
| 19 | 
 | 
|---|
| 20 | #include "includes.h"
 | 
|---|
| 21 | #include "torture/torture.h"
 | 
|---|
| 22 | #include "system/filesys.h"
 | 
|---|
| 23 | #include "libcli/raw/libcliraw.h"
 | 
|---|
| 24 | #include "libcli/raw/raw_proto.h"
 | 
|---|
| 25 | #include "libcli/libcli.h"
 | 
|---|
| 26 | #include "torture/util.h"
 | 
|---|
| 27 | 
 | 
|---|
| 28 | 
 | 
|---|
| 29 | #define BASEDIR "\\testsearch"
 | 
|---|
| 30 | 
 | 
|---|
| 31 | /*
 | 
|---|
| 32 |   callback function for single_search
 | 
|---|
| 33 | */
 | 
|---|
| 34 | static bool single_search_callback(void *private_data, const union smb_search_data *file)
 | 
|---|
| 35 | {
 | 
|---|
| 36 |         union smb_search_data *data = (union smb_search_data *)private_data;
 | 
|---|
| 37 | 
 | 
|---|
| 38 |         *data = *file;
 | 
|---|
| 39 | 
 | 
|---|
| 40 |         return true;
 | 
|---|
| 41 | }
 | 
|---|
| 42 | 
 | 
|---|
| 43 | /*
 | 
|---|
| 44 |   do a single file (non-wildcard) search 
 | 
|---|
| 45 | */
 | 
|---|
| 46 | NTSTATUS torture_single_search(struct smbcli_state *cli, 
 | 
|---|
| 47 |                                TALLOC_CTX *tctx,
 | 
|---|
| 48 |                                const char *pattern,
 | 
|---|
| 49 |                                enum smb_search_level level,
 | 
|---|
| 50 |                                enum smb_search_data_level data_level,
 | 
|---|
| 51 |                                uint16_t attrib,
 | 
|---|
| 52 |                                union smb_search_data *data)
 | 
|---|
| 53 | {
 | 
|---|
| 54 |         union smb_search_first io;
 | 
|---|
| 55 |         union smb_search_close c;
 | 
|---|
| 56 |         NTSTATUS status;
 | 
|---|
| 57 | 
 | 
|---|
| 58 |         switch (level) {
 | 
|---|
| 59 |         case RAW_SEARCH_SEARCH:
 | 
|---|
| 60 |         case RAW_SEARCH_FFIRST:
 | 
|---|
| 61 |         case RAW_SEARCH_FUNIQUE:
 | 
|---|
| 62 |                 io.search_first.level = level;
 | 
|---|
| 63 |                 io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 64 |                 io.search_first.in.max_count = 1;
 | 
|---|
| 65 |                 io.search_first.in.search_attrib = attrib;
 | 
|---|
| 66 |                 io.search_first.in.pattern = pattern;
 | 
|---|
| 67 |                 break;
 | 
|---|
| 68 | 
 | 
|---|
| 69 |         case RAW_SEARCH_TRANS2:
 | 
|---|
| 70 |                 io.t2ffirst.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 71 |                 io.t2ffirst.data_level = data_level;
 | 
|---|
| 72 |                 io.t2ffirst.in.search_attrib = attrib;
 | 
|---|
| 73 |                 io.t2ffirst.in.max_count = 1;
 | 
|---|
| 74 |                 io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
 | 
|---|
| 75 |                 io.t2ffirst.in.storage_type = 0;
 | 
|---|
| 76 |                 io.t2ffirst.in.pattern = pattern;
 | 
|---|
| 77 |                 break;
 | 
|---|
| 78 | 
 | 
|---|
| 79 |         case RAW_SEARCH_SMB2:
 | 
|---|
| 80 |                 return NT_STATUS_INVALID_LEVEL;
 | 
|---|
| 81 |         }
 | 
|---|
| 82 | 
 | 
|---|
| 83 |         status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 84 |                                       &io, (void *)data, single_search_callback);
 | 
|---|
| 85 | 
 | 
|---|
| 86 |         if (NT_STATUS_IS_OK(status) && level == RAW_SEARCH_FFIRST) {
 | 
|---|
| 87 |                 c.fclose.level = RAW_FINDCLOSE_FCLOSE;
 | 
|---|
| 88 |                 c.fclose.in.max_count = 1;
 | 
|---|
| 89 |                 c.fclose.in.search_attrib = 0;
 | 
|---|
| 90 |                 c.fclose.in.id = data->search.id;
 | 
|---|
| 91 |                 status = smb_raw_search_close(cli->tree, &c);
 | 
|---|
| 92 |         }
 | 
|---|
| 93 |         
 | 
|---|
| 94 |         return status;
 | 
|---|
| 95 | }
 | 
|---|
| 96 | 
 | 
|---|
| 97 | 
 | 
|---|
| 98 | static struct {
 | 
|---|
| 99 |         const char *name;
 | 
|---|
| 100 |         enum smb_search_level level;
 | 
|---|
| 101 |         enum smb_search_data_level data_level;
 | 
|---|
| 102 |         int name_offset;
 | 
|---|
| 103 |         int resume_key_offset;
 | 
|---|
| 104 |         uint32_t capability_mask;
 | 
|---|
| 105 |         NTSTATUS status;
 | 
|---|
| 106 |         union smb_search_data data;
 | 
|---|
| 107 | } levels[] = {
 | 
|---|
| 108 |         {"FFIRST",
 | 
|---|
| 109 |          RAW_SEARCH_FFIRST, RAW_SEARCH_DATA_SEARCH,
 | 
|---|
| 110 |          offsetof(union smb_search_data, search.name),
 | 
|---|
| 111 |          -1,
 | 
|---|
| 112 |         },
 | 
|---|
| 113 |         {"FUNIQUE",
 | 
|---|
| 114 |          RAW_SEARCH_FUNIQUE, RAW_SEARCH_DATA_SEARCH,
 | 
|---|
| 115 |          offsetof(union smb_search_data, search.name),
 | 
|---|
| 116 |          -1,
 | 
|---|
| 117 |         },
 | 
|---|
| 118 |         {"SEARCH",
 | 
|---|
| 119 |          RAW_SEARCH_SEARCH, RAW_SEARCH_DATA_SEARCH,
 | 
|---|
| 120 |          offsetof(union smb_search_data, search.name),
 | 
|---|
| 121 |          -1,
 | 
|---|
| 122 |         },
 | 
|---|
| 123 |         {"STANDARD",
 | 
|---|
| 124 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_STANDARD, 
 | 
|---|
| 125 |          offsetof(union smb_search_data, standard.name.s),
 | 
|---|
| 126 |          offsetof(union smb_search_data, standard.resume_key),
 | 
|---|
| 127 |         },
 | 
|---|
| 128 |         {"EA_SIZE",
 | 
|---|
| 129 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_EA_SIZE, 
 | 
|---|
| 130 |          offsetof(union smb_search_data, ea_size.name.s),
 | 
|---|
| 131 |          offsetof(union smb_search_data, ea_size.resume_key),
 | 
|---|
| 132 |         },
 | 
|---|
| 133 |         {"DIRECTORY_INFO",
 | 
|---|
| 134 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_DIRECTORY_INFO, 
 | 
|---|
| 135 |          offsetof(union smb_search_data, directory_info.name.s),
 | 
|---|
| 136 |          offsetof(union smb_search_data, directory_info.file_index),
 | 
|---|
| 137 |         },
 | 
|---|
| 138 |         {"FULL_DIRECTORY_INFO",
 | 
|---|
| 139 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, 
 | 
|---|
| 140 |          offsetof(union smb_search_data, full_directory_info.name.s),
 | 
|---|
| 141 |          offsetof(union smb_search_data, full_directory_info.file_index),
 | 
|---|
| 142 |         },
 | 
|---|
| 143 |         {"NAME_INFO",
 | 
|---|
| 144 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_NAME_INFO, 
 | 
|---|
| 145 |          offsetof(union smb_search_data, name_info.name.s),
 | 
|---|
| 146 |          offsetof(union smb_search_data, name_info.file_index),
 | 
|---|
| 147 |         },
 | 
|---|
| 148 |         {"BOTH_DIRECTORY_INFO",
 | 
|---|
| 149 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, 
 | 
|---|
| 150 |          offsetof(union smb_search_data, both_directory_info.name.s),
 | 
|---|
| 151 |          offsetof(union smb_search_data, both_directory_info.file_index),
 | 
|---|
| 152 |         },
 | 
|---|
| 153 |         {"ID_FULL_DIRECTORY_INFO",
 | 
|---|
| 154 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, 
 | 
|---|
| 155 |          offsetof(union smb_search_data, id_full_directory_info.name.s),
 | 
|---|
| 156 |          offsetof(union smb_search_data, id_full_directory_info.file_index),
 | 
|---|
| 157 |         },
 | 
|---|
| 158 |         {"ID_BOTH_DIRECTORY_INFO",
 | 
|---|
| 159 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, 
 | 
|---|
| 160 |          offsetof(union smb_search_data, id_both_directory_info.name.s),
 | 
|---|
| 161 |          offsetof(union smb_search_data, id_both_directory_info.file_index),
 | 
|---|
| 162 |         },
 | 
|---|
| 163 |         {"UNIX_INFO",
 | 
|---|
| 164 |          RAW_SEARCH_TRANS2, RAW_SEARCH_DATA_UNIX_INFO, 
 | 
|---|
| 165 |          offsetof(union smb_search_data, unix_info.name),
 | 
|---|
| 166 |          offsetof(union smb_search_data, unix_info.file_index),
 | 
|---|
| 167 |          CAP_UNIX}
 | 
|---|
| 168 | };
 | 
|---|
| 169 | 
 | 
|---|
| 170 | 
 | 
|---|
| 171 | /*
 | 
|---|
| 172 |   return level name
 | 
|---|
| 173 | */
 | 
|---|
| 174 | static const char *level_name(enum smb_search_level level,
 | 
|---|
| 175 |                               enum smb_search_data_level data_level)
 | 
|---|
| 176 | {
 | 
|---|
| 177 |         int i;
 | 
|---|
| 178 |         for (i=0;i<ARRAY_SIZE(levels);i++) {
 | 
|---|
| 179 |                 if (level == levels[i].level &&
 | 
|---|
| 180 |                     data_level == levels[i].data_level) {
 | 
|---|
| 181 |                         return levels[i].name;
 | 
|---|
| 182 |                 }
 | 
|---|
| 183 |         }
 | 
|---|
| 184 |         return NULL;
 | 
|---|
| 185 | }
 | 
|---|
| 186 | 
 | 
|---|
| 187 | /*
 | 
|---|
| 188 |   extract the name from a smb_data structure and level
 | 
|---|
| 189 | */
 | 
|---|
| 190 | static const char *extract_name(void *data, enum smb_search_level level,
 | 
|---|
| 191 |                                 enum smb_search_data_level data_level)
 | 
|---|
| 192 | {
 | 
|---|
| 193 |         int i;
 | 
|---|
| 194 |         for (i=0;i<ARRAY_SIZE(levels);i++) {
 | 
|---|
| 195 |                 if (level == levels[i].level &&
 | 
|---|
| 196 |                     data_level == levels[i].data_level) {
 | 
|---|
| 197 |                         return *(const char **)(levels[i].name_offset + (char *)data);
 | 
|---|
| 198 |                 }
 | 
|---|
| 199 |         }
 | 
|---|
| 200 |         return NULL;
 | 
|---|
| 201 | }
 | 
|---|
| 202 | 
 | 
|---|
| 203 | /*
 | 
|---|
| 204 |   extract the name from a smb_data structure and level
 | 
|---|
| 205 | */
 | 
|---|
| 206 | static uint32_t extract_resume_key(void *data, enum smb_search_level level,
 | 
|---|
| 207 |                                    enum smb_search_data_level data_level)
 | 
|---|
| 208 | {
 | 
|---|
| 209 |         int i;
 | 
|---|
| 210 |         for (i=0;i<ARRAY_SIZE(levels);i++) {
 | 
|---|
| 211 |                 if (level == levels[i].level &&
 | 
|---|
| 212 |                     data_level == levels[i].data_level) {
 | 
|---|
| 213 |                         return *(uint32_t *)(levels[i].resume_key_offset + (char *)data);
 | 
|---|
| 214 |                 }
 | 
|---|
| 215 |         }
 | 
|---|
| 216 |         return 0;
 | 
|---|
| 217 | }
 | 
|---|
| 218 | 
 | 
|---|
| 219 | /* find a level in the table by name */
 | 
|---|
| 220 | static union smb_search_data *find(const char *name)
 | 
|---|
| 221 | {
 | 
|---|
| 222 |         int i;
 | 
|---|
| 223 |         for (i=0;i<ARRAY_SIZE(levels);i++) {
 | 
|---|
| 224 |                 if (NT_STATUS_IS_OK(levels[i].status) && 
 | 
|---|
| 225 |                     strcmp(levels[i].name, name) == 0) {
 | 
|---|
| 226 |                         return &levels[i].data;
 | 
|---|
| 227 |                 }
 | 
|---|
| 228 |         }
 | 
|---|
| 229 |         return NULL;
 | 
|---|
| 230 | }
 | 
|---|
| 231 | 
 | 
|---|
| 232 | /* 
 | 
|---|
| 233 |    basic testing of all RAW_SEARCH_* calls using a single file
 | 
|---|
| 234 | */
 | 
|---|
| 235 | static bool test_one_file(struct torture_context *tctx, 
 | 
|---|
| 236 |                           struct smbcli_state *cli)
 | 
|---|
| 237 | {
 | 
|---|
| 238 |         bool ret = true;
 | 
|---|
| 239 |         int fnum;
 | 
|---|
| 240 |         const char *fname = "\\torture_search.txt";
 | 
|---|
| 241 |         const char *fname2 = "\\torture_search-NOTEXIST.txt";
 | 
|---|
| 242 |         NTSTATUS status;
 | 
|---|
| 243 |         int i;
 | 
|---|
| 244 |         union smb_fileinfo all_info, alt_info, name_info, internal_info;
 | 
|---|
| 245 |         union smb_search_data *s;
 | 
|---|
| 246 | 
 | 
|---|
| 247 |         fnum = create_complex_file(cli, tctx, fname);
 | 
|---|
| 248 |         if (fnum == -1) {
 | 
|---|
| 249 |                 printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
 | 
|---|
| 250 |                 ret = false;
 | 
|---|
| 251 |                 goto done;
 | 
|---|
| 252 |         }
 | 
|---|
| 253 | 
 | 
|---|
| 254 |         /* call all the levels */
 | 
|---|
| 255 |         for (i=0;i<ARRAY_SIZE(levels);i++) {
 | 
|---|
| 256 |                 NTSTATUS expected_status;
 | 
|---|
| 257 |                 uint32_t cap = cli->transport->negotiate.capabilities;
 | 
|---|
| 258 | 
 | 
|---|
| 259 |                 torture_comment(tctx, "testing %s\n", levels[i].name);
 | 
|---|
| 260 | 
 | 
|---|
| 261 |                 levels[i].status = torture_single_search(cli, tctx, fname, 
 | 
|---|
| 262 |                                                          levels[i].level,
 | 
|---|
| 263 |                                                          levels[i].data_level,
 | 
|---|
| 264 |                                                          0,
 | 
|---|
| 265 |                                                          &levels[i].data);
 | 
|---|
| 266 | 
 | 
|---|
| 267 |                 /* see if this server claims to support this level */
 | 
|---|
| 268 |                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
 | 
|---|
| 269 |                         printf("search level %s(%d) not supported by server\n",
 | 
|---|
| 270 |                                levels[i].name, (int)levels[i].level);
 | 
|---|
| 271 |                         continue;
 | 
|---|
| 272 |                 }
 | 
|---|
| 273 | 
 | 
|---|
| 274 |                 if (!NT_STATUS_IS_OK(levels[i].status)) {
 | 
|---|
| 275 |                         printf("search level %s(%d) failed - %s\n",
 | 
|---|
| 276 |                                levels[i].name, (int)levels[i].level, 
 | 
|---|
| 277 |                                nt_errstr(levels[i].status));
 | 
|---|
| 278 |                         ret = false;
 | 
|---|
| 279 |                         continue;
 | 
|---|
| 280 |                 }
 | 
|---|
| 281 | 
 | 
|---|
| 282 |                 status = torture_single_search(cli, tctx, fname2, 
 | 
|---|
| 283 |                                                levels[i].level,
 | 
|---|
| 284 |                                                levels[i].data_level,
 | 
|---|
| 285 |                                                0,
 | 
|---|
| 286 |                                                &levels[i].data);
 | 
|---|
| 287 |                 
 | 
|---|
| 288 |                 expected_status = NT_STATUS_NO_SUCH_FILE;
 | 
|---|
| 289 |                 if (levels[i].level == RAW_SEARCH_SEARCH ||
 | 
|---|
| 290 |                     levels[i].level == RAW_SEARCH_FFIRST ||
 | 
|---|
| 291 |                     levels[i].level == RAW_SEARCH_FUNIQUE) {
 | 
|---|
| 292 |                         expected_status = STATUS_NO_MORE_FILES;
 | 
|---|
| 293 |                 }
 | 
|---|
| 294 |                 if (!NT_STATUS_EQUAL(status, expected_status)) {
 | 
|---|
| 295 |                         printf("search level %s(%d) should fail with %s - %s\n",
 | 
|---|
| 296 |                                levels[i].name, (int)levels[i].level, 
 | 
|---|
| 297 |                                nt_errstr(expected_status),
 | 
|---|
| 298 |                                nt_errstr(status));
 | 
|---|
| 299 |                         ret = false;
 | 
|---|
| 300 |                 }
 | 
|---|
| 301 |         }
 | 
|---|
| 302 | 
 | 
|---|
| 303 |         /* get the all_info file into to check against */
 | 
|---|
| 304 |         all_info.generic.level = RAW_FILEINFO_ALL_INFO;
 | 
|---|
| 305 |         all_info.generic.in.file.path = fname;
 | 
|---|
| 306 |         status = smb_raw_pathinfo(cli->tree, tctx, &all_info);
 | 
|---|
| 307 |         torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALL_INFO failed");
 | 
|---|
| 308 | 
 | 
|---|
| 309 |         alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
 | 
|---|
| 310 |         alt_info.generic.in.file.path = fname;
 | 
|---|
| 311 |         status = smb_raw_pathinfo(cli->tree, tctx, &alt_info);
 | 
|---|
| 312 |         torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALT_NAME_INFO failed");
 | 
|---|
| 313 | 
 | 
|---|
| 314 |         internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
 | 
|---|
| 315 |         internal_info.generic.in.file.path = fname;
 | 
|---|
| 316 |         status = smb_raw_pathinfo(cli->tree, tctx, &internal_info);
 | 
|---|
| 317 |         torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_INTERNAL_INFORMATION failed");
 | 
|---|
| 318 | 
 | 
|---|
| 319 |         name_info.generic.level = RAW_FILEINFO_NAME_INFO;
 | 
|---|
| 320 |         name_info.generic.in.file.path = fname;
 | 
|---|
| 321 |         status = smb_raw_pathinfo(cli->tree, tctx, &name_info);
 | 
|---|
| 322 |         torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_NAME_INFO failed");
 | 
|---|
| 323 | 
 | 
|---|
| 324 | #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
 | 
|---|
| 325 |         s = find(name); \
 | 
|---|
| 326 |         if (s) { \
 | 
|---|
| 327 |                 if ((s->sname1.field1) != (v.sname2.out.field2)) { \
 | 
|---|
| 328 |                         printf("(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
 | 
|---|
| 329 |                                __location__, \
 | 
|---|
| 330 |                                 #sname1, #field1, (int)s->sname1.field1, \
 | 
|---|
| 331 |                                 #sname2, #field2, (int)v.sname2.out.field2); \
 | 
|---|
| 332 |                         ret = false; \
 | 
|---|
| 333 |                 } \
 | 
|---|
| 334 |         }} while (0)
 | 
|---|
| 335 | 
 | 
|---|
| 336 | #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
 | 
|---|
| 337 |         s = find(name); \
 | 
|---|
| 338 |         if (s) { \
 | 
|---|
| 339 |                 if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
 | 
|---|
| 340 |                         printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
 | 
|---|
| 341 |                                __location__, \
 | 
|---|
| 342 |                                 #sname1, #field1, timestring(tctx, s->sname1.field1), \
 | 
|---|
| 343 |                                 #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
 | 
|---|
| 344 |                         ret = false; \
 | 
|---|
| 345 |                 } \
 | 
|---|
| 346 |         }} while (0)
 | 
|---|
| 347 | 
 | 
|---|
| 348 | #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
 | 
|---|
| 349 |         s = find(name); \
 | 
|---|
| 350 |         if (s) { \
 | 
|---|
| 351 |                 if (s->sname1.field1 != v.sname2.out.field2) { \
 | 
|---|
| 352 |                         printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
 | 
|---|
| 353 |                                __location__, \
 | 
|---|
| 354 |                                 #sname1, #field1, nt_time_string(tctx, s->sname1.field1), \
 | 
|---|
| 355 |                                 #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
 | 
|---|
| 356 |                         ret = false; \
 | 
|---|
| 357 |                 } \
 | 
|---|
| 358 |         }} while (0)
 | 
|---|
| 359 | 
 | 
|---|
| 360 | #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
 | 
|---|
| 361 |         s = find(name); \
 | 
|---|
| 362 |         if (s) { \
 | 
|---|
| 363 |                 if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
 | 
|---|
| 364 |                         printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
 | 
|---|
| 365 |                                __location__, \
 | 
|---|
| 366 |                                 #sname1, #field1, s->sname1.field1, \
 | 
|---|
| 367 |                                 #sname2, #field2, v.sname2.out.field2.s); \
 | 
|---|
| 368 |                         ret = false; \
 | 
|---|
| 369 |                 } \
 | 
|---|
| 370 |         }} while (0)
 | 
|---|
| 371 | 
 | 
|---|
| 372 | #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
 | 
|---|
| 373 |         s = find(name); \
 | 
|---|
| 374 |         if (s) { \
 | 
|---|
| 375 |                 if (!s->sname1.field1.s || \
 | 
|---|
| 376 |                     strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \
 | 
|---|
| 377 |                     wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
 | 
|---|
| 378 |                         printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
 | 
|---|
| 379 |                                __location__, \
 | 
|---|
| 380 |                                 #sname1, #field1, s->sname1.field1.s, \
 | 
|---|
| 381 |                                 #sname2, #field2, v.sname2.out.field2.s); \
 | 
|---|
| 382 |                         ret = false; \
 | 
|---|
| 383 |                 } \
 | 
|---|
| 384 |         }} while (0)
 | 
|---|
| 385 | 
 | 
|---|
| 386 | #define CHECK_NAME(name, sname1, field1, fname, flags) do { \
 | 
|---|
| 387 |         s = find(name); \
 | 
|---|
| 388 |         if (s) { \
 | 
|---|
| 389 |                 if (!s->sname1.field1.s || \
 | 
|---|
| 390 |                     strcmp(s->sname1.field1.s, fname) || \
 | 
|---|
| 391 |                     wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
 | 
|---|
| 392 |                         printf("(%s) %s/%s [%s] != %s\n", \
 | 
|---|
| 393 |                                __location__, \
 | 
|---|
| 394 |                                 #sname1, #field1, s->sname1.field1.s, \
 | 
|---|
| 395 |                                 fname); \
 | 
|---|
| 396 |                         ret = false; \
 | 
|---|
| 397 |                 } \
 | 
|---|
| 398 |         }} while (0)
 | 
|---|
| 399 | 
 | 
|---|
| 400 | #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
 | 
|---|
| 401 |         s = find(name); \
 | 
|---|
| 402 |         if (s) { \
 | 
|---|
| 403 |                 if (!s->sname1.field1 || \
 | 
|---|
| 404 |                     strcmp(s->sname1.field1, fname)) { \
 | 
|---|
| 405 |                         printf("(%s) %s/%s [%s] != %s\n", \
 | 
|---|
| 406 |                                __location__, \
 | 
|---|
| 407 |                                 #sname1, #field1, s->sname1.field1, \
 | 
|---|
| 408 |                                 fname); \
 | 
|---|
| 409 |                         ret = false; \
 | 
|---|
| 410 |                 } \
 | 
|---|
| 411 |         }} while (0)
 | 
|---|
| 412 |         
 | 
|---|
| 413 |         /* check that all the results are as expected */
 | 
|---|
| 414 |         CHECK_VAL("SEARCH",              search,              attrib, all_info, all_info, attrib&0xFFF);
 | 
|---|
| 415 |         CHECK_VAL("STANDARD",            standard,            attrib, all_info, all_info, attrib&0xFFF);
 | 
|---|
| 416 |         CHECK_VAL("EA_SIZE",             ea_size,             attrib, all_info, all_info, attrib&0xFFF);
 | 
|---|
| 417 |         CHECK_VAL("DIRECTORY_INFO",      directory_info,      attrib, all_info, all_info, attrib);
 | 
|---|
| 418 |         CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info, all_info, attrib);
 | 
|---|
| 419 |         CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info, all_info, attrib);
 | 
|---|
| 420 |         CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           attrib, all_info, all_info, attrib);
 | 
|---|
| 421 |         CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           attrib, all_info, all_info, attrib);
 | 
|---|
| 422 | 
 | 
|---|
| 423 |         CHECK_TIME("SEARCH",             search,              write_time, all_info, all_info, write_time);
 | 
|---|
| 424 |         CHECK_TIME("STANDARD",           standard,            write_time, all_info, all_info, write_time);
 | 
|---|
| 425 |         CHECK_TIME("EA_SIZE",            ea_size,             write_time, all_info, all_info, write_time);
 | 
|---|
| 426 |         CHECK_TIME("STANDARD",           standard,            create_time, all_info, all_info, create_time);
 | 
|---|
| 427 |         CHECK_TIME("EA_SIZE",            ea_size,             create_time, all_info, all_info, create_time);
 | 
|---|
| 428 |         CHECK_TIME("STANDARD",           standard,            access_time, all_info, all_info, access_time);
 | 
|---|
| 429 |         CHECK_TIME("EA_SIZE",            ea_size,             access_time, all_info, all_info, access_time);
 | 
|---|
| 430 | 
 | 
|---|
| 431 |         CHECK_NTTIME("DIRECTORY_INFO",      directory_info,      write_time, all_info, all_info, write_time);
 | 
|---|
| 432 |         CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info, all_info, write_time);
 | 
|---|
| 433 |         CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info, all_info, write_time);
 | 
|---|
| 434 |         CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           write_time, all_info, all_info, write_time);
 | 
|---|
| 435 |         CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           write_time, all_info, all_info, write_time);
 | 
|---|
| 436 | 
 | 
|---|
| 437 |         CHECK_NTTIME("DIRECTORY_INFO",      directory_info,      create_time, all_info, all_info, create_time);
 | 
|---|
| 438 |         CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time);
 | 
|---|
| 439 |         CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time);
 | 
|---|
| 440 |         CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           create_time, all_info, all_info, create_time);
 | 
|---|
| 441 |         CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           create_time, all_info, all_info, create_time);
 | 
|---|
| 442 | 
 | 
|---|
| 443 |         CHECK_NTTIME("DIRECTORY_INFO",      directory_info,      access_time, all_info, all_info, access_time);
 | 
|---|
| 444 |         CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info, all_info, access_time);
 | 
|---|
| 445 |         CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info, all_info, access_time);
 | 
|---|
| 446 |         CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           access_time, all_info, all_info, access_time);
 | 
|---|
| 447 |         CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           access_time, all_info, all_info, access_time);
 | 
|---|
| 448 | 
 | 
|---|
| 449 |         CHECK_NTTIME("DIRECTORY_INFO",      directory_info,      change_time, all_info, all_info, change_time);
 | 
|---|
| 450 |         CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info, all_info, change_time);
 | 
|---|
| 451 |         CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info, all_info, change_time);
 | 
|---|
| 452 |         CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           change_time, all_info, all_info, change_time);
 | 
|---|
| 453 |         CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           change_time, all_info, all_info, change_time);
 | 
|---|
| 454 | 
 | 
|---|
| 455 |         CHECK_VAL("SEARCH",              search,              size, all_info, all_info, size);
 | 
|---|
| 456 |         CHECK_VAL("STANDARD",            standard,            size, all_info, all_info, size);
 | 
|---|
| 457 |         CHECK_VAL("EA_SIZE",             ea_size,             size, all_info, all_info, size);
 | 
|---|
| 458 |         CHECK_VAL("DIRECTORY_INFO",      directory_info,      size, all_info, all_info, size);
 | 
|---|
| 459 |         CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, size, all_info, all_info, size);
 | 
|---|
| 460 |         CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, size, all_info, all_info, size);
 | 
|---|
| 461 |         CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           size, all_info, all_info, size);
 | 
|---|
| 462 |         CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           size, all_info, all_info, size);
 | 
|---|
| 463 |         CHECK_VAL("UNIX_INFO",           unix_info,           size, all_info, all_info, size);
 | 
|---|
| 464 | 
 | 
|---|
| 465 |         CHECK_VAL("STANDARD",            standard,            alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 466 |         CHECK_VAL("EA_SIZE",             ea_size,             alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 467 |         CHECK_VAL("DIRECTORY_INFO",      directory_info,      alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 468 |         CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 469 |         CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 470 |         CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 471 |         CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 472 |         CHECK_VAL("UNIX_INFO",           unix_info,           alloc_size, all_info, all_info, alloc_size);
 | 
|---|
| 473 | 
 | 
|---|
| 474 |         CHECK_VAL("EA_SIZE",             ea_size,             ea_size, all_info, all_info, ea_size);
 | 
|---|
| 475 |         CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info, all_info, ea_size);
 | 
|---|
| 476 |         CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info, all_info, ea_size);
 | 
|---|
| 477 |         CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           ea_size, all_info, all_info, ea_size);
 | 
|---|
| 478 |         CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           ea_size, all_info, all_info, ea_size);
 | 
|---|
| 479 | 
 | 
|---|
| 480 |         CHECK_STR("SEARCH", search, name, alt_info, alt_name_info, fname);
 | 
|---|
| 481 |         CHECK_WSTR("BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE);
 | 
|---|
| 482 | 
 | 
|---|
| 483 |         CHECK_NAME("STANDARD",            standard,            name, fname+1, 0);
 | 
|---|
| 484 |         CHECK_NAME("EA_SIZE",             ea_size,             name, fname+1, 0);
 | 
|---|
| 485 |         CHECK_NAME("DIRECTORY_INFO",      directory_info,      name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 486 |         CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 487 |         CHECK_NAME("NAME_INFO",           name_info,           name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 488 |         CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 489 |         CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 490 |         CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 491 |         CHECK_UNIX_NAME("UNIX_INFO",           unix_info,           name, fname+1, STR_TERMINATE_ASCII);
 | 
|---|
| 492 | 
 | 
|---|
| 493 |         CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, file_id, internal_info, internal_information, file_id);
 | 
|---|
| 494 |         CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, file_id, internal_info, internal_information, file_id);
 | 
|---|
| 495 | 
 | 
|---|
| 496 | done:
 | 
|---|
| 497 |         smb_raw_exit(cli->session);
 | 
|---|
| 498 |         smbcli_unlink(cli->tree, fname);
 | 
|---|
| 499 | 
 | 
|---|
| 500 |         return ret;
 | 
|---|
| 501 | }
 | 
|---|
| 502 | 
 | 
|---|
| 503 | 
 | 
|---|
| 504 | struct multiple_result {
 | 
|---|
| 505 |         TALLOC_CTX *tctx;
 | 
|---|
| 506 |         int count;
 | 
|---|
| 507 |         union smb_search_data *list;
 | 
|---|
| 508 | };
 | 
|---|
| 509 | 
 | 
|---|
| 510 | /*
 | 
|---|
| 511 |   callback function for multiple_search
 | 
|---|
| 512 | */
 | 
|---|
| 513 | static bool multiple_search_callback(void *private_data, const union smb_search_data *file)
 | 
|---|
| 514 | {
 | 
|---|
| 515 |         struct multiple_result *data = (struct multiple_result *)private_data;
 | 
|---|
| 516 | 
 | 
|---|
| 517 | 
 | 
|---|
| 518 |         data->count++;
 | 
|---|
| 519 |         data->list = talloc_realloc(data->tctx,
 | 
|---|
| 520 |                                       data->list, 
 | 
|---|
| 521 |                                       union smb_search_data,
 | 
|---|
| 522 |                                       data->count);
 | 
|---|
| 523 | 
 | 
|---|
| 524 |         data->list[data->count-1] = *file;
 | 
|---|
| 525 | 
 | 
|---|
| 526 |         return true;
 | 
|---|
| 527 | }
 | 
|---|
| 528 | 
 | 
|---|
| 529 | enum continue_type {CONT_FLAGS, CONT_NAME, CONT_RESUME_KEY};
 | 
|---|
| 530 | 
 | 
|---|
| 531 | /*
 | 
|---|
| 532 |   do a single file (non-wildcard) search 
 | 
|---|
| 533 | */
 | 
|---|
| 534 | static NTSTATUS multiple_search(struct smbcli_state *cli, 
 | 
|---|
| 535 |                                 TALLOC_CTX *tctx,
 | 
|---|
| 536 |                                 const char *pattern,
 | 
|---|
| 537 |                                 enum smb_search_data_level data_level,
 | 
|---|
| 538 |                                 enum continue_type cont_type,
 | 
|---|
| 539 |                                 void *data)
 | 
|---|
| 540 | {
 | 
|---|
| 541 |         union smb_search_first io;
 | 
|---|
| 542 |         union smb_search_next io2;
 | 
|---|
| 543 |         NTSTATUS status;
 | 
|---|
| 544 |         const int per_search = 100;
 | 
|---|
| 545 |         struct multiple_result *result = (struct multiple_result *)data;
 | 
|---|
| 546 | 
 | 
|---|
| 547 |         if (data_level == RAW_SEARCH_DATA_SEARCH) {
 | 
|---|
| 548 |                 io.search_first.level = RAW_SEARCH_SEARCH;
 | 
|---|
| 549 |                 io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 550 |                 io.search_first.in.max_count = per_search;
 | 
|---|
| 551 |                 io.search_first.in.search_attrib = 0;
 | 
|---|
| 552 |                 io.search_first.in.pattern = pattern;
 | 
|---|
| 553 |         } else {
 | 
|---|
| 554 |                 io.t2ffirst.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 555 |                 io.t2ffirst.data_level = data_level;
 | 
|---|
| 556 |                 io.t2ffirst.in.search_attrib = 0;
 | 
|---|
| 557 |                 io.t2ffirst.in.max_count = per_search;
 | 
|---|
| 558 |                 io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
 | 
|---|
| 559 |                 io.t2ffirst.in.storage_type = 0;
 | 
|---|
| 560 |                 io.t2ffirst.in.pattern = pattern;
 | 
|---|
| 561 |                 if (cont_type == CONT_RESUME_KEY) {
 | 
|---|
| 562 |                         io.t2ffirst.in.flags |= FLAG_TRANS2_FIND_REQUIRE_RESUME | 
 | 
|---|
| 563 |                                 FLAG_TRANS2_FIND_BACKUP_INTENT;
 | 
|---|
| 564 |                 }
 | 
|---|
| 565 |         }
 | 
|---|
| 566 | 
 | 
|---|
| 567 |         status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 568 |                                       &io, data, multiple_search_callback);
 | 
|---|
| 569 |         
 | 
|---|
| 570 | 
 | 
|---|
| 571 |         while (NT_STATUS_IS_OK(status)) {
 | 
|---|
| 572 |                 if (data_level == RAW_SEARCH_DATA_SEARCH) {
 | 
|---|
| 573 |                         io2.search_next.level = RAW_SEARCH_SEARCH;
 | 
|---|
| 574 |                         io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 575 |                         io2.search_next.in.max_count = per_search;
 | 
|---|
| 576 |                         io2.search_next.in.search_attrib = 0;
 | 
|---|
| 577 |                         io2.search_next.in.id = result->list[result->count-1].search.id;
 | 
|---|
| 578 |                 } else {
 | 
|---|
| 579 |                         io2.t2fnext.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 580 |                         io2.t2fnext.data_level = data_level;
 | 
|---|
| 581 |                         io2.t2fnext.in.handle = io.t2ffirst.out.handle;
 | 
|---|
| 582 |                         io2.t2fnext.in.max_count = per_search;
 | 
|---|
| 583 |                         io2.t2fnext.in.resume_key = 0;
 | 
|---|
| 584 |                         io2.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
 | 
|---|
| 585 |                         io2.t2fnext.in.last_name = "";
 | 
|---|
| 586 |                         switch (cont_type) {
 | 
|---|
| 587 |                         case CONT_RESUME_KEY:
 | 
|---|
| 588 |                                 io2.t2fnext.in.resume_key = extract_resume_key(&result->list[result->count-1],
 | 
|---|
| 589 |                                                                                io2.t2fnext.level, io2.t2fnext.data_level);
 | 
|---|
| 590 |                                 if (io2.t2fnext.in.resume_key == 0) {
 | 
|---|
| 591 |                                         printf("Server does not support resume by key for level %s\n",
 | 
|---|
| 592 |                                                level_name(io2.t2fnext.level, io2.t2fnext.data_level));
 | 
|---|
| 593 |                                         return NT_STATUS_NOT_SUPPORTED;
 | 
|---|
| 594 |                                 }
 | 
|---|
| 595 |                                 io2.t2fnext.in.flags |= FLAG_TRANS2_FIND_REQUIRE_RESUME |
 | 
|---|
| 596 |                                         FLAG_TRANS2_FIND_BACKUP_INTENT;
 | 
|---|
| 597 |                                 break;
 | 
|---|
| 598 |                         case CONT_NAME:
 | 
|---|
| 599 |                                 io2.t2fnext.in.last_name = extract_name(&result->list[result->count-1],
 | 
|---|
| 600 |                                                                         io2.t2fnext.level, io2.t2fnext.data_level);
 | 
|---|
| 601 |                                 break;
 | 
|---|
| 602 |                         case CONT_FLAGS:
 | 
|---|
| 603 |                                 io2.t2fnext.in.flags |= FLAG_TRANS2_FIND_CONTINUE;
 | 
|---|
| 604 |                                 break;
 | 
|---|
| 605 |                         }
 | 
|---|
| 606 |                 }
 | 
|---|
| 607 | 
 | 
|---|
| 608 |                 status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 609 |                                              &io2, data, multiple_search_callback);
 | 
|---|
| 610 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 611 |                         break;
 | 
|---|
| 612 |                 }
 | 
|---|
| 613 |                 if (data_level == RAW_SEARCH_DATA_SEARCH) {
 | 
|---|
| 614 |                         if (io2.search_next.out.count == 0) {
 | 
|---|
| 615 |                                 break;
 | 
|---|
| 616 |                         }
 | 
|---|
| 617 |                 } else if (io2.t2fnext.out.count == 0 ||
 | 
|---|
| 618 |                            io2.t2fnext.out.end_of_search) {
 | 
|---|
| 619 |                         break;
 | 
|---|
| 620 |                 }
 | 
|---|
| 621 |         }
 | 
|---|
| 622 | 
 | 
|---|
| 623 |         return status;
 | 
|---|
| 624 | }
 | 
|---|
| 625 | 
 | 
|---|
| 626 | #define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status")
 | 
|---|
| 627 | 
 | 
|---|
| 628 | #define CHECK_VALUE(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
 | 
|---|
| 629 | 
 | 
|---|
| 630 | #define CHECK_STRING(v, correct) torture_assert_casestr_equal(tctx, v, correct, "incorrect value");
 | 
|---|
| 631 | 
 | 
|---|
| 632 | 
 | 
|---|
| 633 | static enum smb_search_data_level compare_data_level;
 | 
|---|
| 634 | 
 | 
|---|
| 635 | static int search_compare(union smb_search_data *d1, union smb_search_data *d2)
 | 
|---|
| 636 | {
 | 
|---|
| 637 |         const char *s1, *s2;
 | 
|---|
| 638 |         enum smb_search_level level;
 | 
|---|
| 639 | 
 | 
|---|
| 640 |         if (compare_data_level == RAW_SEARCH_DATA_SEARCH) {
 | 
|---|
| 641 |                 level = RAW_SEARCH_SEARCH;
 | 
|---|
| 642 |         } else {
 | 
|---|
| 643 |                 level = RAW_SEARCH_TRANS2;
 | 
|---|
| 644 |         }
 | 
|---|
| 645 | 
 | 
|---|
| 646 |         s1 = extract_name(d1, level, compare_data_level);
 | 
|---|
| 647 |         s2 = extract_name(d2, level, compare_data_level);
 | 
|---|
| 648 |         return strcmp_safe(s1, s2);
 | 
|---|
| 649 | }
 | 
|---|
| 650 | 
 | 
|---|
| 651 | 
 | 
|---|
| 652 | 
 | 
|---|
| 653 | /* 
 | 
|---|
| 654 |    basic testing of search calls using many files
 | 
|---|
| 655 | */
 | 
|---|
| 656 | static bool test_many_files(struct torture_context *tctx, 
 | 
|---|
| 657 |                             struct smbcli_state *cli)
 | 
|---|
| 658 | {
 | 
|---|
| 659 |         const int num_files = 700;
 | 
|---|
| 660 |         int i, fnum, t;
 | 
|---|
| 661 |         char *fname;
 | 
|---|
| 662 |         bool ret = true;
 | 
|---|
| 663 |         NTSTATUS status;
 | 
|---|
| 664 |         struct multiple_result result;
 | 
|---|
| 665 |         struct {
 | 
|---|
| 666 |                 const char *name;
 | 
|---|
| 667 |                 const char *cont_name;
 | 
|---|
| 668 |                 enum smb_search_data_level data_level;
 | 
|---|
| 669 |                 enum continue_type cont_type;
 | 
|---|
| 670 |         } search_types[] = {
 | 
|---|
| 671 |                 {"SEARCH",              "ID",    RAW_SEARCH_DATA_SEARCH,              CONT_RESUME_KEY},
 | 
|---|
| 672 |                 {"BOTH_DIRECTORY_INFO", "NAME",  RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_NAME},
 | 
|---|
| 673 |                 {"BOTH_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_FLAGS},
 | 
|---|
| 674 |                 {"BOTH_DIRECTORY_INFO", "KEY",   RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_RESUME_KEY},
 | 
|---|
| 675 |                 {"STANDARD",            "FLAGS", RAW_SEARCH_DATA_STANDARD,            CONT_FLAGS},
 | 
|---|
| 676 |                 {"STANDARD",            "KEY",   RAW_SEARCH_DATA_STANDARD,            CONT_RESUME_KEY},
 | 
|---|
| 677 |                 {"STANDARD",            "NAME",  RAW_SEARCH_DATA_STANDARD,            CONT_NAME},
 | 
|---|
| 678 |                 {"EA_SIZE",             "FLAGS", RAW_SEARCH_DATA_EA_SIZE,             CONT_FLAGS},
 | 
|---|
| 679 |                 {"EA_SIZE",             "KEY",   RAW_SEARCH_DATA_EA_SIZE,             CONT_RESUME_KEY},
 | 
|---|
| 680 |                 {"EA_SIZE",             "NAME",  RAW_SEARCH_DATA_EA_SIZE,             CONT_NAME},
 | 
|---|
| 681 |                 {"DIRECTORY_INFO",      "FLAGS", RAW_SEARCH_DATA_DIRECTORY_INFO,      CONT_FLAGS},
 | 
|---|
| 682 |                 {"DIRECTORY_INFO",      "KEY",   RAW_SEARCH_DATA_DIRECTORY_INFO,      CONT_RESUME_KEY},
 | 
|---|
| 683 |                 {"DIRECTORY_INFO",      "NAME",  RAW_SEARCH_DATA_DIRECTORY_INFO,      CONT_NAME},
 | 
|---|
| 684 |                 {"FULL_DIRECTORY_INFO",    "FLAGS", RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_FLAGS},
 | 
|---|
| 685 |                 {"FULL_DIRECTORY_INFO",    "KEY",   RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_RESUME_KEY},
 | 
|---|
| 686 |                 {"FULL_DIRECTORY_INFO",    "NAME",  RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_NAME},
 | 
|---|
| 687 |                 {"ID_FULL_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_FLAGS},
 | 
|---|
| 688 |                 {"ID_FULL_DIRECTORY_INFO", "KEY",   RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESUME_KEY},
 | 
|---|
| 689 |                 {"ID_FULL_DIRECTORY_INFO", "NAME",  RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_NAME},
 | 
|---|
| 690 |                 {"ID_BOTH_DIRECTORY_INFO", "NAME",  RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_NAME},
 | 
|---|
| 691 |                 {"ID_BOTH_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_FLAGS},
 | 
|---|
| 692 |                 {"ID_BOTH_DIRECTORY_INFO", "KEY",   RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESUME_KEY}
 | 
|---|
| 693 |         };
 | 
|---|
| 694 | 
 | 
|---|
| 695 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 696 |                 return false;
 | 
|---|
| 697 |         }
 | 
|---|
| 698 | 
 | 
|---|
| 699 |         torture_comment(tctx, "Testing with %d files\n", num_files);
 | 
|---|
| 700 | 
 | 
|---|
| 701 |         for (i=0;i<num_files;i++) {
 | 
|---|
| 702 |                 fname = talloc_asprintf(cli, BASEDIR "\\t%03d-%d.txt", i, i);
 | 
|---|
| 703 |                 fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 704 |                 torture_assert(tctx, fnum != -1, "Failed to create");
 | 
|---|
| 705 |                 talloc_free(fname);
 | 
|---|
| 706 |                 smbcli_close(cli->tree, fnum);
 | 
|---|
| 707 |         }
 | 
|---|
| 708 | 
 | 
|---|
| 709 | 
 | 
|---|
| 710 |         for (t=0;t<ARRAY_SIZE(search_types);t++) {
 | 
|---|
| 711 |                 ZERO_STRUCT(result);
 | 
|---|
| 712 | 
 | 
|---|
| 713 |                 if ((search_types[t].cont_type == CONT_RESUME_KEY) &&
 | 
|---|
| 714 |                     (search_types[t].data_level != RAW_SEARCH_DATA_SEARCH) &&
 | 
|---|
| 715 |                     torture_setting_bool(tctx, "samba3", false)) {
 | 
|---|
| 716 |                         torture_comment(tctx,
 | 
|---|
| 717 |                                         "SKIP: Continue %s via %s\n",
 | 
|---|
| 718 |                                         search_types[t].name, search_types[t].cont_name);
 | 
|---|
| 719 |                         continue;
 | 
|---|
| 720 |                 }
 | 
|---|
| 721 | 
 | 
|---|
| 722 |                 result.tctx = talloc_new(tctx);
 | 
|---|
| 723 |         
 | 
|---|
| 724 |                 torture_comment(tctx,
 | 
|---|
| 725 |                                 "Continue %s via %s\n", search_types[t].name, search_types[t].cont_name);
 | 
|---|
| 726 | 
 | 
|---|
| 727 |                 status = multiple_search(cli, tctx, BASEDIR "\\*.*", 
 | 
|---|
| 728 |                                          search_types[t].data_level,
 | 
|---|
| 729 |                                          search_types[t].cont_type,
 | 
|---|
| 730 |                                          &result);
 | 
|---|
| 731 |         
 | 
|---|
| 732 |                 torture_assert_ntstatus_ok(tctx, status, "search failed");
 | 
|---|
| 733 |                 CHECK_VALUE(result.count, num_files);
 | 
|---|
| 734 | 
 | 
|---|
| 735 |                 compare_data_level = search_types[t].data_level;
 | 
|---|
| 736 | 
 | 
|---|
| 737 |                 qsort(result.list, result.count, sizeof(result.list[0]), 
 | 
|---|
| 738 |                       QSORT_CAST  search_compare);
 | 
|---|
| 739 | 
 | 
|---|
| 740 |                 for (i=0;i<result.count;i++) {
 | 
|---|
| 741 |                         const char *s;
 | 
|---|
| 742 |                         enum smb_search_level level;
 | 
|---|
| 743 |                         if (compare_data_level == RAW_SEARCH_DATA_SEARCH) {
 | 
|---|
| 744 |                                 level = RAW_SEARCH_SEARCH;
 | 
|---|
| 745 |                         } else {
 | 
|---|
| 746 |                                 level = RAW_SEARCH_TRANS2;
 | 
|---|
| 747 |                         }
 | 
|---|
| 748 |                         s = extract_name(&result.list[i], level, compare_data_level);
 | 
|---|
| 749 |                         fname = talloc_asprintf(cli, "t%03d-%d.txt", i, i);
 | 
|---|
| 750 |                         torture_assert_str_equal(tctx, fname, s, "Incorrect name");
 | 
|---|
| 751 |                         talloc_free(fname);
 | 
|---|
| 752 |                 }
 | 
|---|
| 753 |                 talloc_free(result.tctx);
 | 
|---|
| 754 |         }
 | 
|---|
| 755 | 
 | 
|---|
| 756 |         smb_raw_exit(cli->session);
 | 
|---|
| 757 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 758 | 
 | 
|---|
| 759 |         return ret;
 | 
|---|
| 760 | }
 | 
|---|
| 761 | 
 | 
|---|
| 762 | /*
 | 
|---|
| 763 |   check a individual file result
 | 
|---|
| 764 | */
 | 
|---|
| 765 | static bool check_result(struct multiple_result *result, const char *name, bool exist, uint32_t attrib)
 | 
|---|
| 766 | {
 | 
|---|
| 767 |         int i;
 | 
|---|
| 768 |         for (i=0;i<result->count;i++) {
 | 
|---|
| 769 |                 if (strcmp(name, result->list[i].both_directory_info.name.s) == 0) break;
 | 
|---|
| 770 |         }
 | 
|---|
| 771 |         if (i == result->count) {
 | 
|---|
| 772 |                 if (exist) {
 | 
|---|
| 773 |                         printf("failed: '%s' should exist with attribute %s\n", 
 | 
|---|
| 774 |                                name, attrib_string(result->list, attrib));
 | 
|---|
| 775 |                         return false;
 | 
|---|
| 776 |                 }
 | 
|---|
| 777 |                 return true;
 | 
|---|
| 778 |         }
 | 
|---|
| 779 | 
 | 
|---|
| 780 |         if (!exist) {
 | 
|---|
| 781 |                 printf("failed: '%s' should NOT exist (has attribute %s)\n", 
 | 
|---|
| 782 |                        name, attrib_string(result->list, result->list[i].both_directory_info.attrib));
 | 
|---|
| 783 |                 return false;
 | 
|---|
| 784 |         }
 | 
|---|
| 785 | 
 | 
|---|
| 786 |         if ((result->list[i].both_directory_info.attrib&0xFFF) != attrib) {
 | 
|---|
| 787 |                 printf("failed: '%s' should have attribute 0x%x (has 0x%x)\n",
 | 
|---|
| 788 |                        name, 
 | 
|---|
| 789 |                        attrib, result->list[i].both_directory_info.attrib);
 | 
|---|
| 790 |                 return false;
 | 
|---|
| 791 |         }
 | 
|---|
| 792 |         return true;
 | 
|---|
| 793 | }
 | 
|---|
| 794 | 
 | 
|---|
| 795 | /* 
 | 
|---|
| 796 |    test what happens when the directory is modified during a search
 | 
|---|
| 797 | */
 | 
|---|
| 798 | static bool test_modify_search(struct torture_context *tctx, 
 | 
|---|
| 799 |                                                            struct smbcli_state *cli)
 | 
|---|
| 800 | {
 | 
|---|
| 801 |         const int num_files = 20;
 | 
|---|
| 802 |         int i, fnum;
 | 
|---|
| 803 |         char *fname;
 | 
|---|
| 804 |         bool ret = true;
 | 
|---|
| 805 |         NTSTATUS status;
 | 
|---|
| 806 |         struct multiple_result result;
 | 
|---|
| 807 |         union smb_search_first io;
 | 
|---|
| 808 |         union smb_search_next io2;
 | 
|---|
| 809 |         union smb_setfileinfo sfinfo;
 | 
|---|
| 810 | 
 | 
|---|
| 811 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 812 |                 return false;
 | 
|---|
| 813 |         }
 | 
|---|
| 814 | 
 | 
|---|
| 815 |         printf("Creating %d files\n", num_files);
 | 
|---|
| 816 | 
 | 
|---|
| 817 |         for (i=num_files-1;i>=0;i--) {
 | 
|---|
| 818 |                 fname = talloc_asprintf(cli, BASEDIR "\\t%03d-%d.txt", i, i);
 | 
|---|
| 819 |                 fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 820 |                 if (fnum == -1) {
 | 
|---|
| 821 |                         printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
 | 
|---|
| 822 |                         ret = false;
 | 
|---|
| 823 |                         goto done;
 | 
|---|
| 824 |                 }
 | 
|---|
| 825 |                 talloc_free(fname);
 | 
|---|
| 826 |                 smbcli_close(cli->tree, fnum);
 | 
|---|
| 827 |         }
 | 
|---|
| 828 | 
 | 
|---|
| 829 |         printf("pulling the first file\n");
 | 
|---|
| 830 |         ZERO_STRUCT(result);
 | 
|---|
| 831 |         result.tctx = talloc_new(tctx);
 | 
|---|
| 832 | 
 | 
|---|
| 833 |         io.t2ffirst.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 834 |         io.t2ffirst.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
 | 
|---|
| 835 |         io.t2ffirst.in.search_attrib = 0;
 | 
|---|
| 836 |         io.t2ffirst.in.max_count = 0;
 | 
|---|
| 837 |         io.t2ffirst.in.flags = 0;
 | 
|---|
| 838 |         io.t2ffirst.in.storage_type = 0;
 | 
|---|
| 839 |         io.t2ffirst.in.pattern = BASEDIR "\\*.*";
 | 
|---|
| 840 | 
 | 
|---|
| 841 |         status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 842 |                                       &io, &result, multiple_search_callback);
 | 
|---|
| 843 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 844 |         CHECK_VALUE(result.count, 1);
 | 
|---|
| 845 |         
 | 
|---|
| 846 |         printf("pulling the second file\n");
 | 
|---|
| 847 |         io2.t2fnext.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 848 |         io2.t2fnext.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
 | 
|---|
| 849 |         io2.t2fnext.in.handle = io.t2ffirst.out.handle;
 | 
|---|
| 850 |         io2.t2fnext.in.max_count = 1;
 | 
|---|
| 851 |         io2.t2fnext.in.resume_key = 0;
 | 
|---|
| 852 |         io2.t2fnext.in.flags = 0;
 | 
|---|
| 853 |         io2.t2fnext.in.last_name = result.list[result.count-1].both_directory_info.name.s;
 | 
|---|
| 854 | 
 | 
|---|
| 855 |         status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 856 |                                      &io2, &result, multiple_search_callback);
 | 
|---|
| 857 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 858 |         CHECK_VALUE(result.count, 2);
 | 
|---|
| 859 | 
 | 
|---|
| 860 |         result.count = 0;
 | 
|---|
| 861 | 
 | 
|---|
| 862 |         printf("Changing attributes and deleting\n");
 | 
|---|
| 863 |         smbcli_open(cli->tree, BASEDIR "\\T003-03.txt.2", O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 864 |         smbcli_open(cli->tree, BASEDIR "\\T013-13.txt.2", O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 865 |         fnum = create_complex_file(cli, tctx, BASEDIR "\\T013-13.txt.3");
 | 
|---|
| 866 |         smbcli_unlink(cli->tree, BASEDIR "\\T014-14.txt");
 | 
|---|
| 867 |         torture_set_file_attribute(cli->tree, BASEDIR "\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN);
 | 
|---|
| 868 |         torture_set_file_attribute(cli->tree, BASEDIR "\\T016-16.txt", FILE_ATTRIBUTE_NORMAL);
 | 
|---|
| 869 |         torture_set_file_attribute(cli->tree, BASEDIR "\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM);  
 | 
|---|
| 870 |         torture_set_file_attribute(cli->tree, BASEDIR "\\T018-18.txt", 0);      
 | 
|---|
| 871 |         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
 | 
|---|
| 872 |         sfinfo.generic.in.file.fnum = fnum;
 | 
|---|
| 873 |         sfinfo.disposition_info.in.delete_on_close = 1;
 | 
|---|
| 874 |         status = smb_raw_setfileinfo(cli->tree, &sfinfo);
 | 
|---|
| 875 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 876 | 
 | 
|---|
| 877 |         io2.t2fnext.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 878 |         io2.t2fnext.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
 | 
|---|
| 879 |         io2.t2fnext.in.handle = io.t2ffirst.out.handle;
 | 
|---|
| 880 |         io2.t2fnext.in.max_count = num_files + 3;
 | 
|---|
| 881 |         io2.t2fnext.in.resume_key = 0;
 | 
|---|
| 882 |         io2.t2fnext.in.flags = 0;
 | 
|---|
| 883 |         io2.t2fnext.in.last_name = ".";
 | 
|---|
| 884 | 
 | 
|---|
| 885 |         status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 886 |                                      &io2, &result, multiple_search_callback);
 | 
|---|
| 887 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 888 |         CHECK_VALUE(result.count, 20);
 | 
|---|
| 889 | 
 | 
|---|
| 890 |         ret &= check_result(&result, "t009-9.txt", true, FILE_ATTRIBUTE_ARCHIVE);
 | 
|---|
| 891 |         ret &= check_result(&result, "t014-14.txt", false, 0);
 | 
|---|
| 892 |         ret &= check_result(&result, "t015-15.txt", false, 0);
 | 
|---|
| 893 |         ret &= check_result(&result, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL);
 | 
|---|
| 894 |         ret &= check_result(&result, "t017-17.txt", false, 0);
 | 
|---|
| 895 |         ret &= check_result(&result, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE);
 | 
|---|
| 896 |         ret &= check_result(&result, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE);
 | 
|---|
| 897 |         ret &= check_result(&result, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE);
 | 
|---|
| 898 |         ret &= check_result(&result, "T003-3.txt.2", false, 0);
 | 
|---|
| 899 |         ret &= check_result(&result, "T013-13.txt.3", true, FILE_ATTRIBUTE_ARCHIVE);
 | 
|---|
| 900 | 
 | 
|---|
| 901 |         if (!ret) {
 | 
|---|
| 902 |                 for (i=0;i<result.count;i++) {
 | 
|---|
| 903 |                         printf("%s %s (0x%x)\n", 
 | 
|---|
| 904 |                                result.list[i].both_directory_info.name.s, 
 | 
|---|
| 905 |                                attrib_string(tctx, result.list[i].both_directory_info.attrib),
 | 
|---|
| 906 |                                result.list[i].both_directory_info.attrib);
 | 
|---|
| 907 |                 }
 | 
|---|
| 908 |         }
 | 
|---|
| 909 | 
 | 
|---|
| 910 | done:
 | 
|---|
| 911 |         smb_raw_exit(cli->session);
 | 
|---|
| 912 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 913 | 
 | 
|---|
| 914 |         return ret;
 | 
|---|
| 915 | }
 | 
|---|
| 916 | 
 | 
|---|
| 917 | 
 | 
|---|
| 918 | /* 
 | 
|---|
| 919 |    testing if directories always come back sorted
 | 
|---|
| 920 | */
 | 
|---|
| 921 | static bool test_sorted(struct torture_context *tctx, struct smbcli_state *cli)
 | 
|---|
| 922 | {
 | 
|---|
| 923 |         const int num_files = 700;
 | 
|---|
| 924 |         int i, fnum;
 | 
|---|
| 925 |         char *fname;
 | 
|---|
| 926 |         bool ret = true;
 | 
|---|
| 927 |         NTSTATUS status;
 | 
|---|
| 928 |         struct multiple_result result;
 | 
|---|
| 929 | 
 | 
|---|
| 930 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 931 |                 return false;
 | 
|---|
| 932 |         }
 | 
|---|
| 933 | 
 | 
|---|
| 934 |         printf("Creating %d files\n", num_files);
 | 
|---|
| 935 | 
 | 
|---|
| 936 |         for (i=0;i<num_files;i++) {
 | 
|---|
| 937 |                 fname = talloc_asprintf(cli, BASEDIR "\\%s.txt", generate_random_str_list(tctx, 10, "abcdefgh"));
 | 
|---|
| 938 |                 fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 939 |                 if (fnum == -1) {
 | 
|---|
| 940 |                         printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
 | 
|---|
| 941 |                         ret = false;
 | 
|---|
| 942 |                         goto done;
 | 
|---|
| 943 |                 }
 | 
|---|
| 944 |                 talloc_free(fname);
 | 
|---|
| 945 |                 smbcli_close(cli->tree, fnum);
 | 
|---|
| 946 |         }
 | 
|---|
| 947 | 
 | 
|---|
| 948 | 
 | 
|---|
| 949 |         ZERO_STRUCT(result);
 | 
|---|
| 950 |         result.tctx = tctx;
 | 
|---|
| 951 |         
 | 
|---|
| 952 |         status = multiple_search(cli, tctx, BASEDIR "\\*.*", 
 | 
|---|
| 953 |                                  RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
 | 
|---|
| 954 |                                  CONT_NAME, &result);   
 | 
|---|
| 955 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 956 |         CHECK_VALUE(result.count, num_files);
 | 
|---|
| 957 | 
 | 
|---|
| 958 |         for (i=0;i<num_files-1;i++) {
 | 
|---|
| 959 |                 const char *name1, *name2;
 | 
|---|
| 960 |                 name1 = result.list[i].both_directory_info.name.s;
 | 
|---|
| 961 |                 name2 = result.list[i+1].both_directory_info.name.s;
 | 
|---|
| 962 |                 if (strcasecmp_m(name1, name2) > 0) {
 | 
|---|
| 963 |                         printf("non-alphabetical order at entry %d  '%s' '%s'\n", 
 | 
|---|
| 964 |                                i, name1, name2);
 | 
|---|
| 965 |                         printf("Server does not produce sorted directory listings (not an error)\n");
 | 
|---|
| 966 |                         goto done;
 | 
|---|
| 967 |                 }
 | 
|---|
| 968 |         }
 | 
|---|
| 969 | 
 | 
|---|
| 970 |         talloc_free(result.list);
 | 
|---|
| 971 | 
 | 
|---|
| 972 | done:
 | 
|---|
| 973 |         smb_raw_exit(cli->session);
 | 
|---|
| 974 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 975 | 
 | 
|---|
| 976 |         return ret;
 | 
|---|
| 977 | }
 | 
|---|
| 978 | 
 | 
|---|
| 979 | 
 | 
|---|
| 980 | 
 | 
|---|
| 981 | /* 
 | 
|---|
| 982 |    basic testing of many old style search calls using separate dirs
 | 
|---|
| 983 | */
 | 
|---|
| 984 | static bool test_many_dirs(struct torture_context *tctx, 
 | 
|---|
| 985 |                                                    struct smbcli_state *cli)
 | 
|---|
| 986 | {
 | 
|---|
| 987 |         const int num_dirs = 20;
 | 
|---|
| 988 |         int i, fnum, n;
 | 
|---|
| 989 |         char *fname, *dname;
 | 
|---|
| 990 |         bool ret = true;
 | 
|---|
| 991 |         NTSTATUS status;
 | 
|---|
| 992 |         union smb_search_data *file, *file2, *file3;
 | 
|---|
| 993 | 
 | 
|---|
| 994 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 995 |                 return false;
 | 
|---|
| 996 |         }
 | 
|---|
| 997 | 
 | 
|---|
| 998 |         printf("Creating %d dirs\n", num_dirs);
 | 
|---|
| 999 | 
 | 
|---|
| 1000 |         for (i=0;i<num_dirs;i++) {
 | 
|---|
| 1001 |                 dname = talloc_asprintf(cli, BASEDIR "\\d%d", i);
 | 
|---|
| 1002 |                 status = smbcli_mkdir(cli->tree, dname);
 | 
|---|
| 1003 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 1004 |                         printf("(%s) Failed to create %s - %s\n", 
 | 
|---|
| 1005 |                                __location__, dname, nt_errstr(status));
 | 
|---|
| 1006 |                         ret = false;
 | 
|---|
| 1007 |                         goto done;
 | 
|---|
| 1008 |                 }
 | 
|---|
| 1009 | 
 | 
|---|
| 1010 |                 for (n=0;n<3;n++) {
 | 
|---|
| 1011 |                         fname = talloc_asprintf(cli, BASEDIR "\\d%d\\f%d-%d.txt", i, i, n);
 | 
|---|
| 1012 |                         fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 1013 |                         if (fnum == -1) {
 | 
|---|
| 1014 |                                 printf("(%s) Failed to create %s - %s\n", 
 | 
|---|
| 1015 |                                        __location__, fname, smbcli_errstr(cli->tree));
 | 
|---|
| 1016 |                                 ret = false;
 | 
|---|
| 1017 |                                 goto done;
 | 
|---|
| 1018 |                         }
 | 
|---|
| 1019 |                         talloc_free(fname);
 | 
|---|
| 1020 |                         smbcli_close(cli->tree, fnum);
 | 
|---|
| 1021 |                 }
 | 
|---|
| 1022 | 
 | 
|---|
| 1023 |                 talloc_free(dname);
 | 
|---|
| 1024 |         }
 | 
|---|
| 1025 | 
 | 
|---|
| 1026 |         file  = talloc_zero_array(tctx, union smb_search_data, num_dirs);
 | 
|---|
| 1027 |         file2 = talloc_zero_array(tctx, union smb_search_data, num_dirs);
 | 
|---|
| 1028 |         file3 = talloc_zero_array(tctx, union smb_search_data, num_dirs);
 | 
|---|
| 1029 | 
 | 
|---|
| 1030 |         printf("Search first on %d dirs\n", num_dirs);
 | 
|---|
| 1031 | 
 | 
|---|
| 1032 |         for (i=0;i<num_dirs;i++) {
 | 
|---|
| 1033 |                 union smb_search_first io;
 | 
|---|
| 1034 |                 io.search_first.level = RAW_SEARCH_SEARCH;
 | 
|---|
| 1035 |                 io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 1036 |                 io.search_first.in.max_count = 1;
 | 
|---|
| 1037 |                 io.search_first.in.search_attrib = 0;
 | 
|---|
| 1038 |                 io.search_first.in.pattern = talloc_asprintf(tctx, BASEDIR "\\d%d\\*.txt", i);
 | 
|---|
| 1039 |                 fname = talloc_asprintf(tctx, "f%d-", i);
 | 
|---|
| 1040 | 
 | 
|---|
| 1041 |                 io.search_first.out.count = 0;
 | 
|---|
| 1042 | 
 | 
|---|
| 1043 |                 status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 1044 |                                               &io, (void *)&file[i], single_search_callback);
 | 
|---|
| 1045 |                 if (io.search_first.out.count != 1) {
 | 
|---|
| 1046 |                         printf("(%s) search first gave %d entries for dir %d - %s\n",
 | 
|---|
| 1047 |                                __location__, io.search_first.out.count, i, nt_errstr(status));
 | 
|---|
| 1048 |                         ret = false;
 | 
|---|
| 1049 |                         goto done;
 | 
|---|
| 1050 |                 }
 | 
|---|
| 1051 |                 CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1052 |                 if (strncasecmp(file[i].search.name, fname, strlen(fname)) != 0) {
 | 
|---|
| 1053 |                         printf("(%s) incorrect name '%s' expected '%s'[12].txt\n", 
 | 
|---|
| 1054 |                                __location__, file[i].search.name, fname);
 | 
|---|
| 1055 |                         ret = false;
 | 
|---|
| 1056 |                         goto done;
 | 
|---|
| 1057 |                 }
 | 
|---|
| 1058 | 
 | 
|---|
| 1059 |                 talloc_free(fname);
 | 
|---|
| 1060 |         }
 | 
|---|
| 1061 | 
 | 
|---|
| 1062 |         printf("Search next on %d dirs\n", num_dirs);
 | 
|---|
| 1063 | 
 | 
|---|
| 1064 |         for (i=0;i<num_dirs;i++) {
 | 
|---|
| 1065 |                 union smb_search_next io2;
 | 
|---|
| 1066 | 
 | 
|---|
| 1067 |                 io2.search_next.level = RAW_SEARCH_SEARCH;
 | 
|---|
| 1068 |                 io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 1069 |                 io2.search_next.in.max_count = 1;
 | 
|---|
| 1070 |                 io2.search_next.in.search_attrib = 0;
 | 
|---|
| 1071 |                 io2.search_next.in.id = file[i].search.id;
 | 
|---|
| 1072 |                 fname = talloc_asprintf(tctx, "f%d-", i);
 | 
|---|
| 1073 | 
 | 
|---|
| 1074 |                 io2.search_next.out.count = 0;
 | 
|---|
| 1075 | 
 | 
|---|
| 1076 |                 status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 1077 |                                              &io2, (void *)&file2[i], single_search_callback);
 | 
|---|
| 1078 |                 if (io2.search_next.out.count != 1) {
 | 
|---|
| 1079 |                         printf("(%s) search next gave %d entries for dir %d - %s\n",
 | 
|---|
| 1080 |                                __location__, io2.search_next.out.count, i, nt_errstr(status));
 | 
|---|
| 1081 |                         ret = false;
 | 
|---|
| 1082 |                         goto done;
 | 
|---|
| 1083 |                 }
 | 
|---|
| 1084 |                 CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1085 |                 if (strncasecmp(file2[i].search.name, fname, strlen(fname)) != 0) {
 | 
|---|
| 1086 |                         printf("(%s) incorrect name '%s' expected '%s'[12].txt\n", 
 | 
|---|
| 1087 |                                __location__, file2[i].search.name, fname);
 | 
|---|
| 1088 |                         ret = false;
 | 
|---|
| 1089 |                         goto done;
 | 
|---|
| 1090 |                 }
 | 
|---|
| 1091 | 
 | 
|---|
| 1092 |                 talloc_free(fname);
 | 
|---|
| 1093 |         }
 | 
|---|
| 1094 | 
 | 
|---|
| 1095 | 
 | 
|---|
| 1096 |         printf("Search next (rewind) on %d dirs\n", num_dirs);
 | 
|---|
| 1097 | 
 | 
|---|
| 1098 |         for (i=0;i<num_dirs;i++) {
 | 
|---|
| 1099 |                 union smb_search_next io2;
 | 
|---|
| 1100 | 
 | 
|---|
| 1101 |                 io2.search_next.level = RAW_SEARCH_SEARCH;
 | 
|---|
| 1102 |                 io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
 | 
|---|
| 1103 |                 io2.search_next.in.max_count = 1;
 | 
|---|
| 1104 |                 io2.search_next.in.search_attrib = 0;
 | 
|---|
| 1105 |                 io2.search_next.in.id = file[i].search.id;
 | 
|---|
| 1106 |                 fname = talloc_asprintf(tctx, "f%d-", i);
 | 
|---|
| 1107 |                 io2.search_next.out.count = 0;
 | 
|---|
| 1108 | 
 | 
|---|
| 1109 |                 status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 1110 |                                              &io2, (void *)&file3[i], single_search_callback);
 | 
|---|
| 1111 |                 if (io2.search_next.out.count != 1) {
 | 
|---|
| 1112 |                         printf("(%s) search next gave %d entries for dir %d - %s\n",
 | 
|---|
| 1113 |                                __location__, io2.search_next.out.count, i, nt_errstr(status));
 | 
|---|
| 1114 |                         ret = false;
 | 
|---|
| 1115 |                         goto done;
 | 
|---|
| 1116 |                 }
 | 
|---|
| 1117 |                 CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1118 | 
 | 
|---|
| 1119 |                 if (strncasecmp(file3[i].search.name, file2[i].search.name, 3) != 0) {
 | 
|---|
| 1120 |                         printf("(%s) incorrect name '%s' on rewind at dir %d\n", 
 | 
|---|
| 1121 |                                __location__, file2[i].search.name, i);
 | 
|---|
| 1122 |                         ret = false;
 | 
|---|
| 1123 |                         goto done;
 | 
|---|
| 1124 |                 }
 | 
|---|
| 1125 | 
 | 
|---|
| 1126 |                 if (strcmp(file3[i].search.name, file2[i].search.name) != 0) {
 | 
|---|
| 1127 |                         printf("(%s) server did not rewind - got '%s' expected '%s'\n", 
 | 
|---|
| 1128 |                                __location__, file3[i].search.name, file2[i].search.name);
 | 
|---|
| 1129 |                         ret = false;
 | 
|---|
| 1130 |                         goto done;
 | 
|---|
| 1131 |                 }
 | 
|---|
| 1132 | 
 | 
|---|
| 1133 |                 talloc_free(fname);
 | 
|---|
| 1134 |         }
 | 
|---|
| 1135 | 
 | 
|---|
| 1136 | 
 | 
|---|
| 1137 | done:
 | 
|---|
| 1138 |         smb_raw_exit(cli->session);
 | 
|---|
| 1139 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 1140 | 
 | 
|---|
| 1141 |         return ret;
 | 
|---|
| 1142 | }
 | 
|---|
| 1143 | 
 | 
|---|
| 1144 | 
 | 
|---|
| 1145 | /* 
 | 
|---|
| 1146 |    testing of OS/2 style delete
 | 
|---|
| 1147 | */
 | 
|---|
| 1148 | static bool test_os2_delete(struct torture_context *tctx, 
 | 
|---|
| 1149 |                                                         struct smbcli_state *cli)
 | 
|---|
| 1150 | {
 | 
|---|
| 1151 |         const int num_files = 700;
 | 
|---|
| 1152 |         const int delete_count = 4;
 | 
|---|
| 1153 |         int total_deleted = 0;
 | 
|---|
| 1154 |         int i, fnum;
 | 
|---|
| 1155 |         char *fname;
 | 
|---|
| 1156 |         bool ret = true;
 | 
|---|
| 1157 |         NTSTATUS status;
 | 
|---|
| 1158 |         union smb_search_first io;
 | 
|---|
| 1159 |         union smb_search_next io2;
 | 
|---|
| 1160 |         struct multiple_result result;
 | 
|---|
| 1161 | 
 | 
|---|
| 1162 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 1163 |                 return false;
 | 
|---|
| 1164 |         }
 | 
|---|
| 1165 | 
 | 
|---|
| 1166 |         printf("Testing OS/2 style delete on %d files\n", num_files);
 | 
|---|
| 1167 | 
 | 
|---|
| 1168 |         for (i=0;i<num_files;i++) {
 | 
|---|
| 1169 |                 fname = talloc_asprintf(cli, BASEDIR "\\file%u.txt", i);
 | 
|---|
| 1170 |                 fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 1171 |                 if (fnum == -1) {
 | 
|---|
| 1172 |                         printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
 | 
|---|
| 1173 |                         ret = false;
 | 
|---|
| 1174 |                         goto done;
 | 
|---|
| 1175 |                 }
 | 
|---|
| 1176 |                 talloc_free(fname);
 | 
|---|
| 1177 |                 smbcli_close(cli->tree, fnum);
 | 
|---|
| 1178 |         }
 | 
|---|
| 1179 | 
 | 
|---|
| 1180 | 
 | 
|---|
| 1181 |         ZERO_STRUCT(result);
 | 
|---|
| 1182 |         result.tctx = tctx;
 | 
|---|
| 1183 | 
 | 
|---|
| 1184 |         io.t2ffirst.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 1185 |         io.t2ffirst.data_level = RAW_SEARCH_DATA_EA_SIZE;
 | 
|---|
| 1186 |         io.t2ffirst.in.search_attrib = 0;
 | 
|---|
| 1187 |         io.t2ffirst.in.max_count = 100;
 | 
|---|
| 1188 |         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
 | 
|---|
| 1189 |         io.t2ffirst.in.storage_type = 0;
 | 
|---|
| 1190 |         io.t2ffirst.in.pattern = BASEDIR "\\*";
 | 
|---|
| 1191 | 
 | 
|---|
| 1192 |         status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 1193 |                                       &io, &result, multiple_search_callback);
 | 
|---|
| 1194 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1195 | 
 | 
|---|
| 1196 |         for (i=0;i<MIN(result.count, delete_count);i++) {
 | 
|---|
| 1197 |                 fname = talloc_asprintf(cli, BASEDIR "\\%s", result.list[i].ea_size.name.s);
 | 
|---|
| 1198 |                 status = smbcli_unlink(cli->tree, fname);
 | 
|---|
| 1199 |                 CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1200 |                 total_deleted++;
 | 
|---|
| 1201 |                 talloc_free(fname);
 | 
|---|
| 1202 |         }
 | 
|---|
| 1203 | 
 | 
|---|
| 1204 |         io2.t2fnext.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 1205 |         io2.t2fnext.data_level = RAW_SEARCH_DATA_EA_SIZE;
 | 
|---|
| 1206 |         io2.t2fnext.in.handle = io.t2ffirst.out.handle;
 | 
|---|
| 1207 |         io2.t2fnext.in.max_count = 100;
 | 
|---|
| 1208 |         io2.t2fnext.in.resume_key = result.list[i-1].ea_size.resume_key;
 | 
|---|
| 1209 |         io2.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
 | 
|---|
| 1210 |         io2.t2fnext.in.last_name = result.list[i-1].ea_size.name.s;
 | 
|---|
| 1211 | 
 | 
|---|
| 1212 |         do {
 | 
|---|
| 1213 |                 ZERO_STRUCT(result);
 | 
|---|
| 1214 |                 result.tctx = tctx;
 | 
|---|
| 1215 | 
 | 
|---|
| 1216 |                 status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 1217 |                                              &io2, &result, multiple_search_callback);
 | 
|---|
| 1218 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 1219 |                         break;
 | 
|---|
| 1220 |                 }
 | 
|---|
| 1221 | 
 | 
|---|
| 1222 |                 for (i=0;i<MIN(result.count, delete_count);i++) {
 | 
|---|
| 1223 |                         fname = talloc_asprintf(cli, BASEDIR "\\%s", result.list[i].ea_size.name.s);
 | 
|---|
| 1224 |                         status = smbcli_unlink(cli->tree, fname);
 | 
|---|
| 1225 |                         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1226 |                         total_deleted++;
 | 
|---|
| 1227 |                         talloc_free(fname);
 | 
|---|
| 1228 |                 }
 | 
|---|
| 1229 | 
 | 
|---|
| 1230 |                 if (i>0) {
 | 
|---|
| 1231 |                         io2.t2fnext.in.resume_key = result.list[i-1].ea_size.resume_key;
 | 
|---|
| 1232 |                         io2.t2fnext.in.last_name = result.list[i-1].ea_size.name.s;
 | 
|---|
| 1233 |                 }
 | 
|---|
| 1234 |         } while (NT_STATUS_IS_OK(status) && result.count != 0);
 | 
|---|
| 1235 | 
 | 
|---|
| 1236 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1237 | 
 | 
|---|
| 1238 |         if (total_deleted != num_files) {
 | 
|---|
| 1239 |                 printf("error: deleted %d - expected to delete %d\n", 
 | 
|---|
| 1240 |                        total_deleted, num_files);
 | 
|---|
| 1241 |                 ret = false;
 | 
|---|
| 1242 |         }
 | 
|---|
| 1243 | 
 | 
|---|
| 1244 | done:
 | 
|---|
| 1245 |         smb_raw_exit(cli->session);
 | 
|---|
| 1246 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 1247 | 
 | 
|---|
| 1248 |         return ret;
 | 
|---|
| 1249 | }
 | 
|---|
| 1250 | 
 | 
|---|
| 1251 | 
 | 
|---|
| 1252 | static int ealist_cmp(union smb_search_data *r1, union smb_search_data *r2)
 | 
|---|
| 1253 | {
 | 
|---|
| 1254 |         return strcmp(r1->ea_list.name.s, r2->ea_list.name.s);
 | 
|---|
| 1255 | }
 | 
|---|
| 1256 | 
 | 
|---|
| 1257 | /* 
 | 
|---|
| 1258 |    testing of the rather strange ea_list level
 | 
|---|
| 1259 | */
 | 
|---|
| 1260 | static bool test_ea_list(struct torture_context *tctx, 
 | 
|---|
| 1261 |                                                  struct smbcli_state *cli)
 | 
|---|
| 1262 | {
 | 
|---|
| 1263 |         int  fnum;
 | 
|---|
| 1264 |         bool ret = true;
 | 
|---|
| 1265 |         NTSTATUS status;
 | 
|---|
| 1266 |         union smb_search_first io;
 | 
|---|
| 1267 |         union smb_search_next nxt;
 | 
|---|
| 1268 |         struct multiple_result result;
 | 
|---|
| 1269 |         union smb_setfileinfo setfile;
 | 
|---|
| 1270 | 
 | 
|---|
| 1271 |         if (!torture_setup_dir(cli, BASEDIR)) {
 | 
|---|
| 1272 |                 return false;
 | 
|---|
| 1273 |         }
 | 
|---|
| 1274 | 
 | 
|---|
| 1275 |         printf("Testing RAW_SEARCH_EA_LIST level\n");
 | 
|---|
| 1276 | 
 | 
|---|
| 1277 |         fnum = smbcli_open(cli->tree, BASEDIR "\\file1.txt", O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 1278 |         smbcli_close(cli->tree, fnum);
 | 
|---|
| 1279 | 
 | 
|---|
| 1280 |         fnum = smbcli_open(cli->tree, BASEDIR "\\file2.txt", O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 1281 |         smbcli_close(cli->tree, fnum);
 | 
|---|
| 1282 | 
 | 
|---|
| 1283 |         fnum = smbcli_open(cli->tree, BASEDIR "\\file3.txt", O_CREAT|O_RDWR, DENY_NONE);
 | 
|---|
| 1284 |         smbcli_close(cli->tree, fnum);
 | 
|---|
| 1285 | 
 | 
|---|
| 1286 |         setfile.generic.level = RAW_SFILEINFO_EA_SET;
 | 
|---|
| 1287 |         setfile.generic.in.file.path = BASEDIR "\\file2.txt";
 | 
|---|
| 1288 |         setfile.ea_set.in.num_eas = 2;
 | 
|---|
| 1289 |         setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
 | 
|---|
| 1290 |         setfile.ea_set.in.eas[0].flags = 0;
 | 
|---|
| 1291 |         setfile.ea_set.in.eas[0].name.s = "EA ONE";
 | 
|---|
| 1292 |         setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE 1");
 | 
|---|
| 1293 |         setfile.ea_set.in.eas[1].flags = 0;
 | 
|---|
| 1294 |         setfile.ea_set.in.eas[1].name.s = "SECOND EA";
 | 
|---|
| 1295 |         setfile.ea_set.in.eas[1].value = data_blob_string_const("Value Two");
 | 
|---|
| 1296 | 
 | 
|---|
| 1297 |         status = smb_raw_setpathinfo(cli->tree, &setfile);
 | 
|---|
| 1298 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1299 | 
 | 
|---|
| 1300 |         setfile.generic.in.file.path = BASEDIR "\\file3.txt";
 | 
|---|
| 1301 |         status = smb_raw_setpathinfo(cli->tree, &setfile);
 | 
|---|
| 1302 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1303 |         
 | 
|---|
| 1304 |         ZERO_STRUCT(result);
 | 
|---|
| 1305 |         result.tctx = tctx;
 | 
|---|
| 1306 | 
 | 
|---|
| 1307 |         io.t2ffirst.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 1308 |         io.t2ffirst.data_level = RAW_SEARCH_DATA_EA_LIST;
 | 
|---|
| 1309 |         io.t2ffirst.in.search_attrib = 0;
 | 
|---|
| 1310 |         io.t2ffirst.in.max_count = 2;
 | 
|---|
| 1311 |         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
 | 
|---|
| 1312 |         io.t2ffirst.in.storage_type = 0;
 | 
|---|
| 1313 |         io.t2ffirst.in.pattern = BASEDIR "\\*";
 | 
|---|
| 1314 |         io.t2ffirst.in.num_names = 2;
 | 
|---|
| 1315 |         io.t2ffirst.in.ea_names = talloc_array(tctx, struct ea_name, 2);
 | 
|---|
| 1316 |         io.t2ffirst.in.ea_names[0].name.s = "SECOND EA";
 | 
|---|
| 1317 |         io.t2ffirst.in.ea_names[1].name.s = "THIRD EA";
 | 
|---|
| 1318 | 
 | 
|---|
| 1319 |         status = smb_raw_search_first(cli->tree, tctx,
 | 
|---|
| 1320 |                                       &io, &result, multiple_search_callback);
 | 
|---|
| 1321 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1322 |         CHECK_VALUE(result.count, 2);
 | 
|---|
| 1323 | 
 | 
|---|
| 1324 |         nxt.t2fnext.level = RAW_SEARCH_TRANS2;
 | 
|---|
| 1325 |         nxt.t2fnext.data_level = RAW_SEARCH_DATA_EA_LIST;
 | 
|---|
| 1326 |         nxt.t2fnext.in.handle = io.t2ffirst.out.handle;
 | 
|---|
| 1327 |         nxt.t2fnext.in.max_count = 2;
 | 
|---|
| 1328 |         nxt.t2fnext.in.resume_key = result.list[1].ea_list.resume_key;
 | 
|---|
| 1329 |         nxt.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME | FLAG_TRANS2_FIND_CONTINUE;
 | 
|---|
| 1330 |         nxt.t2fnext.in.last_name = result.list[1].ea_list.name.s;
 | 
|---|
| 1331 |         nxt.t2fnext.in.num_names = 2;
 | 
|---|
| 1332 |         nxt.t2fnext.in.ea_names = talloc_array(tctx, struct ea_name, 2);
 | 
|---|
| 1333 |         nxt.t2fnext.in.ea_names[0].name.s = "SECOND EA";
 | 
|---|
| 1334 |         nxt.t2fnext.in.ea_names[1].name.s = "THIRD EA";
 | 
|---|
| 1335 | 
 | 
|---|
| 1336 |         status = smb_raw_search_next(cli->tree, tctx,
 | 
|---|
| 1337 |                                      &nxt, &result, multiple_search_callback);
 | 
|---|
| 1338 |         CHECK_STATUS(status, NT_STATUS_OK);
 | 
|---|
| 1339 | 
 | 
|---|
| 1340 |         /* we have to sort the result as different servers can return directories
 | 
|---|
| 1341 |            in different orders */
 | 
|---|
| 1342 |         qsort(result.list, result.count, sizeof(result.list[0]), 
 | 
|---|
| 1343 |               (comparison_fn_t)ealist_cmp);
 | 
|---|
| 1344 | 
 | 
|---|
| 1345 |         CHECK_VALUE(result.count, 3);
 | 
|---|
| 1346 |         CHECK_VALUE(result.list[0].ea_list.eas.num_eas, 2);
 | 
|---|
| 1347 |         CHECK_STRING(result.list[0].ea_list.name.s, "file1.txt");
 | 
|---|
| 1348 |         CHECK_STRING(result.list[0].ea_list.eas.eas[0].name.s, "SECOND EA");
 | 
|---|
| 1349 |         CHECK_VALUE(result.list[0].ea_list.eas.eas[0].value.length, 0);
 | 
|---|
| 1350 |         CHECK_STRING(result.list[0].ea_list.eas.eas[1].name.s, "THIRD EA");
 | 
|---|
| 1351 |         CHECK_VALUE(result.list[0].ea_list.eas.eas[1].value.length, 0);
 | 
|---|
| 1352 | 
 | 
|---|
| 1353 |         CHECK_STRING(result.list[1].ea_list.name.s, "file2.txt");
 | 
|---|
| 1354 |         CHECK_STRING(result.list[1].ea_list.eas.eas[0].name.s, "SECOND EA");
 | 
|---|
| 1355 |         CHECK_VALUE(result.list[1].ea_list.eas.eas[0].value.length, 9);
 | 
|---|
| 1356 |         CHECK_STRING((const char *)result.list[1].ea_list.eas.eas[0].value.data, "Value Two");
 | 
|---|
| 1357 |         CHECK_STRING(result.list[1].ea_list.eas.eas[1].name.s, "THIRD EA");
 | 
|---|
| 1358 |         CHECK_VALUE(result.list[1].ea_list.eas.eas[1].value.length, 0);
 | 
|---|
| 1359 | 
 | 
|---|
| 1360 |         CHECK_STRING(result.list[2].ea_list.name.s, "file3.txt");
 | 
|---|
| 1361 |         CHECK_STRING(result.list[2].ea_list.eas.eas[0].name.s, "SECOND EA");
 | 
|---|
| 1362 |         CHECK_VALUE(result.list[2].ea_list.eas.eas[0].value.length, 9);
 | 
|---|
| 1363 |         CHECK_STRING((const char *)result.list[2].ea_list.eas.eas[0].value.data, "Value Two");
 | 
|---|
| 1364 |         CHECK_STRING(result.list[2].ea_list.eas.eas[1].name.s, "THIRD EA");
 | 
|---|
| 1365 |         CHECK_VALUE(result.list[2].ea_list.eas.eas[1].value.length, 0);
 | 
|---|
| 1366 | 
 | 
|---|
| 1367 |         smb_raw_exit(cli->session);
 | 
|---|
| 1368 |         smbcli_deltree(cli->tree, BASEDIR);
 | 
|---|
| 1369 | 
 | 
|---|
| 1370 |         return ret;
 | 
|---|
| 1371 | }
 | 
|---|
| 1372 | 
 | 
|---|
| 1373 | 
 | 
|---|
| 1374 | 
 | 
|---|
| 1375 | /* 
 | 
|---|
| 1376 |    basic testing of all RAW_SEARCH_* calls using a single file
 | 
|---|
| 1377 | */
 | 
|---|
| 1378 | struct torture_suite *torture_raw_search(TALLOC_CTX *mem_ctx)
 | 
|---|
| 1379 | {
 | 
|---|
| 1380 |         struct torture_suite *suite = torture_suite_create(mem_ctx, "SEARCH");
 | 
|---|
| 1381 | 
 | 
|---|
| 1382 |         torture_suite_add_1smb_test(suite, "one file search", test_one_file);
 | 
|---|
| 1383 |         torture_suite_add_1smb_test(suite, "many files", test_many_files);
 | 
|---|
| 1384 |         torture_suite_add_1smb_test(suite, "sorted", test_sorted);
 | 
|---|
| 1385 |         torture_suite_add_1smb_test(suite, "modify search", test_modify_search);
 | 
|---|
| 1386 |         torture_suite_add_1smb_test(suite, "many dirs", test_many_dirs);
 | 
|---|
| 1387 |         torture_suite_add_1smb_test(suite, "os2 delete", test_os2_delete);
 | 
|---|
| 1388 |         torture_suite_add_1smb_test(suite, "ea list", test_ea_list);
 | 
|---|
| 1389 | 
 | 
|---|
| 1390 |         return suite;
 | 
|---|
| 1391 | }
 | 
|---|