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"
48 static NTSTATUS
populate_tree(struct torture_context
*tctx
,
50 struct smb2_tree
*tree
,
51 struct file_elem
*files
,
53 struct smb2_handle
*h_out
)
55 struct smb2_create create
;
61 smb2_deltree(tree
, DNAME
);
64 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
65 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
66 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
67 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
68 NTCREATEX_SHARE_ACCESS_WRITE
|
69 NTCREATEX_SHARE_ACCESS_DELETE
;
70 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
71 create
.in
.fname
= DNAME
;
73 status
= smb2_create(tree
, mem_ctx
, &create
);
74 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
75 *h_out
= create
.out
.file
.handle
;
78 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
79 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
80 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
82 strs
= generate_unique_strs(mem_ctx
, 8, nfiles
);
84 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
87 for (i
= 0; i
< nfiles
; i
++) {
88 files
[i
].name
= strs
[i
];
89 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
90 DNAME
, files
[i
].name
);
91 status
= smb2_create(tree
, mem_ctx
, &create
);
92 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
93 files
[i
].create_time
= create
.out
.create_time
;
94 smb2_util_close(tree
, create
.out
.file
.handle
);
108 static bool test_find(struct torture_context
*tctx
,
109 struct smb2_tree
*tree
)
111 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
112 struct smb2_handle h
;
114 union smb_search_data
*d
;
115 struct file_elem files
[NFILES
] = {};
119 int i
, j
, file_count
= 0;
121 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, NFILES
, &h
);
124 f
.in
.file
.handle
= h
;
126 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
127 f
.in
.max_response_size
= 0x100;
128 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
131 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
132 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
134 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
136 for (i
= 0; i
< count
; i
++) {
138 const char *found
= d
[i
].both_directory_info
.name
.s
;
139 NTTIME ct
= d
[i
].both_directory_info
.create_time
;
141 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
145 for (j
= 0; j
< NFILES
; j
++) {
146 if (strcmp(files
[j
].name
, found
) != 0) {
150 torture_assert_u64_equal_goto(tctx
,
151 files
[j
].create_time
,
153 talloc_asprintf(tctx
,
156 files
[j
].found
= true;
164 torture_result(tctx
, TORTURE_FAIL
,
165 "(%s): didn't expect %s\n",
166 __location__
, found
);
171 file_count
= file_count
+ i
;
172 f
.in
.continue_flags
= 0;
173 f
.in
.max_response_size
= 4096;
174 } while (count
!= 0);
176 torture_assert_int_equal_goto(tctx
, file_count
, NFILES
+ 2, ret
, done
,
179 for (i
= 0; i
< NFILES
; i
++) {
183 torture_result(tctx
, TORTURE_FAIL
,
184 "(%s): expected to find %s, but didn't\n",
185 __location__
, files
[j
].name
);
191 smb2_deltree(tree
, DNAME
);
192 talloc_free(mem_ctx
);
198 test fixed enumeration
201 static bool test_fixed(struct torture_context
*tctx
,
202 struct smb2_tree
*tree
)
204 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
205 struct smb2_create create
;
206 struct smb2_handle h
, h2
;
208 union smb_search_data
*d
;
209 struct file_elem files
[NFILES
] = {};
215 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, NFILES
, &h
);
218 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
219 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
220 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
221 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
222 NTCREATEX_SHARE_ACCESS_WRITE
|
223 NTCREATEX_SHARE_ACCESS_DELETE
;
224 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
225 create
.in
.fname
= DNAME
;
227 status
= smb2_create(tree
, mem_ctx
, &create
);
228 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
229 h2
= create
.out
.file
.handle
;
232 f
.in
.file
.handle
= h
;
234 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
235 f
.in
.max_response_size
= 0x100;
236 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
238 /* Start enumeration on h, then delete all from h2 */
239 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
240 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
242 f
.in
.file
.handle
= h2
;
245 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
246 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
248 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
250 for (i
= 0; i
< count
; i
++) {
251 const char *found
= d
[i
].both_directory_info
.name
.s
;
252 char *path
= talloc_asprintf(mem_ctx
, "%s\\%s",
255 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
258 status
= smb2_util_unlink(tree
, path
);
259 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
265 f
.in
.continue_flags
= 0;
266 f
.in
.max_response_size
= 4096;
267 } while (count
!= 0);
269 /* Now finish h enumeration. */
270 f
.in
.file
.handle
= h
;
273 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
274 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
276 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
278 for (i
= 0; i
< count
; i
++) {
279 const char *found
= d
[i
].both_directory_info
.name
.s
;
281 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
284 torture_result(tctx
, TORTURE_FAIL
,
285 "(%s): didn't expect %s (count=%u)\n",
286 __location__
, found
, count
);
291 f
.in
.continue_flags
= 0;
292 f
.in
.max_response_size
= 4096;
293 } while (count
!= 0);
296 smb2_util_close(tree
, h
);
297 smb2_util_close(tree
, h2
);
298 smb2_deltree(tree
, DNAME
);
299 talloc_free(mem_ctx
);
307 enum smb_search_data_level data_level
;
309 int resume_key_offset
;
310 uint32_t capability_mask
;
312 union smb_search_data data
;
314 {"SMB2_FIND_DIRECTORY_INFO",
315 SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
,
316 offsetof(union smb_search_data
, directory_info
.name
.s
),
317 offsetof(union smb_search_data
, directory_info
.file_index
),
319 {"SMB2_FIND_FULL_DIRECTORY_INFO",
320 SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
,
321 offsetof(union smb_search_data
, full_directory_info
.name
.s
),
322 offsetof(union smb_search_data
, full_directory_info
.file_index
),
324 {"SMB2_FIND_NAME_INFO",
325 SMB2_FIND_NAME_INFO
, RAW_SEARCH_DATA_NAME_INFO
,
326 offsetof(union smb_search_data
, name_info
.name
.s
),
327 offsetof(union smb_search_data
, name_info
.file_index
),
329 {"SMB2_FIND_BOTH_DIRECTORY_INFO",
330 SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
331 offsetof(union smb_search_data
, both_directory_info
.name
.s
),
332 offsetof(union smb_search_data
, both_directory_info
.file_index
),
334 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO",
335 SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
,
336 offsetof(union smb_search_data
, id_full_directory_info
.name
.s
),
337 offsetof(union smb_search_data
, id_full_directory_info
.file_index
),
339 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO",
340 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
,
341 offsetof(union smb_search_data
, id_both_directory_info
.name
.s
),
342 offsetof(union smb_search_data
, id_both_directory_info
.file_index
),
347 extract the name from a smb_data structure and level
349 static const char *extract_name(union smb_search_data
*data
,
351 enum smb_search_data_level data_level
)
354 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
355 if (level
== levels
[i
].level
&&
356 data_level
== levels
[i
].data_level
) {
357 return *(const char **)(levels
[i
].name_offset
+ (char *)data
);
363 /* find a level in the table by name */
364 static union smb_search_data
*find(const char *name
)
367 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
368 if (NT_STATUS_IS_OK(levels
[i
].status
) &&
369 strcmp(levels
[i
].name
, name
) == 0) {
370 return &levels
[i
].data
;
376 static bool fill_level_data(TALLOC_CTX
*mem_ctx
,
377 union smb_search_data
*data
,
378 union smb_search_data
*d
,
381 enum smb_search_data_level data_level
)
384 const char *sname
= NULL
;
385 for (i
=0; i
< count
; i
++) {
386 sname
= extract_name(&d
[i
], level
, data_level
);
389 if (!strcmp(sname
, ".") || !strcmp(sname
, ".."))
397 NTSTATUS
torture_single_file_search(struct smb2_tree
*tree
,
401 enum smb_search_data_level data_level
,
403 union smb_search_data
*d
,
405 struct smb2_handle
*h
)
411 f
.in
.file
.handle
= *h
;
412 f
.in
.pattern
= pattern
;
413 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
414 f
.in
.max_response_size
= 0x100;
417 status
= smb2_find_level(tree
, tree
, &f
, count
, &d
);
418 if (NT_STATUS_IS_OK(status
))
419 fill_level_data(mem_ctx
, &levels
[idx
].data
, d
, *count
, level
,
425 basic testing of all File Information Classes using a single file
427 static bool test_one_file(struct torture_context
*tctx
,
428 struct smb2_tree
*tree
)
430 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
432 const char *fname
= "torture_search.txt";
436 union smb_fileinfo all_info2
, alt_info
, internal_info
;
437 union smb_search_data
*s
;
438 union smb_search_data d
;
439 struct smb2_handle h
, h2
;
441 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
442 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
444 status
= smb2_create_complex_file(tree
, DNAME
"\\torture_search.txt",
446 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
448 /* call all the File Information Classes */
449 for (i
=0;i
<ARRAY_SIZE(levels
);i
++) {
450 torture_comment(tctx
, "Testing %s %d\n", levels
[i
].name
,
453 levels
[i
].status
= torture_single_file_search(tree
, mem_ctx
,
454 fname
, levels
[i
].level
, levels
[i
].data_level
,
456 torture_assert_ntstatus_ok_goto(tctx
, levels
[i
].status
, ret
,
460 /* get the all_info file into to check against */
461 all_info2
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
462 all_info2
.generic
.in
.file
.handle
= h2
;
463 status
= smb2_getinfo_file(tree
, tctx
, &all_info2
);
464 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
465 "RAW_FILEINFO_ALL_INFO failed");
467 alt_info
.generic
.level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
468 alt_info
.generic
.in
.file
.handle
= h2
;
469 status
= smb2_getinfo_file(tree
, tctx
, &alt_info
);
470 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
471 "RAW_FILEINFO_ALT_NAME_INFO failed");
473 internal_info
.generic
.level
= RAW_FILEINFO_INTERNAL_INFORMATION
;
474 internal_info
.generic
.in
.file
.handle
= h2
;
475 status
= smb2_getinfo_file(tree
, tctx
, &internal_info
);
476 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
477 "RAW_FILEINFO_INTERNAL_INFORMATION "
480 #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
483 if ((s->sname1.field1) != (v.sname2.out.field2)) { \
484 torture_result(tctx, TORTURE_FAIL, \
485 "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
487 #sname1, #field1, (int)s->sname1.field1, \
488 #sname2, #field2, (int)v.sname2.out.field2); \
493 #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
496 if (s->sname1.field1 != \
497 (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
498 torture_result(tctx, TORTURE_FAIL, \
499 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
502 timestring(tctx, s->sname1.field1), \
504 nt_time_string(tctx, v.sname2.out.field2)); \
509 #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
512 if (s->sname1.field1 != v.sname2.out.field2) { \
513 torture_result(tctx, TORTURE_FAIL, \
514 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
517 nt_time_string(tctx, s->sname1.field1), \
519 nt_time_string(tctx, v.sname2.out.field2)); \
524 #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
527 if (!s->sname1.field1 || \
528 strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
529 torture_result(tctx, TORTURE_FAIL, \
530 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
532 #sname1, #field1, s->sname1.field1, \
533 #sname2, #field2, v.sname2.out.field2.s); \
538 #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
541 if (!s->sname1.field1.s || \
542 strcmp(s->sname1.field1.s, v.sname2.out.field2.s)) { \
543 torture_result(tctx, TORTURE_FAIL, \
544 "(%s) %s/%s [%s] != %s/%s [%s]\n", \
546 #sname1, #field1, s->sname1.field1.s, \
547 #sname2, #field2, v.sname2.out.field2.s); \
552 #define CHECK_NAME(name, sname1, field1, fname, flags) do { \
555 if (!s->sname1.field1.s || \
556 strcmp(s->sname1.field1.s, fname)) { \
557 torture_result(tctx, TORTURE_FAIL, \
558 "(%s) %s/%s [%s] != %s\n", \
560 #sname1, #field1, s->sname1.field1.s, fname); \
565 #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
568 if (!s->sname1.field1 || \
569 strcmp(s->sname1.field1, fname)) { \
570 torture_result(tctx, TORTURE_FAIL, \
571 "(%s) %s/%s [%s] != %s\n", \
573 #sname1, #field1, s->sname1.field1, fname); \
578 /* check that all the results are as expected */
579 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, attrib
, all_info2
, all_info2
, attrib
);
580 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
581 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
582 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
583 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, attrib
, all_info2
, all_info2
, attrib
);
585 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, write_time
, all_info2
, all_info2
, write_time
);
586 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
587 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
588 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
589 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, write_time
, all_info2
, all_info2
, write_time
);
591 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, create_time
, all_info2
, all_info2
, create_time
);
592 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
593 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
594 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
595 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, create_time
, all_info2
, all_info2
, create_time
);
597 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, access_time
, all_info2
, all_info2
, access_time
);
598 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
599 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
600 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
601 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, access_time
, all_info2
, all_info2
, access_time
);
603 CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info
, change_time
, all_info2
, all_info2
, change_time
);
604 CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
605 CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
606 CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
607 CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, change_time
, all_info2
, all_info2
, change_time
);
609 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, size
, all_info2
, all_info2
, size
);
610 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, size
, all_info2
, all_info2
, size
);
611 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, size
, all_info2
, all_info2
, size
);
612 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, size
, all_info2
, all_info2
, size
);
613 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, size
, all_info2
, all_info2
, size
);
615 CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
616 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
617 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
618 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
619 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, alloc_size
, all_info2
, all_info2
, alloc_size
);
621 CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
622 CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
623 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
624 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, ea_size
, all_info2
, all_info2
, ea_size
);
626 CHECK_NAME("SMB2_FIND_DIRECTORY_INFO", directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
627 CHECK_NAME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
628 CHECK_NAME("SMB2_FIND_NAME_INFO", name_info
, name
, fname
, STR_TERMINATE_ASCII
);
629 CHECK_NAME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
630 CHECK_NAME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
631 CHECK_NAME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, name
, fname
, STR_TERMINATE_ASCII
);
633 CHECK_WSTR("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info
, short_name
, alt_info
, alt_name_info
, fname
, STR_UNICODE
);
635 CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info
, file_id
, internal_info
, internal_information
, file_id
);
636 CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info
, file_id
, internal_info
, internal_information
, file_id
);
639 smb2_util_close(tree
, h
);
640 smb2_util_unlink(tree
, fname
);
641 talloc_free(mem_ctx
);
647 struct multiple_result
{
650 union smb_search_data
*list
;
653 bool fill_result(void *private_data
,
654 union smb_search_data
*file
,
657 enum smb_search_data_level data_level
)
661 struct multiple_result
*data
= (struct multiple_result
*)private_data
;
663 for (i
=0; i
<count
; i
++) {
664 sname
= extract_name(&file
[i
], level
, data_level
);
665 if (!strcmp(sname
, ".") || !(strcmp(sname
, "..")))
668 data
->list
= talloc_realloc(data
->tctx
,
670 union smb_search_data
,
672 data
->list
[data
->count
-1] = file
[i
];
677 enum continue_type
{CONT_SINGLE
, CONT_INDEX
, CONT_RESTART
, CONT_REOPEN
};
679 static NTSTATUS
multiple_smb2_search(struct smb2_tree
*tree
,
683 enum smb_search_data_level data_level
,
684 enum continue_type cont_type
,
686 struct smb2_handle
*h
)
690 unsigned int count
= 0;
691 union smb_search_data
*d
;
693 struct multiple_result
*result
= (struct multiple_result
*)data
;
696 f
.in
.file
.handle
= *h
;
697 f
.in
.pattern
= pattern
;
698 f
.in
.max_response_size
= 0x1000;
701 /* The search should start from the beginning everytime */
702 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
703 if (cont_type
== CONT_REOPEN
) {
704 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_REOPEN
;
708 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
709 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
711 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
712 if (!fill_result(result
, d
, count
, level
, data_level
)) {
713 return NT_STATUS_UNSUCCESSFUL
;
716 if (count
== 0 || result
== NULL
|| result
->count
== 0) {
717 return NT_STATUS_UNSUCCESSFUL
;
721 * After the first iteration is complete set the CONTINUE
722 * FLAGS appropriately
726 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_INDEX
;
727 switch (data_level
) {
728 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
730 result
->list
[result
->count
-1].both_directory_info
.file_index
;
732 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
734 result
->list
[result
->count
-1].directory_info
.file_index
;
736 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
738 result
->list
[result
->count
-1].full_directory_info
.file_index
;
740 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
742 result
->list
[result
->count
-1].id_full_directory_info
.file_index
;
744 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
746 result
->list
[result
->count
-1].id_both_directory_info
.file_index
;
749 return NT_STATUS_INVALID_PARAMETER
;
753 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
757 /* we should prevent staying in the loop
759 f
.in
.continue_flags
= 0;
762 } while (count
!= 0);
771 static enum smb_search_data_level compare_data_level
;
774 static int search_compare(union smb_search_data
*d1
,
775 union smb_search_data
*d2
)
779 s1
= extract_name(d1
, level_sort
, compare_data_level
);
780 s2
= extract_name(d2
, level_sort
, compare_data_level
);
781 return strcmp_safe(s1
, s2
);
785 basic testing of search calls using many files
787 static bool test_many_files(struct torture_context
*tctx
,
788 struct smb2_tree
*tree
)
790 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
791 const int num_files
= 700;
796 struct multiple_result result
;
797 struct smb2_create create
;
798 struct smb2_handle h
;
801 const char *cont_name
;
803 enum smb_search_data_level data_level
;
804 enum continue_type cont_type
;
806 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_SINGLE
},
807 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_INDEX
},
808 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_RESTART
},
809 {"SMB2_FIND_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
, CONT_REOPEN
},
810 {"SMB2_FIND_DIRECTORY_INFO", "SINGLE", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_SINGLE
},
811 {"SMB2_FIND_DIRECTORY_INFO", "INDEX", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_INDEX
},
812 {"SMB2_FIND_DIRECTORY_INFO", "RESTART", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_RESTART
},
813 {"SMB2_FIND_DIRECTORY_INFO", "REOPEN", SMB2_FIND_DIRECTORY_INFO
, RAW_SEARCH_DATA_DIRECTORY_INFO
, CONT_REOPEN
},
814 {"SMB2_FIND_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_SINGLE
},
815 {"SMB2_FIND_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_INDEX
},
816 {"SMB2_FIND_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_RESTART
},
817 {"SMB2_FIND_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
, CONT_REOPEN
},
818 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_SINGLE
},
819 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_INDEX
},
820 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_RESTART
},
821 {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_FULL_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
, CONT_REOPEN
},
822 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_SINGLE
},
823 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_INDEX
},
824 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_RESTART
},
825 {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
, CONT_REOPEN
},
828 smb2_deltree(tree
, DNAME
);
829 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
830 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
832 torture_comment(tctx
, "Testing with %d files\n", num_files
);
834 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
835 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
836 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
838 for (i
=num_files
-1;i
>=0;i
--) {
839 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\t%03d-%d.txt", i
, i
);
840 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s", fname
);
841 status
= smb2_create(tree
, mem_ctx
, &create
);
842 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
843 smb2_util_close(tree
, create
.out
.file
.handle
);
847 for (t
=0;t
<ARRAY_SIZE(search_types
);t
++) {
849 result
.tctx
= talloc_new(tctx
);
851 torture_comment(tctx
,
852 "Continue %s via %s\n", search_types
[t
].name
,
853 search_types
[t
].cont_name
);
854 status
= multiple_smb2_search(tree
, tctx
, "*",
855 search_types
[t
].level
,
856 search_types
[t
].data_level
,
857 search_types
[t
].cont_type
,
860 torture_assert_int_equal_goto(tctx
, result
.count
, num_files
,
863 compare_data_level
= search_types
[t
].data_level
;
864 level_sort
= search_types
[t
].level
;
866 TYPESAFE_QSORT(result
.list
, result
.count
, search_compare
);
868 for (i
=0;i
<result
.count
;i
++) {
870 s
= extract_name(&result
.list
[i
],
871 search_types
[t
].level
,
873 fname
= talloc_asprintf(mem_ctx
, "t%03d-%d.txt", i
, i
);
874 torture_assert_str_equal_goto(tctx
, s
, fname
, ret
,
875 done
, "Incorrect name");
878 talloc_free(result
.tctx
);
882 smb2_util_close(tree
, h
);
883 smb2_deltree(tree
, DNAME
);
884 talloc_free(mem_ctx
);
890 check an individual file result
892 static bool check_result(struct torture_context
*tctx
,
893 struct multiple_result
*result
,
899 for (i
=0;i
<result
->count
;i
++) {
901 result
->list
[i
].both_directory_info
.name
.s
) == 0) {
905 if (i
== result
->count
) {
907 torture_result(tctx
, TORTURE_FAIL
,
908 "failed: '%s' should exist with attribute %s\n",
909 name
, attrib_string(result
->list
, attrib
));
916 torture_result(tctx
, TORTURE_FAIL
,
917 "failed: '%s' should NOT exist (has attribute %s)\n",
918 name
, attrib_string(result
->list
,
919 result
->list
[i
].both_directory_info
.attrib
));
923 if ((result
->list
[i
].both_directory_info
.attrib
&0xFFF) != attrib
) {
924 torture_result(tctx
, TORTURE_FAIL
,
925 "failed: '%s' should have attribute 0x%x (has 0x%x)\n",
926 name
, attrib
, result
->list
[i
].both_directory_info
.attrib
);
933 test what happens when the directory is modified during a search
935 static bool test_modify_search(struct torture_context
*tctx
,
936 struct smb2_tree
*tree
)
938 struct multiple_result result
;
939 union smb_setfileinfo sfinfo
;
940 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
941 struct smb2_create create
;
942 struct smb2_handle h
;
944 union smb_search_data
*d
;
945 struct file_elem files
[703] = {};
946 int num_files
= ARRAY_SIZE(files
)-3;
952 smb2_deltree(tree
, DNAME
);
954 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
955 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
957 torture_comment(tctx
, "Creating %d files\n", num_files
);
960 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
961 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
962 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
964 for (i
= num_files
-1; i
>= 0; i
--) {
965 files
[i
].name
= talloc_asprintf(mem_ctx
, "t%03d-%d.txt", i
, i
);
966 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
967 DNAME
, files
[i
].name
);
968 status
= smb2_create(tree
, mem_ctx
, &create
);
969 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
970 smb2_util_close(tree
, create
.out
.file
.handle
);
973 torture_comment(tctx
, "pulling the first two files\n");
975 result
.tctx
= talloc_new(tctx
);
978 f
.in
.file
.handle
= h
;
980 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
981 f
.in
.max_response_size
= 0x100;
982 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
985 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
986 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
988 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
989 if (!fill_result(&result
, d
, count
, f
.in
.level
,
990 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
)) {
994 } while (result
.count
< 2);
996 torture_comment(tctx
, "Changing attributes and deleting\n");
999 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1000 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1001 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1003 files
[num_files
].name
= talloc_asprintf(mem_ctx
, "T003-03.txt.2");
1004 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s", DNAME
,
1005 files
[num_files
].name
);
1006 status
= smb2_create(tree
, mem_ctx
, &create
);
1007 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1008 smb2_util_close(tree
, create
.out
.file
.handle
);
1010 ZERO_STRUCT(create
);
1011 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1012 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1013 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1015 files
[num_files
+ 1].name
= talloc_asprintf(mem_ctx
, "T013-13.txt.2");
1016 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s", DNAME
,
1017 files
[num_files
+ 1].name
);
1018 status
= smb2_create(tree
, mem_ctx
, &create
);
1019 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1020 smb2_util_close(tree
, create
.out
.file
.handle
);
1022 files
[num_files
+ 2].name
= talloc_asprintf(mem_ctx
, "T013-13.txt.3");
1023 status
= smb2_create_complex_file(tree
, DNAME
"\\T013-13.txt.3", &h
);
1024 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1026 smb2_util_unlink(tree
, DNAME
"\\T014-14.txt");
1027 smb2_util_setatr(tree
, DNAME
"\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN
);
1028 smb2_util_setatr(tree
, DNAME
"\\T016-16.txt", FILE_ATTRIBUTE_NORMAL
);
1029 smb2_util_setatr(tree
, DNAME
"\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM
);
1030 smb2_util_setatr(tree
, DNAME
"\\T018-18.txt", 0);
1031 smb2_util_setatr(tree
, DNAME
"\\T039-39.txt", FILE_ATTRIBUTE_HIDDEN
);
1032 smb2_util_setatr(tree
, DNAME
"\\T000-0.txt", FILE_ATTRIBUTE_HIDDEN
);
1033 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
1034 sfinfo
.generic
.in
.file
.path
= DNAME
"\\T013-13.txt.3";
1035 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
1036 status
= smb2_composite_setpathinfo(tree
, &sfinfo
);
1037 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1039 /* Reset the numfiles to include the new files and start the
1040 * search from the beginning */
1041 num_files
= num_files
+ 2;
1043 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
;
1047 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1048 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1050 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1051 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1052 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
)) {
1056 f
.in
.continue_flags
= 0;
1057 f
.in
.max_response_size
= 4096;
1058 } while (count
!= 0);
1061 ret
&= check_result(tctx
, &result
, "t039-39.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1062 ret
&= check_result(tctx
, &result
, "t000-0.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1063 ret
&= check_result(tctx
, &result
, "t014-14.txt", false, 0);
1064 ret
&= check_result(tctx
, &result
, "t015-15.txt", true, FILE_ATTRIBUTE_HIDDEN
);
1065 ret
&= check_result(tctx
, &result
, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL
);
1066 ret
&= check_result(tctx
, &result
, "t017-17.txt", true, FILE_ATTRIBUTE_SYSTEM
);
1067 ret
&= check_result(tctx
, &result
, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE
);
1068 ret
&= check_result(tctx
, &result
, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE
);
1069 ret
&= check_result(tctx
, &result
, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE
);
1070 ret
&= check_result(tctx
, &result
, "T003-3.txt.2", false, 0);
1071 ret
&= check_result(tctx
, &result
, "T013-13.txt.3", true, FILE_ATTRIBUTE_NORMAL
);
1074 for (i
=0;i
<result
.count
;i
++) {
1075 torture_warning(tctx
, "%s %s (0x%x)\n",
1076 result
.list
[i
].both_directory_info
.name
.s
,
1078 result
.list
[i
].both_directory_info
.attrib
),
1079 result
.list
[i
].both_directory_info
.attrib
);
1083 smb2_util_close(tree
, h
);
1084 smb2_deltree(tree
, DNAME
);
1085 talloc_free(mem_ctx
);
1091 testing if directories always come back sorted
1093 static bool test_sorted(struct torture_context
*tctx
,
1094 struct smb2_tree
*tree
)
1096 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1097 const int num_files
= 700;
1099 struct file_elem files
[700] = {};
1102 struct multiple_result result
;
1103 struct smb2_handle h
;
1105 torture_comment(tctx
, "Testing if directories always come back "
1107 status
= populate_tree(tctx
, mem_ctx
, tree
, files
, num_files
, &h
);
1108 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1110 ZERO_STRUCT(result
);
1113 status
= multiple_smb2_search(tree
, tctx
, "*",
1114 SMB2_FIND_BOTH_DIRECTORY_INFO
,
1115 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
1116 SMB2_CONTINUE_FLAG_SINGLE
,
1119 torture_assert_int_equal_goto(tctx
, result
.count
, num_files
, ret
, done
,
1122 for (i
=0;i
<num_files
-1;i
++) {
1123 const char *name1
, *name2
;
1124 name1
= result
.list
[i
].both_directory_info
.name
.s
;
1125 name2
= result
.list
[i
+1].both_directory_info
.name
.s
;
1126 if (strcasecmp_m(name1
, name2
) > 0) {
1127 torture_comment(tctx
, "non-alphabetical order at entry "
1128 "%d '%s' '%s'\n", i
, name1
, name2
);
1129 torture_comment(tctx
,
1130 "Server does not produce sorted directory listings"
1131 "(not an error)\n");
1135 talloc_free(result
.list
);
1137 smb2_util_close(tree
, h
);
1138 smb2_deltree(tree
, DNAME
);
1139 talloc_free(mem_ctx
);
1144 /* test the behavior of file_index field in the SMB2_FIND struct */
1145 static bool test_file_index(struct torture_context
*tctx
,
1146 struct smb2_tree
*tree
)
1148 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1149 const int num_files
= 100;
1150 int resume_index
= 4;
1155 struct multiple_result result
;
1156 struct smb2_create create
;
1158 struct smb2_handle h
;
1159 union smb_search_data
*d
;
1162 smb2_deltree(tree
, DNAME
);
1164 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1165 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1167 torture_comment(tctx
, "Testing the behavior of file_index flag\n");
1169 ZERO_STRUCT(create
);
1170 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1171 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1172 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1173 for (i
= num_files
-1; i
>= 0; i
--) {
1174 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\file%u.txt", i
);
1175 create
.in
.fname
= fname
;
1176 status
= smb2_create(tree
, mem_ctx
, &create
);
1177 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1179 smb2_util_close(tree
, create
.out
.file
.handle
);
1182 ZERO_STRUCT(result
);
1186 f
.in
.file
.handle
= h
;
1188 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
;
1189 f
.in
.max_response_size
= 0x1000;
1190 f
.in
.level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
1193 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1194 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1196 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1197 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1198 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
)) {
1202 } while(result
.count
< 10);
1204 if (result
.list
[0].full_directory_info
.file_index
== 0) {
1205 torture_skip_goto(tctx
, done
,
1206 "Talking to a server that doesn't provide a "
1207 "file index.\nWindows servers using NTFS do "
1208 "not provide a file_index. Skipping test\n");
1210 /* We are not talking to a Windows based server. Windows
1211 * servers using NTFS do not provide a file_index. Windows
1212 * servers using FAT do provide a file index, however in both
1213 * cases they do not honor a file index on a resume request.
1214 * See MS-FSCC <62> and MS-SMB2 <54> for more information. */
1216 /* Set the file_index flag to point to the fifth file from the
1217 * previous enumeration and try to start the subsequent
1218 * searches from that point */
1220 result
.list
[resume_index
].full_directory_info
.file_index
;
1221 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_INDEX
;
1223 /* get the name of the next expected file */
1224 fname
= talloc_asprintf(mem_ctx
, DNAME
"\\%s",
1225 result
.list
[resume_index
].full_directory_info
.name
.s
);
1227 ZERO_STRUCT(result
);
1229 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1230 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1232 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1233 if (!fill_result(&result
, d
, count
, f
.in
.level
,
1234 RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
)) {
1239 result
.list
[0].full_directory_info
.name
.s
)) {
1240 torture_comment(tctx
, "Next expected file: %s but the "
1241 "server returned %s\n", fname
,
1242 result
.list
[0].full_directory_info
.name
.s
);
1243 torture_comment(tctx
,
1244 "Not an error. Resuming using a file "
1245 "index is an optional feature of the "
1251 smb2_util_close(tree
, h
);
1252 smb2_deltree(tree
, DNAME
);
1253 talloc_free(mem_ctx
);
1259 * Tests directory enumeration in a directory containing >1000 files with
1260 * names of varying lengths.
1262 static bool test_large_files(struct torture_context
*tctx
,
1263 struct smb2_tree
*tree
)
1265 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1266 const int num_files
= 2000;
1268 /* These should be evenly divisible */
1269 int num_at_len
= num_files
/ max_len
;
1270 struct file_elem files
[2000] = {};
1274 struct smb2_create create
;
1276 struct smb2_handle h
;
1277 union smb_search_data
*d
;
1278 int i
, j
, file_count
= 0;
1282 torture_comment(tctx
,
1283 "Testing directory enumeration in a directory with >1000 files\n");
1285 smb2_deltree(tree
, DNAME
);
1287 ZERO_STRUCT(create
);
1288 create
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
1289 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1290 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1291 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1292 NTCREATEX_SHARE_ACCESS_WRITE
|
1293 NTCREATEX_SHARE_ACCESS_DELETE
;
1294 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1295 create
.in
.fname
= DNAME
;
1297 status
= smb2_create(tree
, mem_ctx
, &create
);
1298 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1299 h
= create
.out
.file
.handle
;
1301 ZERO_STRUCT(create
);
1302 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1303 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1304 create
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1306 for (i
= 0; i
< num_files
; i
++) {
1307 if (i
% num_at_len
== 0) {
1308 strs
= generate_unique_strs(mem_ctx
, len
, num_at_len
);
1311 files
[i
].name
= strs
[i
% num_at_len
];
1312 create
.in
.fname
= talloc_asprintf(mem_ctx
, "%s\\%s",
1313 DNAME
, files
[i
].name
);
1314 status
= smb2_create(tree
, mem_ctx
, &create
);
1315 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1316 smb2_util_close(tree
, create
.out
.file
.handle
);
1320 f
.in
.file
.handle
= h
;
1322 f
.in
.max_response_size
= 0x100;
1323 f
.in
.level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
1326 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
1327 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
))
1329 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "");
1331 for (i
= 0; i
< count
; i
++) {
1333 const char *found
= d
[i
].both_directory_info
.name
.s
;
1335 if (!strcmp(found
, ".") || !strcmp(found
, ".."))
1339 for (j
= 0; j
< 2000; j
++) {
1340 if (!strcmp(files
[j
].name
, found
)) {
1341 files
[j
].found
= true;
1350 torture_result(tctx
, TORTURE_FAIL
,
1351 "(%s): didn't expect %s\n",
1352 __location__
, found
);
1356 file_count
= file_count
+ i
;
1357 f
.in
.continue_flags
= 0;
1358 f
.in
.max_response_size
= 4096;
1359 } while (count
!= 0);
1361 torture_assert_int_equal_goto(tctx
, file_count
, num_files
+ 2, ret
,
1364 for (i
= 0; i
< num_files
; i
++) {
1368 torture_result(tctx
, TORTURE_FAIL
,
1369 "(%s): expected to find %s, but didn't\n",
1370 __location__
, files
[j
].name
);
1375 smb2_util_close(tree
, h
);
1376 smb2_deltree(tree
, DNAME
);
1377 talloc_free(mem_ctx
);
1382 struct torture_suite
*torture_smb2_dir_init(void)
1384 struct torture_suite
*suite
=
1385 torture_suite_create(talloc_autofree_context(), "dir");
1387 torture_suite_add_1smb2_test(suite
, "find", test_find
);
1388 torture_suite_add_1smb2_test(suite
, "fixed", test_fixed
);
1389 torture_suite_add_1smb2_test(suite
, "one", test_one_file
);
1390 torture_suite_add_1smb2_test(suite
, "many", test_many_files
);
1391 torture_suite_add_1smb2_test(suite
, "modify", test_modify_search
);
1392 torture_suite_add_1smb2_test(suite
, "sorted", test_sorted
);
1393 torture_suite_add_1smb2_test(suite
, "file-index", test_file_index
);
1394 torture_suite_add_1smb2_test(suite
, "large-files", test_large_files
);
1395 suite
->description
= talloc_strdup(suite
, "SMB2-DIR tests");