2 Unix SMB/CIFS implementation.
4 SMB2 dir list test suite
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Zachary Loafman 2009
8 Copyright (C) Aravind Srinivasan 2009
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.
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.
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/>.
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"
32 #include "torture/torture.h"
33 #include "torture/smb2/proto.h"
34 #include "torture/util.h"
36 #include "system/filesys.h"
37 #include "lib/util/tsort.h"
39 #define DNAME "smb2_dir"
47 static NTSTATUS
populate_tree(struct torture_context
*tctx
,
49 struct smb2_tree
*tree
,
50 struct file_elem
*files
,
52 struct smb2_handle
*h_out
)
54 struct smb2_create create
;
60 smb2_deltree(tree
, DNAME
);
63 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
64 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
65 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
66 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
67 NTCREATEX_SHARE_ACCESS_WRITE
|
68 NTCREATEX_SHARE_ACCESS_DELETE
;
69 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
70 create
.in
.fname
= DNAME
;
72 status
= smb2_create(tree
, mem_ctx
, &create
);
73 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
74 *h_out
= create
.out
.file
.handle
;
77 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
78 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
79 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
81 strs
= generate_unique_strs(mem_ctx
, 8, nfiles
);
83 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
86 for (i
= 0; i
< nfiles
; i
++) {
87 files
[i
].name
= strs
[i
];
88 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
89 DNAME
, files
[i
].name
);
90 status
= smb2_create(tree
, mem_ctx
, &create
);
91 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
92 smb2_util_close(tree
, create
.out
.file
.handle
);
102 static bool test_find(struct torture_context
*tctx
,
103 struct smb2_tree
*tree
)
105 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
106 struct smb2_handle h
;
108 union smb_search_data
*d
;
109 struct file_elem files
[NFILES
] = {};
113 int i
, j
, file_count
= 0;
115 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, NFILES
, &h
);
118 f
.in
.file
.handle
= h
;
120 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
121 f
.in
.max_response_size
= 0x100;
122 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
125 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
126 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
128 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
130 for (i
= 0; i
< count
; i
++) {
132 const char *found
= d
[i
].both_directory_info
.name
.s
;
134 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
138 for (j
= 0; j
< NFILES
; j
++) {
139 if (!strcmp(files
[j
].name
, found
)) {
140 files
[j
].found
= true;
149 torture_result(tctx
, TORTURE_FAIL
,
150 "(%s): didn't expect %s\n",
151 __location__
, found
);
156 file_count
= file_count
+ i
;
157 f
.in
.continue_flags
= 0;
158 f
.in
.max_response_size
= 4096;
159 } while (count
!= 0);
161 torture_assert_int_equal_goto(tctx
, file_count
, NFILES
+ 2, ret
, done
,
164 for (i
= 0; i
< NFILES
; i
++) {
168 torture_result(tctx
, TORTURE_FAIL
,
169 "(%s): expected to find %s, but didn't\n",
170 __location__
, files
[j
].name
);
176 smb2_deltree(tree
, DNAME
);
177 talloc_free(mem_ctx
);
183 test fixed enumeration
186 static bool test_fixed(struct torture_context
*tctx
,
187 struct smb2_tree
*tree
)
189 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
190 struct smb2_create create
;
191 struct smb2_handle h
, h2
;
193 union smb_search_data
*d
;
194 struct file_elem files
[NFILES
] = {};
200 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, NFILES
, &h
);
203 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
204 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
205 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
206 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
207 NTCREATEX_SHARE_ACCESS_WRITE
|
208 NTCREATEX_SHARE_ACCESS_DELETE
;
209 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
210 create
.in
.fname
= DNAME
;
212 status
= smb2_create(tree
, mem_ctx
, &create
);
213 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
214 h2
= create
.out
.file
.handle
;
217 f
.in
.file
.handle
= h
;
219 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
220 f
.in
.max_response_size
= 0x100;
221 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
223 /* Start enumeration on h, then delete all from h2 */
224 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
225 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
227 f
.in
.file
.handle
= h2
;
230 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
231 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
233 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
235 for (i
= 0; i
< count
; i
++) {
236 const char *found
= d
[i
].both_directory_info
.name
.s
;
237 char *path
= talloc_asprintf(mem_ctx
, "%s\\%s",
240 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
243 status
= smb2_util_unlink(tree
, path
);
244 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
250 f
.in
.continue_flags
= 0;
251 f
.in
.max_response_size
= 4096;
252 } while (count
!= 0);
254 /* Now finish h enumeration. */
255 f
.in
.file
.handle
= h
;
258 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
259 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
261 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
263 for (i
= 0; i
< count
; i
++) {
264 const char *found
= d
[i
].both_directory_info
.name
.s
;
266 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
269 torture_result(tctx
, TORTURE_FAIL
,
270 "(%s): didn't expect %s (count=%u)\n",
271 __location__
, found
, count
);
276 f
.in
.continue_flags
= 0;
277 f
.in
.max_response_size
= 4096;
278 } while (count
!= 0);
281 smb2_util_close(tree
, h
);
282 smb2_util_close(tree
, h2
);
283 smb2_deltree(tree
, DNAME
);
284 talloc_free(mem_ctx
);
292 enum smb_search_data_level data_level
;
294 int resume_key_offset
;
295 uint32_t capability_mask
;
297 union smb_search_data data
;
299 {"SMB2_FIND_DIRECTORY_INFO",
300 SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
,
301 offsetof(union smb_search_data
, directory_info
.name
.s
),
302 offsetof(union smb_search_data
, directory_info
.file_index
),
304 {"SMB2_FIND_FULL_DIRECTORY_INFO",
305 SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
,
306 offsetof(union smb_search_data
, full_directory_info
.name
.s
),
307 offsetof(union smb_search_data
, full_directory_info
.file_index
),
309 {"SMB2_FIND_NAME_INFO",
310 SMB2_FIND_NAME_INFO
, RAW_SEARCH_DATA_NAME_INFO
,
311 offsetof(union smb_search_data
, name_info
.name
.s
),
312 offsetof(union smb_search_data
, name_info
.file_index
),
314 {"SMB2_FIND_BOTH_DIRECTORY_INFO",
315 SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
316 offsetof(union smb_search_data
, both_directory_info
.name
.s
),
317 offsetof(union smb_search_data
, both_directory_info
.file_index
),
319 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO",
320 SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
,
321 offsetof(union smb_search_data
, id_full_directory_info
.name
.s
),
322 offsetof(union smb_search_data
, id_full_directory_info
.file_index
),
324 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO",
325 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
,
326 offsetof(union smb_search_data
, id_both_directory_info
.name
.s
),
327 offsetof(union smb_search_data
, id_both_directory_info
.file_index
),
332 extract the name from a smb_data structure and level
334 static const char *extract_name(union smb_search_data
*data
,
336 enum smb_search_data_level data_level
)
339 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
340 if (level
== levels
[i
].level
&&
341 data_level
== levels
[i
].data_level
) {
342 return *(const char **)(levels
[i
].name_offset
+ (char *)data
);
348 /* find a level in the table by name */
349 static union smb_search_data
*find(const char *name
)
352 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
353 if (NT_STATUS_IS_OK(levels
[i
].status
) &&
354 strcmp(levels
[i
].name
, name
) == 0) {
355 return &levels
[i
].data
;
361 static bool fill_level_data(TALLOC_CTX
*mem_ctx
,
362 union smb_search_data
*data
,
363 union smb_search_data
*d
,
366 enum smb_search_data_level data_level
)
369 const char *sname
= NULL
;
370 for (i
=0; i
< count
; i
++) {
371 sname
= extract_name(&d
[i
], level
, data_level
);
374 if (!strcmp(sname
, ".") || !strcmp(sname
, ".."))
382 NTSTATUS
torture_single_file_search(struct smb2_tree
*tree
,
386 enum smb_search_data_level data_level
,
388 union smb_search_data
*d
,
390 struct smb2_handle
*h
)
396 f
.in
.file
.handle
= *h
;
397 f
.in
.pattern
= pattern
;
398 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
399 f
.in
.max_response_size
= 0x100;
402 status
= smb2_find_level(tree
, tree
, &f
, count
, &d
);
403 if (NT_STATUS_IS_OK(status
))
404 fill_level_data(mem_ctx
, &levels
[idx
].data
, d
, *count
, level
,
410 basic testing of all File Information Classes using a single file
412 static bool test_one_file(struct torture_context
*tctx
,
413 struct smb2_tree
*tree
)
415 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
417 const char *fname
= "torture_search.txt";
421 union smb_fileinfo all_info2
, alt_info
, internal_info
;
422 union smb_search_data
*s
;
423 union smb_search_data d
;
424 struct smb2_handle h
, h2
;
426 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
427 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
429 status
= smb2_create_complex_file(tree
, DNAME
"\\torture_search.txt",
431 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
433 /* call all the File Information Classes */
434 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
435 torture_comment(tctx
, "Testing %s %d\n", levels
[i
].name
,
438 levels
[i
].status
= torture_single_file_search(tree
, mem_ctx
,
439 fname
, levels
[i
].level
, levels
[i
].data_level
,
441 torture_assert_ntstatus_ok_goto(tctx
, levels
[i
].status
, ret
,
445 /* get the all_info file into to check against */
446 all_info2
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
447 all_info2
.generic
.in
.file
.handle
= h2
;
448 status
= smb2_getinfo_file(tree
, tctx
, &all_info2
);
449 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
450 "RAW_FILEINFO_ALL_INFO failed");
452 alt_info
.generic
.level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
453 alt_info
.generic
.in
.file
.handle
= h2
;
454 status
= smb2_getinfo_file(tree
, tctx
, &alt_info
);
455 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
456 "RAW_FILEINFO_ALT_NAME_INFO failed");
458 internal_info
.generic
.level
= RAW_FILEINFO_INTERNAL_INFORMATION
;
459 internal_info
.generic
.in
.file
.handle
= h2
;
460 status
= smb2_getinfo_file(tree
, tctx
, &internal_info
);
461 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
462 "RAW_FILEINFO_INTERNAL_INFORMATION "
465 #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
468 if ((s->sname1.field1) != (v.sname2.out.field2)) { \
469 torture_result(tctx, TORTURE_FAIL, \
470 "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
472 #sname1, #field1, (int)s->sname1.field1, \
473 #sname2, #field2, (int)v.sname2.out.field2); \
478 #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
481 if (s->sname1.field1 != \
482 (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
483 torture_result(tctx, TORTURE_FAIL, \
484 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
487 timestring(tctx, s->sname1.field1), \
489 nt_time_string(tctx, v.sname2.out.field2)); \
494 #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
497 if (s->sname1.field1 != v.sname2.out.field2) { \
498 torture_result(tctx, TORTURE_FAIL, \
499 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
502 nt_time_string(tctx, s->sname1.field1), \
504 nt_time_string(tctx, v.sname2.out.field2)); \
509 #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
512 if (!s->sname1.field1 || \
513 strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
514 torture_result(tctx, TORTURE_FAIL, \
515 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
517 #sname1, #field1, s->sname1.field1, \
518 #sname2, #field2, v.sname2.out.field2.s); \
523 #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
526 if (!s->sname1.field1.s || \
527 strcmp(s->sname1.field1.s, v.sname2.out.field2.s)) { \
528 torture_result(tctx, TORTURE_FAIL, \
529 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
531 #sname1, #field1, s->sname1.field1.s, \
532 #sname2, #field2, v.sname2.out.field2.s); \
537 #define CHECK_NAME(name, sname1, field1, fname, flags) do { \
540 if (!s->sname1.field1.s || \
541 strcmp(s->sname1.field1.s, fname)) { \
542 torture_result(tctx, TORTURE_FAIL, \
543 "(%s) %s/%s [%s] != %s\n", \
545 #sname1, #field1, s->sname1.field1.s, fname); \
550 #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
553 if (!s->sname1.field1 || \
554 strcmp(s->sname1.field1, fname)) { \
555 torture_result(tctx, TORTURE_FAIL, \
556 "(%s) %s/%s [%s] != %s\n", \
558 #sname1, #field1, s->sname1.field1, fname); \
563 /* check that all the results are as expected */
564 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, attrib
, all_info2
, all_info2
, attrib
);
565 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
566 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
567 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
568 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
570 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, write_time
, all_info2
, all_info2
, write_time
);
571 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
572 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
573 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
574 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
576 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, create_time
, all_info2
, all_info2
, create_time
);
577 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
578 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
579 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
580 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
582 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, access_time
, all_info2
, all_info2
, access_time
);
583 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
584 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
585 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
586 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
588 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, change_time
, all_info2
, all_info2
, change_time
);
589 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
590 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
591 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
592 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
594 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, size
, all_info2
, all_info2
, size
);
595 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, size
, all_info2
, all_info2
, size
);
596 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, size
, all_info2
, all_info2
, size
);
597 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, size
, all_info2
, all_info2
, size
);
598 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, size
, all_info2
, all_info2
, size
);
600 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
601 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
602 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
603 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
604 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
606 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
607 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
608 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
609 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
611 CHECK_NAME("SMB2_FIND_DIRECTORY_INFO", directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
612 CHECK_NAME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
613 CHECK_NAME("SMB2_FIND_NAME_INFO", name_info
, name
, fname
, STR_TERMINATE_ASCII
);
614 CHECK_NAME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
615 CHECK_NAME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
616 CHECK_NAME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
618 CHECK_WSTR("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, short_name
, alt_info
, alt_name_info
, fname
, STR_UNICODE
);
620 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, file_id
, internal_info
, internal_information
, file_id
);
621 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, file_id
, internal_info
, internal_information
, file_id
);
624 smb2_util_close(tree
, h
);
625 smb2_util_unlink(tree
, fname
);
626 talloc_free(mem_ctx
);
632 struct multiple_result
{
635 union smb_search_data
*list
;
638 bool fill_result(void *private_data
,
639 union smb_search_data
*file
,
642 enum smb_search_data_level data_level
)
646 struct multiple_result
*data
= (struct multiple_result
*)private_data
;
648 for (i
=0; i
<count
; i
++) {
649 sname
= extract_name(&file
[i
], level
, data_level
);
650 if (!strcmp(sname
, ".") || !(strcmp(sname
, "..")))
653 data
->list
= talloc_realloc(data
->tctx
,
655 union smb_search_data
,
657 data
->list
[data
->count
-1] = file
[i
];
662 enum continue_type
{CONT_SINGLE
, CONT_INDEX
, CONT_RESTART
};
664 static NTSTATUS
multiple_smb2_search(struct smb2_tree
*tree
,
668 enum smb_search_data_level data_level
,
669 enum continue_type cont_type
,
671 struct smb2_handle
*h
)
675 unsigned int count
= 0;
676 union smb_search_data
*d
;
678 struct multiple_result
*result
= (struct multiple_result
*)data
;
681 f
.in
.file
.handle
= *h
;
682 f
.in
.pattern
= pattern
;
683 f
.in
.max_response_size
= 0x1000;
686 /* The search should start from the beginning everytime */
687 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
690 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
691 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
693 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
694 if (!fill_result(result
, d
, count
, level
, data_level
)) {
695 return NT_STATUS_UNSUCCESSFUL
;
699 * After the first iteration is complete set the CONTINUE
700 * FLAGS appropriately
704 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_INDEX
;
707 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
711 /* we should prevent staying in the loop
713 f
.in
.continue_flags
= 0;
716 } while (count
!= 0);
722 static enum smb_search_data_level compare_data_level
;
725 static int search_compare(union smb_search_data
*d1
,
726 union smb_search_data
*d2
)
730 s1
= extract_name(d1
, level_sort
, compare_data_level
);
731 s2
= extract_name(d2
, level_sort
, compare_data_level
);
732 return strcmp_safe(s1
, s2
);
736 basic testing of search calls using many files
738 static bool test_many_files(struct torture_context
*tctx
,
739 struct smb2_tree
*tree
)
741 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
742 const int num_files
= 700;
747 struct multiple_result result
;
748 struct smb2_create create
;
749 struct smb2_handle h
;
752 const char *cont_name
;
754 enum smb_search_data_level data_level
;
755 enum continue_type cont_type
;
757 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_SINGLE
},
758 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_INDEX
},
759 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_RESTART
},
760 {"SMB2_FIND_DIRECTORY_INFO", "SINGLE", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_SINGLE
},
761 {"SMB2_FIND_DIRECTORY_INFO", "INDEX", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_INDEX
},
762 {"SMB2_FIND_DIRECTORY_INFO", "RESTART", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_RESTART
},
763 {"SMB2_FIND_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_SINGLE
},
764 {"SMB2_FIND_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_INDEX
},
765 {"SMB2_FIND_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_RESTART
},
766 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_SINGLE
},
767 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_INDEX
},
768 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_RESTART
},
769 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_SINGLE
},
770 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_INDEX
},
771 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_RESTART
}
774 smb2_deltree(tree
, DNAME
);
775 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
776 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
778 torture_comment(tctx
, "Testing with %d files\n", num_files
);
780 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
781 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
782 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
784 for (i
=num_files
-1;i
>=0;i
--) {
785 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\t%03d-%d.txt", i
, i
);
786 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s", fname
);
787 status
= smb2_create(tree
, mem_ctx
, &create
);
788 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
789 smb2_util_close(tree
, create
.out
.file
.handle
);
793 for (t
=0;t
<ARRAY_SIZE(search_types
);t
++) {
795 result
.tctx
= talloc_new(tctx
);
797 torture_comment(tctx
,
798 "Continue %s via %s\n", search_types
[t
].name
,
799 search_types
[t
].cont_name
);
800 status
= multiple_smb2_search(tree
, tctx
, "*",
801 search_types
[t
].level
,
802 search_types
[t
].data_level
,
803 search_types
[t
].cont_type
,
806 torture_assert_int_equal_goto(tctx
, result
.count
, num_files
,
809 compare_data_level
= search_types
[t
].data_level
;
810 level_sort
= search_types
[t
].level
;
812 TYPESAFE_QSORT(result
.list
, result
.count
, search_compare
);
814 for (i
=0;i
<result
.count
;i
++) {
816 enum smb_search_level level
;
817 level
= RAW_SEARCH_SMB2
;
818 s
= extract_name(&result
.list
[i
],
819 search_types
[t
].level
,
821 fname
= talloc_asprintf(mem_ctx
, "t%03d-%d.txt", i
, i
);
822 torture_assert_str_equal_goto(tctx
, s
, fname
, ret
,
823 done
, "Incorrect name");
826 talloc_free(result
.tctx
);
830 smb2_util_close(tree
, h
);
831 smb2_deltree(tree
, DNAME
);
832 talloc_free(mem_ctx
);
838 check an individual file result
840 static bool check_result(struct torture_context
*tctx
,
841 struct multiple_result
*result
,
847 for (i
=0;i
<result
->count
;i
++) {
849 result
->list
[i
].both_directory_info
.name
.s
) == 0) {
853 if (i
== result
->count
) {
855 torture_result(tctx
, TORTURE_FAIL
,
856 "failed: '%s' should exist with attribute %s\n",
857 name
, attrib_string(result
->list
, attrib
));
864 torture_result(tctx
, TORTURE_FAIL
,
865 "failed: '%s' should NOT exist (has attribute %s)\n",
866 name
, attrib_string(result
->list
,
867 result
->list
[i
].both_directory_info
.attrib
));
871 if ((result
->list
[i
].both_directory_info
.attrib
&0xFFF) != attrib
) {
872 torture_result(tctx
, TORTURE_FAIL
,
873 "failed: '%s' should have attribute 0x%x (has 0x%x)\n",
874 name
, attrib
, result
->list
[i
].both_directory_info
.attrib
);
881 test what happens when the directory is modified during a search
883 static bool test_modify_search(struct torture_context
*tctx
,
884 struct smb2_tree
*tree
)
887 struct multiple_result result
;
888 union smb_setfileinfo sfinfo
;
889 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
890 struct smb2_create create
;
891 struct smb2_handle h
;
893 union smb_search_data
*d
;
894 struct file_elem files
[700] = {};
900 smb2_deltree(tree
, DNAME
);
902 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
903 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
905 torture_comment(tctx
, "Creating %d files\n", num_files
);
908 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
909 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
910 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
912 for (i
= num_files
-1; i
>= 0; i
--) {
913 files
[i
].name
= talloc_asprintf(mem_ctx
, "t%03d-%d.txt", i
, i
);
914 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
915 DNAME
, files
[i
].name
);
916 status
= smb2_create(tree
, mem_ctx
, &create
);
917 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
918 smb2_util_close(tree
, create
.out
.file
.handle
);
921 torture_comment(tctx
, "pulling the first two files\n");
923 result
.tctx
= talloc_new(tctx
);
926 f
.in
.file
.handle
= h
;
928 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
929 f
.in
.max_response_size
= 0x100;
930 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
933 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
934 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
936 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
937 if (!fill_result(&result
, d
, count
, f
.in
.level
,
938 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
)) {
942 } while (result
.count
< 2);
944 torture_comment(tctx
, "Changing attributes and deleting\n");
947 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
948 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
949 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
951 files
[num_files
].name
= talloc_asprintf(mem_ctx
, "T003-03.txt.2");
952 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s", DNAME
,
953 files
[num_files
].name
);
954 status
= smb2_create(tree
, mem_ctx
, &create
);
955 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
956 smb2_util_close(tree
, create
.out
.file
.handle
);
959 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
960 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
961 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
963 files
[num_files
+ 1].name
= talloc_asprintf(mem_ctx
, "T013-13.txt.2");
964 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s", DNAME
,
965 files
[num_files
+ 1].name
);
966 status
= smb2_create(tree
, mem_ctx
, &create
);
967 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
968 smb2_util_close(tree
, create
.out
.file
.handle
);
970 files
[num_files
+ 2].name
= talloc_asprintf(mem_ctx
, "T013-13.txt.3");
971 status
= smb2_create_complex_file(tree
, DNAME
"\\T013-13.txt.3", &h
);
972 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
974 smb2_util_unlink(tree
, DNAME
"\\T014-14.txt");
975 smb2_util_setatr(tree
, DNAME
"\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN
);
976 smb2_util_setatr(tree
, DNAME
"\\T016-16.txt", FILE_ATTRIBUTE_NORMAL
);
977 smb2_util_setatr(tree
, DNAME
"\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM
);
978 smb2_util_setatr(tree
, DNAME
"\\T018-18.txt", 0);
979 smb2_util_setatr(tree
, DNAME
"\\T039-39.txt", FILE_ATTRIBUTE_HIDDEN
);
980 smb2_util_setatr(tree
, DNAME
"\\T000-0.txt", FILE_ATTRIBUTE_HIDDEN
);
981 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
982 sfinfo
.generic
.in
.file
.path
= DNAME
"\\T013-13.txt.3";
983 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
984 status
= smb2_composite_setpathinfo(tree
, &sfinfo
);
985 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
987 /* Reset the numfiles to include the new files and start the
988 * search from the beginning */
989 num_files
= num_files
+ 2;
991 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
995 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
996 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
998 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
999 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1000 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
)) {
1004 f
.in
.continue_flags
= 0;
1005 f
.in
.max_response_size
= 4096;
1006 } while (count
!= 0);
1009 ret
&= check_result(tctx
, &result
, "t039-39.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1010 ret
&= check_result(tctx
, &result
, "t000-0.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1011 ret
&= check_result(tctx
, &result
, "t014-14.txt", false, 0);
1012 ret
&= check_result(tctx
, &result
, "t015-15.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1013 ret
&= check_result(tctx
, &result
, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL
);
1014 ret
&= check_result(tctx
, &result
, "t017-17.txt", true, FILE_ATTRIBUTE_SYSTEM
);
1015 ret
&= check_result(tctx
, &result
, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE
);
1016 ret
&= check_result(tctx
, &result
, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE
);
1017 ret
&= check_result(tctx
, &result
, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE
);
1018 ret
&= check_result(tctx
, &result
, "T003-3.txt.2", false, 0);
1019 ret
&= check_result(tctx
, &result
, "T013-13.txt.3", true, FILE_ATTRIBUTE_NORMAL
);
1022 for (i
=0;i
<result
.count
;i
++) {
1023 torture_warning(tctx
, "%s %s (0x%x)\n",
1024 result
.list
[i
].both_directory_info
.name
.s
,
1026 result
.list
[i
].both_directory_info
.attrib
),
1027 result
.list
[i
].both_directory_info
.attrib
);
1031 smb2_util_close(tree
, h
);
1032 smb2_deltree(tree
, DNAME
);
1033 talloc_free(mem_ctx
);
1039 testing if directories always come back sorted
1041 static bool test_sorted(struct torture_context
*tctx
,
1042 struct smb2_tree
*tree
)
1044 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1045 const int num_files
= 700;
1047 struct file_elem files
[700] = {};
1050 struct multiple_result result
;
1051 struct smb2_handle h
;
1053 torture_comment(tctx
, "Testing if directories always come back "
1055 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, num_files
, &h
);
1056 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1058 ZERO_STRUCT(result
);
1061 status
= multiple_smb2_search(tree
, tctx
, "*",
1062 SMB2_FIND_BOTH_DIRECTORY_INFO
,
1063 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
1064 SMB2_CONTINUE_FLAG_SINGLE
,
1067 torture_assert_int_equal_goto(tctx
, result
.count
, num_files
, ret
, done
,
1070 for (i
=0;i
<num_files
-1;i
++) {
1071 const char *name1
, *name2
;
1072 name1
= result
.list
[i
].both_directory_info
.name
.s
;
1073 name2
= result
.list
[i
+1].both_directory_info
.name
.s
;
1074 if (strcasecmp_m(name1
, name2
) > 0) {
1075 torture_comment(tctx
, "non-alphabetical order at entry "
1076 "%d '%s' '%s'\n", i
, name1
, name2
);
1077 torture_comment(tctx
,
1078 "Server does not produce sorted directory listings"
1079 "(not an error)\n");
1083 talloc_free(result
.list
);
1085 smb2_util_close(tree
, h
);
1086 smb2_deltree(tree
, DNAME
);
1087 talloc_free(mem_ctx
);
1092 /* test the behavior of file_index field in the SMB2_FIND struct */
1093 static bool test_file_index(struct torture_context
*tctx
,
1094 struct smb2_tree
*tree
)
1096 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1097 const int num_files
= 100;
1098 int resume_index
= 4;
1103 struct multiple_result result
;
1104 struct smb2_create create
;
1106 struct smb2_handle h
;
1107 union smb_search_data
*d
;
1110 smb2_deltree(tree
, DNAME
);
1112 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1113 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1115 torture_comment(tctx
, "Testing the behavior of file_index flag\n");
1117 ZERO_STRUCT(create
);
1118 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1119 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1120 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1121 for (i
= num_files
-1; i
>= 0; i
--) {
1122 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\file%u.txt", i
);
1123 create
.in
.fname
= fname
;
1124 status
= smb2_create(tree
, mem_ctx
, &create
);
1125 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1127 smb2_util_close(tree
, create
.out
.file
.handle
);
1130 ZERO_STRUCT(result
);
1134 f
.in
.file
.handle
= h
;
1136 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
1137 f
.in
.max_response_size
= 0x1000;
1138 f
.in
.level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
1141 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1142 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1144 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1145 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1146 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
)) {
1150 } while(result
.count
< 10);
1152 if (result
.list
[0].full_directory_info
.file_index
== 0) {
1153 torture_skip_goto(tctx
, done
,
1154 "Talking to a server that doesn't provide a "
1155 "file index.\nWindows servers using NTFS do "
1156 "not provide a file_index. Skipping test\n");
1158 /* We are not talking to a Windows based server. Windows
1159 * servers using NTFS do not provide a file_index. Windows
1160 * servers using FAT do provide a file index, however in both
1161 * cases they do not honor a file index on a resume request.
1162 * See MS-FSCC <62> and MS-SMB2 <54> for more information. */
1164 /* Set the file_index flag to point to the fifth file from the
1165 * previous enumeration and try to start the subsequent
1166 * searches from that point */
1168 result
.list
[resume_index
].full_directory_info
.file_index
;
1169 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_INDEX
;
1171 /* get the name of the next expected file */
1172 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\%s",
1173 result
.list
[resume_index
].full_directory_info
.name
.s
);
1175 ZERO_STRUCT(result
);
1177 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1178 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1180 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1181 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1182 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
)) {
1187 result
.list
[0].full_directory_info
.name
.s
)) {
1188 torture_comment(tctx
, "Next expected file: %s but the "
1189 "server returned %s\n", fname
,
1190 result
.list
[0].full_directory_info
.name
.s
);
1191 torture_comment(tctx
,
1192 "Not an error. Resuming using a file "
1193 "index is an optional feature of the "
1199 smb2_util_close(tree
, h
);
1200 smb2_deltree(tree
, DNAME
);
1201 talloc_free(mem_ctx
);
1207 * Tests directory enumeration in a directory containing >1000 files with
1208 * names of varying lengths.
1210 static bool test_large_files(struct torture_context
*tctx
,
1211 struct smb2_tree
*tree
)
1213 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1214 const int num_files
= 2000;
1216 /* These should be evenly divisible */
1217 int num_at_len
= num_files
/ max_len
;
1218 struct file_elem files
[2000] = {};
1222 struct smb2_create create
;
1224 struct smb2_handle h
;
1225 union smb_search_data
*d
;
1226 int i
, j
, file_count
= 0;
1230 torture_comment(tctx
,
1231 "Testing directory enumeration in a directory with >1000 files\n");
1233 smb2_deltree(tree
, DNAME
);
1235 ZERO_STRUCT(create
);
1236 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
1237 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1238 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1239 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1240 NTCREATEX_SHARE_ACCESS_WRITE
|
1241 NTCREATEX_SHARE_ACCESS_DELETE
;
1242 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1243 create
.in
.fname
= DNAME
;
1245 status
= smb2_create(tree
, mem_ctx
, &create
);
1246 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1247 h
= create
.out
.file
.handle
;
1249 ZERO_STRUCT(create
);
1250 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1251 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1252 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1254 for (i
= 0; i
< num_files
; i
++) {
1255 if (i
% num_at_len
== 0) {
1256 strs
= generate_unique_strs(mem_ctx
, len
, num_at_len
);
1259 files
[i
].name
= strs
[i
% num_at_len
];
1260 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
1261 DNAME
, files
[i
].name
);
1262 status
= smb2_create(tree
, mem_ctx
, &create
);
1263 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1264 smb2_util_close(tree
, create
.out
.file
.handle
);
1268 f
.in
.file
.handle
= h
;
1270 f
.in
.max_response_size
= 0x100;
1271 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
1274 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1275 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1277 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1279 for (i
= 0; i
< count
; i
++) {
1281 const char *found
= d
[i
].both_directory_info
.name
.s
;
1283 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
1287 for (j
= 0; j
< 2000; j
++) {
1288 if (!strcmp(files
[j
].name
, found
)) {
1289 files
[j
].found
= true;
1298 torture_result(tctx
, TORTURE_FAIL
,
1299 "(%s): didn't expect %s\n",
1300 __location__
, found
);
1304 file_count
= file_count
+ i
;
1305 f
.in
.continue_flags
= 0;
1306 f
.in
.max_response_size
= 4096;
1307 } while (count
!= 0);
1309 torture_assert_int_equal_goto(tctx
, file_count
, num_files
+ 2, ret
,
1312 for (i
= 0; i
< num_files
; i
++) {
1316 torture_result(tctx
, TORTURE_FAIL
,
1317 "(%s): expected to find %s, but didn't\n",
1318 __location__
, files
[j
].name
);
1323 smb2_util_close(tree
, h
);
1324 smb2_deltree(tree
, DNAME
);
1325 talloc_free(mem_ctx
);
1330 struct torture_suite
*torture_smb2_dir_init(void)
1332 struct torture_suite
*suite
=
1333 torture_suite_create(talloc_autofree_context(), "DIR");
1335 torture_suite_add_1smb2_test(suite
, "FIND", test_find
);
1336 torture_suite_add_1smb2_test(suite
, "FIXED", test_fixed
);
1337 torture_suite_add_1smb2_test(suite
, "ONE", test_one_file
);
1338 torture_suite_add_1smb2_test(suite
, "MANY", test_many_files
);
1339 torture_suite_add_1smb2_test(suite
, "MODIFY", test_modify_search
);
1340 torture_suite_add_1smb2_test(suite
, "SORTED", test_sorted
);
1341 torture_suite_add_1smb2_test(suite
, "FILE-INDEX", test_file_index
);
1342 torture_suite_add_1smb2_test(suite
, "LARGE-FILES", test_large_files
);
1343 suite
->description
= talloc_strdup(suite
, "SMB2-DIR tests");