2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
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.
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.
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/>.
21 #include "lib/cmdline/popt_common.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "libcli/raw/request.h"
25 #include "libcli/libcli.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "librpc/gen_ndr/security.h"
28 #include "auth/credentials/credentials.h"
29 #include "libcli/resolve/resolve.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "dynconfig.h"
38 static struct gentest_options
{
42 bool analyze_continuous
;
43 uint_t max_open_handles
;
47 char **ignore_patterns
;
48 const char *seeds_file
;
49 bool use_preset_seeds
;
53 /* mapping between open handles on the server and local handles */
57 uint_t server_fnum
[NSERVERS
];
60 static uint_t num_open_handles
;
62 /* state information for the servers. We open NINSTANCES connections to
65 struct smbcli_state
*cli
[NINSTANCES
];
68 struct cli_credentials
*credentials
;
71 /* the seeds and flags for each operation */
78 /* oplock break info */
85 } oplocks
[NSERVERS
][NINSTANCES
];
87 /* change notify reply info */
91 union smb_notify notify
;
92 } notifies
[NSERVERS
][NINSTANCES
];
94 /* info relevant to the current operation */
105 #define BAD_HANDLE 0xFFFE
107 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private);
108 static void idle_func(struct smbcli_transport
*transport
, void *private);
111 check if a string should be ignored. This is used as the basis
112 for all error ignore settings
114 static bool ignore_pattern(const char *str
)
117 if (!options
.ignore_patterns
) return false;
119 for (i
=0;options
.ignore_patterns
[i
];i
++) {
120 if (strcmp(options
.ignore_patterns
[i
], str
) == 0 ||
121 gen_fnmatch(options
.ignore_patterns
[i
], str
) == 0) {
122 DEBUG(2,("Ignoring '%s'\n", str
));
129 /*****************************************************
130 connect to the servers
131 *******************************************************/
132 static bool connect_servers_fast(void)
136 /* close all open files */
137 for (h
=0;h
<options
.max_open_handles
;h
++) {
138 if (!open_handles
[h
].active
) continue;
139 for (i
=0;i
<NSERVERS
;i
++) {
140 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
141 open_handles
[h
].server_fnum
[i
])))) {
144 open_handles
[h
].active
= false;
154 /*****************************************************
155 connect to the servers
156 *******************************************************/
157 static bool connect_servers(struct loadparm_context
*lp_ctx
)
161 if (options
.fast_reconnect
&& servers
[0].cli
[0]) {
162 if (connect_servers_fast()) {
167 /* close any existing connections */
168 for (i
=0;i
<NSERVERS
;i
++) {
169 for (j
=0;j
<NINSTANCES
;j
++) {
170 if (servers
[i
].cli
[j
]) {
171 smbcli_tdis(servers
[i
].cli
[j
]);
172 talloc_free(servers
[i
].cli
[j
]);
173 servers
[i
].cli
[j
] = NULL
;
178 for (i
=0;i
<NSERVERS
;i
++) {
179 for (j
=0;j
<NINSTANCES
;j
++) {
180 struct smbcli_options smb_options
;
182 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
183 servers
[i
].server_name
, servers
[i
].share_name
,
184 servers
[i
].credentials
->username
, j
);
186 cli_credentials_set_workstation(servers
[i
].credentials
,
187 "gentest", CRED_SPECIFIED
);
189 lp_smbcli_options(lp_ctx
, &smb_options
);
190 status
= smbcli_full_connection(NULL
, &servers
[i
].cli
[j
],
191 servers
[i
].server_name
,
192 lp_smb_ports(lp_ctx
),
193 servers
[i
].share_name
, NULL
,
194 servers
[i
].credentials
,
195 lp_resolve_context(lp_ctx
),
197 if (!NT_STATUS_IS_OK(status
)) {
198 printf("Failed to connect to \\\\%s\\%s - %s\n",
199 servers
[i
].server_name
, servers
[i
].share_name
,
204 smbcli_oplock_handler(servers
[i
].cli
[j
]->transport
, oplock_handler
, NULL
);
205 smbcli_transport_idle_handler(servers
[i
].cli
[j
]->transport
, idle_func
, 50000, NULL
);
213 work out the time skew between the servers - be conservative
215 static uint_t
time_skew(void)
218 ret
= labs(servers
[0].cli
[0]->transport
->negotiate
.server_time
-
219 servers
[1].cli
[0]->transport
->negotiate
.server_time
);
224 turn an fnum for an instance into a handle
226 static uint_t
fnum_to_handle(int server
, int instance
, uint16_t fnum
)
229 for (i
=0;i
<options
.max_open_handles
;i
++) {
230 if (!open_handles
[i
].active
||
231 instance
!= open_handles
[i
].instance
) continue;
232 if (open_handles
[i
].server_fnum
[server
] == fnum
) {
236 printf("Invalid fnum %d in fnum_to_handle on server %d instance %d\n",
237 fnum
, server
, instance
);
242 add some newly opened handles
244 static void gen_add_handle(int instance
, const char *name
, uint16_t fnums
[NSERVERS
])
247 for (h
=0;h
<options
.max_open_handles
;h
++) {
248 if (!open_handles
[h
].active
) break;
250 if (h
== options
.max_open_handles
) {
251 /* we have to force close a random handle */
252 h
= random() % options
.max_open_handles
;
253 for (i
=0;i
<NSERVERS
;i
++) {
254 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
255 open_handles
[h
].server_fnum
[i
])))) {
256 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
257 smbcli_errstr(servers
[i
].cli
[open_handles
[h
].instance
]->tree
));
260 printf("Recovered handle %d\n", h
);
263 for (i
=0;i
<NSERVERS
;i
++) {
264 open_handles
[h
].server_fnum
[i
] = fnums
[i
];
265 open_handles
[h
].instance
= instance
;
266 open_handles
[h
].active
= true;
267 open_handles
[h
].name
= name
;
271 printf("OPEN num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
273 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
278 remove a closed handle
280 static void gen_remove_handle(int instance
, uint16_t fnums
[NSERVERS
])
283 for (h
=0;h
<options
.max_open_handles
;h
++) {
284 if (instance
== open_handles
[h
].instance
&&
285 open_handles
[h
].server_fnum
[0] == fnums
[0]) {
286 open_handles
[h
].active
= false;
288 printf("CLOSE num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
290 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
291 open_handles
[h
].name
);
295 printf("Removing invalid handle!?\n");
300 return true with 'chance' probability as a percentage
302 static bool gen_chance(uint_t chance
)
304 return ((random() % 100) <= chance
);
308 map an internal handle number to a server fnum
310 static uint16_t gen_lookup_fnum(int server
, uint16_t handle
)
312 if (handle
== BAD_HANDLE
) return handle
;
313 return open_handles
[handle
].server_fnum
[server
];
319 static uint16_t gen_fnum(int instance
)
324 if (gen_chance(20)) return BAD_HANDLE
;
326 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
327 h
= random() % options
.max_open_handles
;
328 if (open_handles
[h
].active
&&
329 open_handles
[h
].instance
== instance
) {
337 return a file handle, but skewed so we don't close the last
338 couple of handles too readily
340 static uint16_t gen_fnum_close(int instance
)
342 if (num_open_handles
< 3) {
343 if (gen_chance(80)) return BAD_HANDLE
;
346 return gen_fnum(instance
);
350 generate an integer in a specified range
352 static int gen_int_range(uint_t min
, uint_t max
)
355 return min
+ (r
% (1+max
-min
));
359 return a fnum for use as a root fid
360 be careful to call GEN_SET_FNUM() when you use this!
362 static uint16_t gen_root_fid(int instance
)
364 if (gen_chance(5)) return gen_fnum(instance
);
369 generate a file offset
371 static int gen_offset(void)
373 if (gen_chance(20)) return 0;
374 return gen_int_range(0, 1024*1024);
380 static int gen_io_count(void)
382 if (gen_chance(20)) return 0;
383 return gen_int_range(0, 4096);
389 static const char *gen_fname(void)
391 const char *names
[] = {"\\gentest\\gentest.dat",
393 "\\gentest\\foo2.sym",
394 "\\gentest\\foo3.dll",
396 "\\gentest\\foo4:teststream1",
397 "\\gentest\\foo4:teststream2",
398 "\\gentest\\foo5.exe",
399 "\\gentest\\foo5.exe:teststream3",
400 "\\gentest\\foo5.exe:teststream4",
401 "\\gentest\\foo6.com",
403 "\\gentest\\blah\\blergh.txt",
404 "\\gentest\\blah\\blergh2",
405 "\\gentest\\blah\\blergh3.txt",
406 "\\gentest\\blah\\blergh4",
407 "\\gentest\\blah\\blergh5.txt",
408 "\\gentest\\blah\\blergh5",
409 "\\gentest\\blah\\.",
411 /* this causes problem with w2k3 */
412 "\\gentest\\blah\\..",
414 "\\gentest\\a_very_long_name.bin",
420 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
421 } while (ignore_pattern(names
[i
]));
427 generate a filename with a higher chance of choosing an already
430 static const char *gen_fname_open(int instance
)
433 h
= gen_fnum(instance
);
434 if (h
== BAD_HANDLE
) {
437 return open_handles
[h
].name
;
441 generate a wildcard pattern
443 static const char *gen_pattern(void)
446 const char *names
[] = {"\\gentest\\*.dat",
449 "\\gentest\\blah\\*.*",
450 "\\gentest\\blah\\*",
453 if (gen_chance(50)) return gen_fname();
456 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
457 } while (ignore_pattern(names
[i
]));
465 static uint32_t gen_bits_mask(uint_t mask
)
467 uint_t ret
= random();
472 generate a bitmask with high probability of the first mask
473 and low of the second
475 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
477 if (gen_chance(10)) return gen_bits_mask(mask2
);
478 return gen_bits_mask(mask1
);
484 static bool gen_bool(void)
486 return gen_bits_mask2(0x1, 0xFF);
490 generate ntrename flags
492 static uint16_t gen_rename_flags(void)
494 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
495 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
496 if (gen_chance(30)) return RENAME_FLAG_COPY
;
497 return gen_bits_mask(0xFFFF);
502 return a lockingx lock mode
504 static uint16_t gen_lock_mode(void)
506 if (gen_chance(5)) return gen_bits_mask(0xFFFF);
507 if (gen_chance(20)) return gen_bits_mask(0x1F);
508 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
514 static uint16_t gen_pid(void)
516 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
521 generate a lock count
523 static off_t
gen_lock_count(void)
525 return gen_int_range(0, 3);
529 generate a ntcreatex flags field
531 static uint32_t gen_ntcreatex_flags(void)
533 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
534 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
538 generate a NT access mask
540 static uint32_t gen_access_mask(void)
542 if (gen_chance(50)) return SEC_FLAG_MAXIMUM_ALLOWED
;
543 if (gen_chance(20)) return SEC_FILE_ALL
;
544 return gen_bits_mask(0xFFFFFFFF);
548 generate a ntcreatex create options bitfield
550 static uint32_t gen_create_options(void)
552 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
553 if (gen_chance(50)) return 0;
554 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
558 generate a ntcreatex open disposition
560 static uint32_t gen_open_disp(void)
562 if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
563 return gen_int_range(0, 5);
567 generate an openx open mode
569 static uint16_t gen_openx_mode(void)
571 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
572 if (gen_chance(20)) return gen_bits_mask(0xFF);
573 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
577 generate an openx flags field
579 static uint16_t gen_openx_flags(void)
581 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
582 return gen_bits_mask(0x7);
586 generate an openx open function
588 static uint16_t gen_openx_func(void)
590 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
591 return gen_bits_mask(0x13);
595 generate a file attrib combination
597 static uint32_t gen_attrib(void)
599 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
600 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
604 generate a unix timestamp
606 static time_t gen_timet(void)
608 if (gen_chance(30)) return 0;
609 return (time_t)random();
613 generate a unix timestamp
615 static NTTIME
gen_nttime(void)
618 unix_to_nt_time(&ret
, gen_timet());
623 generate a milliseconds protocol timeout
625 static uint32_t gen_timeout(void)
627 if (gen_chance(98)) return 0;
628 return random() % 50;
632 generate a file allocation size
634 static uint_t
gen_alloc_size(void)
638 if (gen_chance(30)) return 0;
640 ret
= random() % 4*1024*1024;
641 /* give a high chance of a round number */
642 if (gen_chance(60)) {
643 ret
&= ~(1024*1024 - 1);
649 generate an ea_struct
651 static struct ea_struct
gen_ea_struct(void)
654 const char *names
[] = {"EAONE",
659 "AVERYLONGATTRIBUTENAME"};
660 const char *values
[] = {"VALUE1",
665 "ASOMEWHATLONGERATTRIBUTEVALUE"};
671 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
672 } while (ignore_pattern(names
[i
]));
674 ea
.name
.s
= names
[i
];
677 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
678 } while (ignore_pattern(values
[i
]));
680 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
682 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
690 this is called when a change notify reply comes in
692 static void async_notify(struct smbcli_request
*req
)
694 union smb_notify notify
;
698 struct smbcli_transport
*transport
= req
->transport
;
700 tid
= SVAL(req
->in
.hdr
, HDR_TID
);
702 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
703 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
704 if (NT_STATUS_IS_OK(status
)) {
705 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
707 notify
.nttrans
.out
.num_changes
,
708 notify
.nttrans
.out
.changes
[0].action
,
709 notify
.nttrans
.out
.changes
[0].name
.s
);
712 for (i
=0;i
<NSERVERS
;i
++) {
713 for (j
=0;j
<NINSTANCES
;j
++) {
714 if (transport
== servers
[i
].cli
[j
]->transport
&&
715 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
716 notifies
[i
][j
].notify_count
++;
717 notifies
[i
][j
].status
= status
;
718 notifies
[i
][j
].notify
= notify
;
724 static void oplock_handler_close_recv(struct smbcli_request
*req
)
727 status
= smbcli_request_simple_recv(req
);
728 if (!NT_STATUS_IS_OK(status
)) {
729 printf("close failed in oplock_handler\n");
730 smb_panic("close failed in oplock_handler");
735 the oplock handler will either ack the break or close the file
737 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private)
742 struct smbcli_tree
*tree
= NULL
;
743 struct smbcli_request
*req
;
745 srandom(current_op
.seed
);
746 do_close
= gen_chance(50);
748 for (i
=0;i
<NSERVERS
;i
++) {
749 for (j
=0;j
<NINSTANCES
;j
++) {
750 if (transport
== servers
[i
].cli
[j
]->transport
&&
751 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
752 oplocks
[i
][j
].got_break
= true;
753 oplocks
[i
][j
].fnum
= fnum
;
754 oplocks
[i
][j
].handle
= fnum_to_handle(i
, j
, fnum
);
755 oplocks
[i
][j
].level
= level
;
756 oplocks
[i
][j
].do_close
= do_close
;
757 tree
= servers
[i
].cli
[j
]->tree
;
763 printf("Oplock break not for one of our trees!?\n");
768 printf("oplock ack fnum=%d\n", fnum
);
769 return smbcli_oplock_ack(tree
, fnum
, level
);
772 printf("oplock close fnum=%d\n", fnum
);
774 io
.close
.level
= RAW_CLOSE_CLOSE
;
775 io
.close
.in
.file
.fnum
= fnum
;
776 io
.close
.in
.write_time
= 0;
777 req
= smb_raw_close_send(tree
, &io
);
780 printf("WARNING: close failed in oplock_handler_close\n");
784 req
->async
.fn
= oplock_handler_close_recv
;
785 req
->async
.private = NULL
;
792 the idle function tries to cope with getting an oplock break on a connection, and
793 an operation on another connection blocking until that break is acked
794 we check for operations on all transports in the idle function
796 static void idle_func(struct smbcli_transport
*transport
, void *private)
799 for (i
=0;i
<NSERVERS
;i
++) {
800 for (j
=0;j
<NINSTANCES
;j
++) {
801 if (servers
[i
].cli
[j
] &&
802 transport
!= servers
[i
].cli
[j
]->transport
) {
803 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
812 compare NTSTATUS, using checking ignored patterns
814 static bool compare_status(NTSTATUS status1
, NTSTATUS status2
)
816 if (NT_STATUS_EQUAL(status1
, status2
)) return true;
818 /* one code being an error and the other OK is always an error */
819 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) return false;
821 /* if we are ignoring one of the status codes then consider this a match */
822 if (ignore_pattern(nt_errstr(status1
)) ||
823 ignore_pattern(nt_errstr(status2
))) {
831 check for pending packets on all connections
833 static void check_pending(void)
839 for (j
=0;j
<NINSTANCES
;j
++) {
840 for (i
=0;i
<NSERVERS
;i
++) {
841 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
847 check that the same oplock breaks have been received by all instances
849 static bool check_oplocks(const char *call
)
857 for (j
=0;j
<NINSTANCES
;j
++) {
858 for (i
=1;i
<NSERVERS
;i
++) {
859 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
860 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
861 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
862 if (tries
++ < 10) goto again
;
863 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
864 oplocks
[0][j
].got_break
,
865 oplocks
[0][j
].handle
,
867 oplocks
[i
][j
].got_break
,
868 oplocks
[i
][j
].handle
,
869 oplocks
[i
][j
].level
);
875 /* if we got a break and closed then remove the handle */
876 for (j
=0;j
<NINSTANCES
;j
++) {
877 if (oplocks
[0][j
].got_break
&&
878 oplocks
[0][j
].do_close
) {
879 uint16_t fnums
[NSERVERS
];
880 for (i
=0;i
<NSERVERS
;i
++) {
881 fnums
[i
] = oplocks
[i
][j
].fnum
;
883 gen_remove_handle(j
, fnums
);
892 check that the same change notify info has been received by all instances
894 static bool check_notifies(const char *call
)
902 for (j
=0;j
<NINSTANCES
;j
++) {
903 for (i
=1;i
<NSERVERS
;i
++) {
905 union smb_notify not1
, not2
;
907 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
908 if (tries
++ < 10) goto again
;
909 printf("Notify count inconsistent %d %d\n",
910 notifies
[0][j
].notify_count
,
911 notifies
[i
][j
].notify_count
);
915 if (notifies
[0][j
].notify_count
== 0) continue;
917 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
918 notifies
[i
][j
].status
)) {
919 printf("Notify status mismatch - %s - %s\n",
920 nt_errstr(notifies
[0][j
].status
),
921 nt_errstr(notifies
[i
][j
].status
));
925 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
929 not1
= notifies
[0][j
].notify
;
930 not2
= notifies
[i
][j
].notify
;
932 for (n
=0;n
<not1
.nttrans
.out
.num_changes
;n
++) {
933 if (not1
.nttrans
.out
.changes
[n
].action
!=
934 not2
.nttrans
.out
.changes
[n
].action
) {
935 printf("Notify action %d inconsistent %d %d\n", n
,
936 not1
.nttrans
.out
.changes
[n
].action
,
937 not2
.nttrans
.out
.changes
[n
].action
);
940 if (strcmp(not1
.nttrans
.out
.changes
[n
].name
.s
,
941 not2
.nttrans
.out
.changes
[n
].name
.s
)) {
942 printf("Notify name %d inconsistent %s %s\n", n
,
943 not1
.nttrans
.out
.changes
[n
].name
.s
,
944 not2
.nttrans
.out
.changes
[n
].name
.s
);
947 if (not1
.nttrans
.out
.changes
[n
].name
.private_length
!=
948 not2
.nttrans
.out
.changes
[n
].name
.private_length
) {
949 printf("Notify name length %d inconsistent %d %d\n", n
,
950 not1
.nttrans
.out
.changes
[n
].name
.private_length
,
951 not2
.nttrans
.out
.changes
[n
].name
.private_length
);
958 ZERO_STRUCT(notifies
);
964 #define GEN_COPY_PARM do { \
966 for (i=1;i<NSERVERS;i++) { \
971 #define GEN_CALL(call) do { \
973 ZERO_STRUCT(oplocks); \
974 ZERO_STRUCT(notifies); \
975 for (i=0;i<NSERVERS;i++) { \
976 struct smbcli_tree *tree = servers[i].cli[instance]->tree; \
979 current_op.status = status[0]; \
980 for (i=1;i<NSERVERS;i++) { \
981 if (!compare_status(status[i], status[0])) { \
982 printf("status different in %s - %s %s\n", #call, \
983 nt_errstr(status[0]), nt_errstr(status[i])); \
987 if (!check_oplocks(#call)) return false; \
988 if (!check_notifies(#call)) return false; \
989 if (!NT_STATUS_IS_OK(status[0])) { \
994 #define ADD_HANDLE(name, field) do { \
995 uint16_t fnums[NSERVERS]; \
997 for (i=0;i<NSERVERS;i++) { \
998 fnums[i] = parm[i].field; \
1000 gen_add_handle(instance, name, fnums); \
1003 #define REMOVE_HANDLE(field) do { \
1004 uint16_t fnums[NSERVERS]; \
1006 for (i=0;i<NSERVERS;i++) { \
1007 fnums[i] = parm[i].field; \
1009 gen_remove_handle(instance, fnums); \
1012 #define GEN_SET_FNUM(field) do { \
1014 for (i=0;i<NSERVERS;i++) { \
1015 parm[i].field = gen_lookup_fnum(i, parm[i].field); \
1019 #define CHECK_EQUAL(field) do { \
1020 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1021 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1022 (int)parm[0].field, (int)parm[1].field); \
1027 #define CHECK_WSTR_EQUAL(field) do { \
1028 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1029 printf("%s is NULL!\n", #field); \
1032 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1033 printf("Mismatch in %s - %s %s\n", #field, \
1034 parm[0].field.s, parm[1].field.s); \
1037 CHECK_EQUAL(field.private_length); \
1040 #define CHECK_BLOB_EQUAL(field) do { \
1041 if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1042 printf("Mismatch in %s\n", #field); \
1045 CHECK_EQUAL(field.length); \
1048 #define CHECK_TIMES_EQUAL(field) do { \
1049 if (labs(parm[0].field - parm[1].field) > time_skew() && \
1050 !ignore_pattern(#field)) { \
1051 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1052 (int)parm[0].field, (int)parm[1].field); \
1057 #define CHECK_NTTIMES_EQUAL(field) do { \
1058 if (labs(nt_time_to_unix(parm[0].field) - \
1059 nt_time_to_unix(parm[1].field)) > time_skew() && \
1060 !ignore_pattern(#field)) { \
1061 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1062 (int)nt_time_to_unix(parm[0].field), \
1063 (int)nt_time_to_unix(parm[1].field)); \
1069 generate openx operations
1071 static bool handler_openx(int instance
)
1073 union smb_open parm
[NSERVERS
];
1074 NTSTATUS status
[NSERVERS
];
1076 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1077 parm
[0].openx
.in
.flags
= gen_openx_flags();
1078 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1079 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1080 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1081 parm
[0].openx
.in
.write_time
= gen_timet();
1082 parm
[0].openx
.in
.open_func
= gen_openx_func();
1083 parm
[0].openx
.in
.size
= gen_io_count();
1084 parm
[0].openx
.in
.timeout
= gen_timeout();
1085 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1087 if (!options
.use_oplocks
) {
1088 /* mask out oplocks */
1089 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1090 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1094 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1096 CHECK_EQUAL(openx
.out
.attrib
);
1097 CHECK_EQUAL(openx
.out
.size
);
1098 CHECK_EQUAL(openx
.out
.access
);
1099 CHECK_EQUAL(openx
.out
.ftype
);
1100 CHECK_EQUAL(openx
.out
.devstate
);
1101 CHECK_EQUAL(openx
.out
.action
);
1102 CHECK_EQUAL(openx
.out
.access_mask
);
1103 CHECK_EQUAL(openx
.out
.unknown
);
1104 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1106 /* open creates a new file handle */
1107 ADD_HANDLE(parm
[0].openx
.in
.fname
, openx
.out
.file
.fnum
);
1114 generate open operations
1116 static bool handler_open(int instance
)
1118 union smb_open parm
[NSERVERS
];
1119 NTSTATUS status
[NSERVERS
];
1121 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1122 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1123 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1124 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1126 if (!options
.use_oplocks
) {
1127 /* mask out oplocks */
1128 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1129 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1133 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1135 CHECK_EQUAL(openold
.out
.attrib
);
1136 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1137 CHECK_EQUAL(openold
.out
.size
);
1138 CHECK_EQUAL(openold
.out
.rmode
);
1140 /* open creates a new file handle */
1141 ADD_HANDLE(parm
[0].openold
.in
.fname
, openold
.out
.file
.fnum
);
1148 generate ntcreatex operations
1150 static bool handler_ntcreatex(int instance
)
1152 union smb_open parm
[NSERVERS
];
1153 NTSTATUS status
[NSERVERS
];
1155 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1156 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1157 parm
[0].ntcreatex
.in
.root_fid
= gen_root_fid(instance
);
1158 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1159 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1160 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1161 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1162 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1163 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1164 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1165 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1166 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1168 if (!options
.use_oplocks
) {
1169 /* mask out oplocks */
1170 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1171 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1175 if (parm
[0].ntcreatex
.in
.root_fid
!= 0) {
1176 GEN_SET_FNUM(ntcreatex
.in
.root_fid
);
1178 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1180 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1181 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1182 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1183 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1184 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1185 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1186 CHECK_EQUAL(ntcreatex
.out
.attrib
);
1187 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1188 CHECK_EQUAL(ntcreatex
.out
.size
);
1189 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1190 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1191 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1193 /* ntcreatex creates a new file handle */
1194 ADD_HANDLE(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.file
.fnum
);
1200 generate close operations
1202 static bool handler_close(int instance
)
1204 union smb_close parm
[NSERVERS
];
1205 NTSTATUS status
[NSERVERS
];
1207 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1208 parm
[0].close
.in
.file
.fnum
= gen_fnum_close(instance
);
1209 parm
[0].close
.in
.write_time
= gen_timet();
1212 GEN_SET_FNUM(close
.in
.file
.fnum
);
1213 GEN_CALL(smb_raw_close(tree
, &parm
[i
]));
1215 REMOVE_HANDLE(close
.in
.file
.fnum
);
1221 generate unlink operations
1223 static bool handler_unlink(int instance
)
1225 union smb_unlink parm
[NSERVERS
];
1226 NTSTATUS status
[NSERVERS
];
1228 parm
[0].unlink
.in
.pattern
= gen_pattern();
1229 parm
[0].unlink
.in
.attrib
= gen_attrib();
1232 GEN_CALL(smb_raw_unlink(tree
, &parm
[i
]));
1238 generate chkpath operations
1240 static bool handler_chkpath(int instance
)
1242 union smb_chkpath parm
[NSERVERS
];
1243 NTSTATUS status
[NSERVERS
];
1245 parm
[0].chkpath
.in
.path
= gen_fname_open(instance
);
1248 GEN_CALL(smb_raw_chkpath(tree
, &parm
[i
]));
1254 generate mkdir operations
1256 static bool handler_mkdir(int instance
)
1258 union smb_mkdir parm
[NSERVERS
];
1259 NTSTATUS status
[NSERVERS
];
1261 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1262 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1265 GEN_CALL(smb_raw_mkdir(tree
, &parm
[i
]));
1271 generate rmdir operations
1273 static bool handler_rmdir(int instance
)
1275 struct smb_rmdir parm
[NSERVERS
];
1276 NTSTATUS status
[NSERVERS
];
1278 parm
[0].in
.path
= gen_fname_open(instance
);
1281 GEN_CALL(smb_raw_rmdir(tree
, &parm
[i
]));
1287 generate rename operations
1289 static bool handler_rename(int instance
)
1291 union smb_rename parm
[NSERVERS
];
1292 NTSTATUS status
[NSERVERS
];
1294 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1295 parm
[0].rename
.in
.pattern1
= gen_pattern();
1296 parm
[0].rename
.in
.pattern2
= gen_pattern();
1297 parm
[0].rename
.in
.attrib
= gen_attrib();
1300 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1306 generate ntrename operations
1308 static bool handler_ntrename(int instance
)
1310 union smb_rename parm
[NSERVERS
];
1311 NTSTATUS status
[NSERVERS
];
1313 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1314 parm
[0].ntrename
.in
.old_name
= gen_fname();
1315 parm
[0].ntrename
.in
.new_name
= gen_fname();
1316 parm
[0].ntrename
.in
.attrib
= gen_attrib();
1317 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
1318 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
1321 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1328 generate seek operations
1330 static bool handler_seek(int instance
)
1332 union smb_seek parm
[NSERVERS
];
1333 NTSTATUS status
[NSERVERS
];
1335 parm
[0].lseek
.in
.file
.fnum
= gen_fnum(instance
);
1336 parm
[0].lseek
.in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
1337 parm
[0].lseek
.in
.offset
= gen_offset();
1340 GEN_SET_FNUM(lseek
.in
.file
.fnum
);
1341 GEN_CALL(smb_raw_seek(tree
, &parm
[i
]));
1343 CHECK_EQUAL(lseek
.out
.offset
);
1350 generate readx operations
1352 static bool handler_readx(int instance
)
1354 union smb_read parm
[NSERVERS
];
1355 NTSTATUS status
[NSERVERS
];
1357 parm
[0].readx
.level
= RAW_READ_READX
;
1358 parm
[0].readx
.in
.file
.fnum
= gen_fnum(instance
);
1359 parm
[0].readx
.in
.offset
= gen_offset();
1360 parm
[0].readx
.in
.mincnt
= gen_io_count();
1361 parm
[0].readx
.in
.maxcnt
= gen_io_count();
1362 parm
[0].readx
.in
.remaining
= gen_io_count();
1363 parm
[0].readx
.in
.read_for_execute
= gen_bool();
1364 parm
[0].readx
.out
.data
= talloc_array(current_op
.mem_ctx
, uint8_t,
1365 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
1368 GEN_SET_FNUM(readx
.in
.file
.fnum
);
1369 GEN_CALL(smb_raw_read(tree
, &parm
[i
]));
1371 CHECK_EQUAL(readx
.out
.remaining
);
1372 CHECK_EQUAL(readx
.out
.compaction_mode
);
1373 CHECK_EQUAL(readx
.out
.nread
);
1379 generate writex operations
1381 static bool handler_writex(int instance
)
1383 union smb_write parm
[NSERVERS
];
1384 NTSTATUS status
[NSERVERS
];
1386 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
1387 parm
[0].writex
.in
.file
.fnum
= gen_fnum(instance
);
1388 parm
[0].writex
.in
.offset
= gen_offset();
1389 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
1390 parm
[0].writex
.in
.remaining
= gen_io_count();
1391 parm
[0].writex
.in
.count
= gen_io_count();
1392 parm
[0].writex
.in
.data
= talloc_zero_array(current_op
.mem_ctx
, uint8_t, parm
[0].writex
.in
.count
);
1395 GEN_SET_FNUM(writex
.in
.file
.fnum
);
1396 GEN_CALL(smb_raw_write(tree
, &parm
[i
]));
1398 CHECK_EQUAL(writex
.out
.nwritten
);
1399 CHECK_EQUAL(writex
.out
.remaining
);
1405 generate lockingx operations
1407 static bool handler_lockingx(int instance
)
1409 union smb_lock parm
[NSERVERS
];
1410 NTSTATUS status
[NSERVERS
];
1413 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
1414 parm
[0].lockx
.in
.file
.fnum
= gen_fnum(instance
);
1415 parm
[0].lockx
.in
.mode
= gen_lock_mode();
1416 parm
[0].lockx
.in
.timeout
= gen_timeout();
1418 /* make sure we don't accidentially generate an oplock
1419 break ack - otherwise the server can just block forever */
1420 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
1421 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
1422 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
1423 } while (nlocks
== 0);
1426 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
1427 struct smb_lock_entry
,
1429 for (n
=0;n
<nlocks
;n
++) {
1430 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
1431 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
1432 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
1437 GEN_SET_FNUM(lockx
.in
.file
.fnum
);
1438 GEN_CALL(smb_raw_lock(tree
, &parm
[i
]));
1444 generate a fileinfo query structure
1446 static void gen_fileinfo(int instance
, union smb_fileinfo
*info
)
1449 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1451 enum smb_fileinfo_level level
;
1454 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
1455 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
1456 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
1457 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
1458 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
1459 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
1460 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
1461 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
1462 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
1463 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
1466 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1467 } while (ignore_pattern(levels
[i
].name
));
1469 info
->generic
.level
= levels
[i
].level
;
1473 compare returned fileinfo structures
1475 static bool cmp_fileinfo(int instance
,
1476 union smb_fileinfo parm
[NSERVERS
],
1477 NTSTATUS status
[NSERVERS
])
1481 switch (parm
[0].generic
.level
) {
1482 case RAW_FILEINFO_GENERIC
:
1485 case RAW_FILEINFO_GETATTR
:
1486 CHECK_EQUAL(getattr
.out
.attrib
);
1487 CHECK_EQUAL(getattr
.out
.size
);
1488 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1491 case RAW_FILEINFO_GETATTRE
:
1492 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1493 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1494 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1495 CHECK_EQUAL(getattre
.out
.size
);
1496 CHECK_EQUAL(getattre
.out
.alloc_size
);
1497 CHECK_EQUAL(getattre
.out
.attrib
);
1500 case RAW_FILEINFO_STANDARD
:
1501 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1502 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1503 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1504 CHECK_EQUAL(standard
.out
.size
);
1505 CHECK_EQUAL(standard
.out
.alloc_size
);
1506 CHECK_EQUAL(standard
.out
.attrib
);
1509 case RAW_FILEINFO_EA_SIZE
:
1510 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1511 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1512 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1513 CHECK_EQUAL(ea_size
.out
.size
);
1514 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1515 CHECK_EQUAL(ea_size
.out
.attrib
);
1516 CHECK_EQUAL(ea_size
.out
.ea_size
);
1519 case RAW_FILEINFO_ALL_EAS
:
1520 CHECK_EQUAL(all_eas
.out
.num_eas
);
1521 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1522 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1523 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1524 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1528 case RAW_FILEINFO_IS_NAME_VALID
:
1531 case RAW_FILEINFO_BASIC_INFO
:
1532 case RAW_FILEINFO_BASIC_INFORMATION
:
1533 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1534 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1535 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1536 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1537 CHECK_EQUAL(basic_info
.out
.attrib
);
1540 case RAW_FILEINFO_STANDARD_INFO
:
1541 case RAW_FILEINFO_STANDARD_INFORMATION
:
1542 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1543 CHECK_EQUAL(standard_info
.out
.size
);
1544 CHECK_EQUAL(standard_info
.out
.nlink
);
1545 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1546 CHECK_EQUAL(standard_info
.out
.directory
);
1549 case RAW_FILEINFO_EA_INFO
:
1550 case RAW_FILEINFO_EA_INFORMATION
:
1551 CHECK_EQUAL(ea_info
.out
.ea_size
);
1554 case RAW_FILEINFO_NAME_INFO
:
1555 case RAW_FILEINFO_NAME_INFORMATION
:
1556 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1559 case RAW_FILEINFO_ALL_INFO
:
1560 case RAW_FILEINFO_ALL_INFORMATION
:
1561 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1562 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1563 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1564 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1565 CHECK_EQUAL(all_info
.out
.attrib
);
1566 CHECK_EQUAL(all_info
.out
.alloc_size
);
1567 CHECK_EQUAL(all_info
.out
.size
);
1568 CHECK_EQUAL(all_info
.out
.nlink
);
1569 CHECK_EQUAL(all_info
.out
.delete_pending
);
1570 CHECK_EQUAL(all_info
.out
.directory
);
1571 CHECK_EQUAL(all_info
.out
.ea_size
);
1572 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1575 case RAW_FILEINFO_ALT_NAME_INFO
:
1576 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1577 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1580 case RAW_FILEINFO_STREAM_INFO
:
1581 case RAW_FILEINFO_STREAM_INFORMATION
:
1582 CHECK_EQUAL(stream_info
.out
.num_streams
);
1583 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1584 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1585 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1586 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1590 case RAW_FILEINFO_COMPRESSION_INFO
:
1591 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1592 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1593 CHECK_EQUAL(compression_info
.out
.format
);
1594 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1595 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1596 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1599 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1600 CHECK_EQUAL(internal_information
.out
.file_id
);
1603 case RAW_FILEINFO_ACCESS_INFORMATION
:
1604 CHECK_EQUAL(access_information
.out
.access_flags
);
1607 case RAW_FILEINFO_POSITION_INFORMATION
:
1608 CHECK_EQUAL(position_information
.out
.position
);
1611 case RAW_FILEINFO_MODE_INFORMATION
:
1612 CHECK_EQUAL(mode_information
.out
.mode
);
1615 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1616 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1619 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1620 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1621 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1622 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1623 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1624 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1625 CHECK_EQUAL(network_open_information
.out
.size
);
1626 CHECK_EQUAL(network_open_information
.out
.attrib
);
1629 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1630 CHECK_EQUAL(attribute_tag_information
.out
.attrib
);
1631 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1634 /* Unhandled levels */
1636 case RAW_FILEINFO_SEC_DESC
:
1637 case RAW_FILEINFO_EA_LIST
:
1638 case RAW_FILEINFO_UNIX_BASIC
:
1639 case RAW_FILEINFO_UNIX_LINK
:
1640 case RAW_FILEINFO_SMB2_ALL_EAS
:
1641 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
1642 case RAW_FILEINFO_UNIX_INFO2
:
1650 generate qpathinfo operations
1652 static bool handler_qpathinfo(int instance
)
1654 union smb_fileinfo parm
[NSERVERS
];
1655 NTSTATUS status
[NSERVERS
];
1657 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
1659 gen_fileinfo(instance
, &parm
[0]);
1662 GEN_CALL(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1664 return cmp_fileinfo(instance
, parm
, status
);
1668 generate qfileinfo operations
1670 static bool handler_qfileinfo(int instance
)
1672 union smb_fileinfo parm
[NSERVERS
];
1673 NTSTATUS status
[NSERVERS
];
1675 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
1677 gen_fileinfo(instance
, &parm
[0]);
1680 GEN_SET_FNUM(generic
.in
.file
.fnum
);
1681 GEN_CALL(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1683 return cmp_fileinfo(instance
, parm
, status
);
1688 generate a fileinfo query structure
1690 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
1694 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1696 enum smb_setfileinfo_level level
;
1700 /* disabled until win2003 can handle them ... */
1701 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
1702 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
1704 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
1705 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
1706 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
1707 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
1708 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1711 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1712 } while (ignore_pattern(levels
[i
].name
));
1714 info
->generic
.level
= levels
[i
].level
;
1716 switch (info
->generic
.level
) {
1717 case RAW_SFILEINFO_SETATTR
:
1718 info
->setattr
.in
.attrib
= gen_attrib();
1719 info
->setattr
.in
.write_time
= gen_timet();
1721 case RAW_SFILEINFO_SETATTRE
:
1722 info
->setattre
.in
.create_time
= gen_timet();
1723 info
->setattre
.in
.access_time
= gen_timet();
1724 info
->setattre
.in
.write_time
= gen_timet();
1726 case RAW_SFILEINFO_STANDARD
:
1727 info
->standard
.in
.create_time
= gen_timet();
1728 info
->standard
.in
.access_time
= gen_timet();
1729 info
->standard
.in
.write_time
= gen_timet();
1731 case RAW_SFILEINFO_EA_SET
: {
1732 static struct ea_struct ea
;
1733 info
->ea_set
.in
.num_eas
= 1;
1734 info
->ea_set
.in
.eas
= &ea
;
1735 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
1738 case RAW_SFILEINFO_BASIC_INFO
:
1739 case RAW_SFILEINFO_BASIC_INFORMATION
:
1740 info
->basic_info
.in
.create_time
= gen_nttime();
1741 info
->basic_info
.in
.access_time
= gen_nttime();
1742 info
->basic_info
.in
.write_time
= gen_nttime();
1743 info
->basic_info
.in
.change_time
= gen_nttime();
1744 info
->basic_info
.in
.attrib
= gen_attrib();
1746 case RAW_SFILEINFO_DISPOSITION_INFO
:
1747 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
1748 info
->disposition_info
.in
.delete_on_close
= gen_bool();
1750 case RAW_SFILEINFO_ALLOCATION_INFO
:
1751 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
1752 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
1754 case RAW_SFILEINFO_END_OF_FILE_INFO
:
1755 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
1756 info
->end_of_file_info
.in
.size
= gen_offset();
1758 case RAW_SFILEINFO_RENAME_INFORMATION
:
1759 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2
:
1760 info
->rename_information
.in
.overwrite
= gen_bool();
1761 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
1762 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
1764 case RAW_SFILEINFO_POSITION_INFORMATION
:
1765 info
->position_information
.in
.position
= gen_offset();
1767 case RAW_SFILEINFO_MODE_INFORMATION
:
1768 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
1770 case RAW_SFILEINFO_GENERIC
:
1771 case RAW_SFILEINFO_SEC_DESC
:
1772 case RAW_SFILEINFO_UNIX_BASIC
:
1773 case RAW_SFILEINFO_UNIX_LINK
:
1774 case RAW_SFILEINFO_UNIX_HLINK
:
1775 case RAW_SFILEINFO_1023
:
1776 case RAW_SFILEINFO_1025
:
1777 case RAW_SFILEINFO_1029
:
1778 case RAW_SFILEINFO_1032
:
1779 case RAW_SFILEINFO_1039
:
1780 case RAW_SFILEINFO_1040
:
1781 case RAW_SFILEINFO_UNIX_INFO2
:
1788 generate setpathinfo operations
1790 static bool handler_spathinfo(int instance
)
1792 union smb_setfileinfo parm
[NSERVERS
];
1793 NTSTATUS status
[NSERVERS
];
1795 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
1797 gen_setfileinfo(instance
, &parm
[0]);
1801 /* a special case for the fid in a RENAME */
1802 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
1803 parm
[0].rename_information
.in
.root_fid
!= 0) {
1804 GEN_SET_FNUM(rename_information
.in
.root_fid
);
1807 GEN_CALL(smb_raw_setpathinfo(tree
, &parm
[i
]));
1814 generate setfileinfo operations
1816 static bool handler_sfileinfo(int instance
)
1818 union smb_setfileinfo parm
[NSERVERS
];
1819 NTSTATUS status
[NSERVERS
];
1821 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
1823 gen_setfileinfo(instance
, &parm
[0]);
1826 GEN_SET_FNUM(generic
.in
.file
.fnum
);
1827 GEN_CALL(smb_raw_setfileinfo(tree
, &parm
[i
]));
1834 generate change notify operations
1836 static bool handler_notify(int instance
)
1838 union smb_notify parm
[NSERVERS
];
1841 ZERO_STRUCT(parm
[0]);
1842 parm
[0].nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1843 parm
[0].nttrans
.in
.buffer_size
= gen_io_count();
1844 parm
[0].nttrans
.in
.completion_filter
= gen_bits_mask(0xFF);
1845 parm
[0].nttrans
.in
.file
.fnum
= gen_fnum(instance
);
1846 parm
[0].nttrans
.in
.recursive
= gen_bool();
1849 GEN_SET_FNUM(nttrans
.in
.file
.fnum
);
1851 for (n
=0;n
<NSERVERS
;n
++) {
1852 struct smbcli_request
*req
;
1853 req
= smb_raw_changenotify_send(servers
[n
].cli
[instance
]->tree
, &parm
[n
]);
1854 req
->async
.fn
= async_notify
;
1861 wipe any relevant files
1863 static void wipe_files(void)
1866 for (i
=0;i
<NSERVERS
;i
++) {
1867 int n
= smbcli_deltree(servers
[i
].cli
[0]->tree
, "\\gentest");
1869 printf("Failed to wipe tree on server %d\n", i
);
1872 if (NT_STATUS_IS_ERR(smbcli_mkdir(servers
[i
].cli
[0]->tree
, "\\gentest"))) {
1873 printf("Failed to create \\gentest - %s\n",
1874 smbcli_errstr(servers
[i
].cli
[0]->tree
));
1878 printf("Deleted %d files on server %d\n", n
, i
);
1884 dump the current seeds - useful for continuing a backtrack
1886 static void dump_seeds(void)
1891 if (!options
.seeds_file
) {
1894 f
= fopen("seeds.tmp", "w");
1897 for (i
=0;i
<options
.numops
;i
++) {
1898 fprintf(f
, "%u\n", op_parms
[i
].seed
);
1901 rename("seeds.tmp", options
.seeds_file
);
1907 the list of top-level operations that we will generate
1911 bool (*handler
)(int instance
);
1912 int count
, success_count
;
1914 {"OPEN", handler_open
},
1915 {"OPENX", handler_openx
},
1916 {"NTCREATEX", handler_ntcreatex
},
1917 {"CLOSE", handler_close
},
1918 {"UNLINK", handler_unlink
},
1919 {"MKDIR", handler_mkdir
},
1920 {"RMDIR", handler_rmdir
},
1921 {"RENAME", handler_rename
},
1922 {"NTRENAME", handler_ntrename
},
1923 {"READX", handler_readx
},
1924 {"WRITEX", handler_writex
},
1925 {"CHKPATH", handler_chkpath
},
1926 {"LOCKINGX", handler_lockingx
},
1927 {"QPATHINFO", handler_qpathinfo
},
1928 {"QFILEINFO", handler_qfileinfo
},
1929 {"SPATHINFO", handler_spathinfo
},
1930 {"SFILEINFO", handler_sfileinfo
},
1931 {"NOTIFY", handler_notify
},
1932 {"SEEK", handler_seek
},
1937 run the test with the current set of op_parms parameters
1938 return the number of operations that completed successfully
1940 static int run_test(struct loadparm_context
*lp_ctx
)
1944 if (!connect_servers(lp_ctx
)) {
1945 printf("Failed to connect to servers\n");
1951 /* wipe any leftover files from old runs */
1954 /* reset the open handles array */
1955 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
1956 num_open_handles
= 0;
1958 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1959 gen_ops
[i
].count
= 0;
1960 gen_ops
[i
].success_count
= 0;
1963 for (op
=0; op
<options
.numops
; op
++) {
1964 int instance
, which_op
;
1967 if (op_parms
[op
].disabled
) continue;
1969 srandom(op_parms
[op
].seed
);
1971 instance
= gen_int_range(0, NINSTANCES
-1);
1973 /* generate a non-ignored operation */
1975 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
1976 } while (ignore_pattern(gen_ops
[which_op
].name
));
1978 DEBUG(3,("Generating op %s on instance %d\n",
1979 gen_ops
[which_op
].name
, instance
));
1981 current_op
.seed
= op_parms
[op
].seed
;
1982 current_op
.opnum
= op
;
1983 current_op
.name
= gen_ops
[which_op
].name
;
1984 current_op
.status
= NT_STATUS_OK
;
1985 current_op
.mem_ctx
= talloc_named(NULL
, 0, "%s", current_op
.name
);
1987 ret
= gen_ops
[which_op
].handler(instance
);
1989 talloc_free(current_op
.mem_ctx
);
1991 gen_ops
[which_op
].count
++;
1992 if (NT_STATUS_IS_OK(current_op
.status
)) {
1993 gen_ops
[which_op
].success_count
++;
1997 printf("Failed at operation %d - %s\n",
1998 op
, gen_ops
[which_op
].name
);
2002 if (op
% 100 == 0) {
2007 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
2008 printf("Op %-10s got %d/%d success\n",
2010 gen_ops
[i
].success_count
,
2018 perform a backtracking analysis of the minimal set of operations
2019 to generate an error
2021 static void backtrack_analyze(struct loadparm_context
*lp_ctx
)
2025 chunk
= options
.numops
/ 2;
2030 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
2033 chunk
= MIN(chunk
, options
.numops
/ 2);
2035 /* mark this range as disabled */
2036 max
= MIN(options
.numops
, base
+chunk
);
2037 for (i
=base
;i
<max
; i
++) {
2038 op_parms
[i
].disabled
= true;
2040 printf("Testing %d ops with %d-%d disabled\n",
2041 options
.numops
, base
, max
-1);
2042 ret
= run_test(lp_ctx
);
2043 printf("Completed %d of %d ops\n", ret
, options
.numops
);
2044 for (i
=base
;i
<max
; i
++) {
2045 op_parms
[i
].disabled
= false;
2047 if (ret
== options
.numops
) {
2048 /* this chunk is needed */
2050 } else if (ret
< base
) {
2051 printf("damn - inconsistent errors! found early error\n");
2052 options
.numops
= ret
+1;
2055 /* it failed - this chunk isn't needed for a failure */
2056 memmove(&op_parms
[base
], &op_parms
[max
],
2057 sizeof(op_parms
[0]) * (options
.numops
- max
));
2058 options
.numops
= (ret
+1) - (max
- base
);
2068 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
2071 } while (chunk
> 0);
2073 printf("Reduced to %d ops\n", options
.numops
);
2074 ret
= run_test(lp_ctx
);
2075 if (ret
!= options
.numops
- 1) {
2076 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
2081 start the main gentest process
2083 static bool start_gentest(struct loadparm_context
*lp_ctx
)
2088 /* allocate the open_handles array */
2089 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
2091 srandom(options
.seed
);
2092 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
2094 /* generate the seeds - after this everything is deterministic */
2095 if (options
.use_preset_seeds
) {
2097 char **preset
= file_lines_load(options
.seeds_file
, &numops
, NULL
);
2099 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
2102 if (numops
< options
.numops
) {
2103 options
.numops
= numops
;
2105 for (op
=0;op
<options
.numops
;op
++) {
2107 printf("Not enough seeds in %s\n", options
.seeds_file
);
2110 op_parms
[op
].seed
= atoi(preset
[op
]);
2112 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
2114 for (op
=0; op
<options
.numops
; op
++) {
2115 op_parms
[op
].seed
= random();
2119 ret
= run_test(lp_ctx
);
2121 if (ret
!= options
.numops
&& options
.analyze
) {
2122 options
.numops
= ret
+1;
2123 backtrack_analyze(lp_ctx
);
2124 } else if (options
.analyze_always
) {
2125 backtrack_analyze(lp_ctx
);
2126 } else if (options
.analyze_continuous
) {
2127 while (run_test(lp_ctx
) == options
.numops
) ;
2130 return ret
== options
.numops
;
2134 static void usage(poptContext pc
)
2138 gentest //server1/share1 //server2/share2 [options..]\n\
2140 poptPrintUsage(pc
, stdout
, 0);
2144 split a UNC name into server and share names
2146 static bool split_unc_name(const char *unc
, char **server
, char **share
)
2148 char *p
= strdup(unc
);
2149 if (!p
) return false;
2150 all_string_sub(p
, "\\", "/", 0);
2151 if (strncmp(p
, "//", 2) != 0) return false;
2154 p
= strchr(*server
, '/');
2155 if (!p
) return false;
2165 /****************************************************************************
2167 ****************************************************************************/
2168 int main(int argc
, char *argv
[])
2171 int i
, username_count
=0;
2173 char *ignore_file
=NULL
;
2174 struct loadparm_context
*lp_ctx
;
2178 enum {OPT_UNCLIST
=1000};
2179 struct poptOption long_options
[] = {
2181 {"seed", 0, POPT_ARG_INT
, &options
.seed
, 0, "Seed to use for randomizer", NULL
},
2182 {"num-ops", 0, POPT_ARG_INT
, &options
.numops
, 0, "num ops", NULL
},
2183 {"oplocks", 0, POPT_ARG_NONE
, &options
.use_oplocks
,0, "use oplocks", NULL
},
2184 {"showall", 0, POPT_ARG_NONE
, &options
.showall
, 0, "display all operations", NULL
},
2185 {"analyse", 0, POPT_ARG_NONE
, &options
.analyze
, 0, "do backtrack analysis", NULL
},
2186 {"analysealways", 0, POPT_ARG_NONE
, &options
.analyze_always
, 0, "analysis always", NULL
},
2187 {"analysecontinuous", 0, POPT_ARG_NONE
, &options
.analyze_continuous
, 0, "analysis continuous", NULL
},
2188 {"ignore", 0, POPT_ARG_STRING
, &ignore_file
, 0, "ignore from file", NULL
},
2189 {"preset", 0, POPT_ARG_NONE
, &options
.use_preset_seeds
, 0, "use preset seeds", NULL
},
2190 {"fast", 0, POPT_ARG_NONE
, &options
.fast_reconnect
, 0, "use fast reconnect", NULL
},
2191 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
2192 {"seedsfile", 0, POPT_ARG_STRING
, &options
.seeds_file
, 0, "seed file", NULL
},
2193 { "user", 'U', POPT_ARG_STRING
, NULL
, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
2195 POPT_COMMON_CONNECTION
2196 POPT_COMMON_CREDENTIALS
2202 options
.seed
= time(NULL
);
2203 options
.numops
= 1000;
2204 options
.max_open_handles
= 20;
2205 options
.seeds_file
= "gentest_seeds.dat";
2207 pc
= poptGetContext("gentest", argc
, (const char **) argv
, long_options
,
2208 POPT_CONTEXT_KEEP_FIRST
);
2210 poptSetOtherOptionHelp(pc
, "<unc1> <unc2>");
2212 lp_ctx
= cmdline_lp_ctx
;
2213 servers
[0].credentials
= cli_credentials_init(talloc_autofree_context());
2214 servers
[1].credentials
= cli_credentials_init(talloc_autofree_context());
2215 cli_credentials_guess(servers
[0].credentials
, lp_ctx
);
2216 cli_credentials_guess(servers
[1].credentials
, lp_ctx
);
2218 while((opt
= poptGetNextOpt(pc
)) != -1) {
2221 lp_set_cmdline(cmdline_lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
2224 if (username_count
== 2) {
2228 cli_credentials_parse_string(servers
[username_count
].credentials
, poptGetOptArg(pc
), CRED_SPECIFIED
);
2235 options
.ignore_patterns
= file_lines_load(ignore_file
, NULL
, NULL
);
2238 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
2240 for (i
=0; i
<argc
; i
++) {
2241 if (argv_new
[i
] == NULL
) {
2247 if (!(argc_new
>= 3)) {
2254 setup_logging("gentest", DEBUG_STDOUT
);
2256 if (argc
< 3 || argv
[1][0] == '-') {
2261 setup_logging(argv
[0], DEBUG_STDOUT
);
2263 for (i
=0;i
<NSERVERS
;i
++) {
2264 const char *share
= argv
[1+i
];
2265 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
2266 printf("Invalid share name '%s'\n", share
);
2271 if (username_count
== 0) {
2275 if (username_count
== 1) {
2276 servers
[1].credentials
= servers
[0].credentials
;
2279 printf("seed=%u\n", options
.seed
);
2281 gensec_init(lp_ctx
);
2283 ret
= start_gentest(lp_ctx
);
2286 printf("gentest completed - no errors\n");
2288 printf("gentest failed\n");