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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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/ndr_security.h"
28 #include "auth/gensec/gensec.h"
34 static struct gentest_options
{
38 BOOL analyze_continuous
;
39 uint_t max_open_handles
;
43 char **ignore_patterns
;
44 const char *seeds_file
;
45 BOOL use_preset_seeds
;
49 /* mapping between open handles on the server and local handles */
53 uint_t server_fnum
[NSERVERS
];
56 static uint_t num_open_handles
;
58 /* state information for the servers. We open NINSTANCES connections to
61 struct smbcli_state
*cli
[NINSTANCES
];
64 struct cli_credentials
*credentials
;
67 /* the seeds and flags for each operation */
74 /* oplock break info */
81 } oplocks
[NSERVERS
][NINSTANCES
];
83 /* change notify reply info */
87 struct smb_notify notify
;
88 } notifies
[NSERVERS
][NINSTANCES
];
90 /* info relevant to the current operation */
101 #define BAD_HANDLE 0xFFFE
103 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private);
104 static void idle_func(struct smbcli_transport
*transport
, void *private);
107 check if a string should be ignored. This is used as the basis
108 for all error ignore settings
110 static BOOL
ignore_pattern(const char *str
)
113 if (!options
.ignore_patterns
) return False
;
115 for (i
=0;options
.ignore_patterns
[i
];i
++) {
116 if (strcmp(options
.ignore_patterns
[i
], str
) == 0 ||
117 gen_fnmatch(options
.ignore_patterns
[i
], str
) == 0) {
118 DEBUG(2,("Ignoring '%s'\n", str
));
125 /*****************************************************
126 connect to the servers
127 *******************************************************/
128 static BOOL
connect_servers_fast(void)
132 /* close all open files */
133 for (h
=0;h
<options
.max_open_handles
;h
++) {
134 if (!open_handles
[h
].active
) continue;
135 for (i
=0;i
<NSERVERS
;i
++) {
136 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
137 open_handles
[h
].server_fnum
[i
])))) {
140 open_handles
[h
].active
= False
;
150 /*****************************************************
151 connect to the servers
152 *******************************************************/
153 static BOOL
connect_servers(void)
157 if (options
.fast_reconnect
&& servers
[0].cli
[0]) {
158 if (connect_servers_fast()) {
163 /* close any existing connections */
164 for (i
=0;i
<NSERVERS
;i
++) {
165 for (j
=0;j
<NINSTANCES
;j
++) {
166 if (servers
[i
].cli
[j
]) {
167 smbcli_tdis(servers
[i
].cli
[j
]);
168 talloc_free(servers
[i
].cli
[j
]);
169 servers
[i
].cli
[j
] = NULL
;
174 for (i
=0;i
<NSERVERS
;i
++) {
175 for (j
=0;j
<NINSTANCES
;j
++) {
177 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
178 servers
[i
].server_name
, servers
[i
].share_name
,
179 servers
[i
].credentials
->username
, j
);
181 cli_credentials_set_workstation(servers
[i
].credentials
,
182 "gentest", CRED_SPECIFIED
);
184 status
= smbcli_full_connection(NULL
, &servers
[i
].cli
[j
],
185 servers
[i
].server_name
,
186 servers
[i
].share_name
, NULL
,
187 servers
[i
].credentials
, NULL
);
188 if (!NT_STATUS_IS_OK(status
)) {
189 printf("Failed to connect to \\\\%s\\%s - %s\n",
190 servers
[i
].server_name
, servers
[i
].share_name
,
195 smbcli_oplock_handler(servers
[i
].cli
[j
]->transport
, oplock_handler
, NULL
);
196 smbcli_transport_idle_handler(servers
[i
].cli
[j
]->transport
, idle_func
, 50000, NULL
);
204 work out the time skew between the servers - be conservative
206 static uint_t
time_skew(void)
209 ret
= ABS(servers
[0].cli
[0]->transport
->negotiate
.server_time
-
210 servers
[1].cli
[0]->transport
->negotiate
.server_time
);
215 turn an fnum for an instance into a handle
217 static uint_t
fnum_to_handle(int server
, int instance
, uint16_t fnum
)
220 for (i
=0;i
<options
.max_open_handles
;i
++) {
221 if (!open_handles
[i
].active
||
222 instance
!= open_handles
[i
].instance
) continue;
223 if (open_handles
[i
].server_fnum
[server
] == fnum
) {
227 printf("Invalid fnum %d in fnum_to_handle on server %d instance %d\n",
228 fnum
, server
, instance
);
233 add some newly opened handles
235 static void gen_add_handle(int instance
, const char *name
, uint16_t fnums
[NSERVERS
])
238 for (h
=0;h
<options
.max_open_handles
;h
++) {
239 if (!open_handles
[h
].active
) break;
241 if (h
== options
.max_open_handles
) {
242 /* we have to force close a random handle */
243 h
= random() % options
.max_open_handles
;
244 for (i
=0;i
<NSERVERS
;i
++) {
245 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
246 open_handles
[h
].server_fnum
[i
])))) {
247 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
248 smbcli_errstr(servers
[i
].cli
[open_handles
[h
].instance
]->tree
));
251 printf("Recovered handle %d\n", h
);
254 for (i
=0;i
<NSERVERS
;i
++) {
255 open_handles
[h
].server_fnum
[i
] = fnums
[i
];
256 open_handles
[h
].instance
= instance
;
257 open_handles
[h
].active
= True
;
258 open_handles
[h
].name
= name
;
262 printf("OPEN num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
264 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
269 remove a closed handle
271 static void gen_remove_handle(int instance
, uint16_t fnums
[NSERVERS
])
274 for (h
=0;h
<options
.max_open_handles
;h
++) {
275 if (instance
== open_handles
[h
].instance
&&
276 open_handles
[h
].server_fnum
[0] == fnums
[0]) {
277 open_handles
[h
].active
= False
;
279 printf("CLOSE num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
281 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
282 open_handles
[h
].name
);
286 printf("Removing invalid handle!?\n");
291 return True with 'chance' probability as a percentage
293 static BOOL
gen_chance(uint_t chance
)
295 return ((random() % 100) <= chance
);
299 map an internal handle number to a server fnum
301 static uint16_t gen_lookup_fnum(int server
, uint16_t handle
)
303 if (handle
== BAD_HANDLE
) return handle
;
304 return open_handles
[handle
].server_fnum
[server
];
310 static uint16_t gen_fnum(int instance
)
315 if (gen_chance(20)) return BAD_HANDLE
;
317 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
318 h
= random() % options
.max_open_handles
;
319 if (open_handles
[h
].active
&&
320 open_handles
[h
].instance
== instance
) {
328 return a file handle, but skewed so we don't close the last
329 couple of handles too readily
331 static uint16_t gen_fnum_close(int instance
)
333 if (num_open_handles
< 3) {
334 if (gen_chance(80)) return BAD_HANDLE
;
337 return gen_fnum(instance
);
341 generate an integer in a specified range
343 static int gen_int_range(uint_t min
, uint_t max
)
346 return min
+ (r
% (1+max
-min
));
350 return a fnum for use as a root fid
351 be careful to call GEN_SET_FNUM() when you use this!
353 static uint16_t gen_root_fid(int instance
)
355 if (gen_chance(5)) return gen_fnum(instance
);
360 generate a file offset
362 static int gen_offset(void)
364 if (gen_chance(20)) return 0;
365 return gen_int_range(0, 1024*1024);
371 static int gen_io_count(void)
373 if (gen_chance(20)) return 0;
374 return gen_int_range(0, 4096);
380 static const char *gen_fname(void)
382 const char *names
[] = {"\\gentest\\gentest.dat",
384 "\\gentest\\foo2.sym",
385 "\\gentest\\foo3.dll",
387 "\\gentest\\foo4:teststream1",
388 "\\gentest\\foo4:teststream2",
389 "\\gentest\\foo5.exe",
390 "\\gentest\\foo5.exe:teststream3",
391 "\\gentest\\foo5.exe:teststream4",
392 "\\gentest\\foo6.com",
394 "\\gentest\\blah\\blergh.txt",
395 "\\gentest\\blah\\blergh2",
396 "\\gentest\\blah\\blergh3.txt",
397 "\\gentest\\blah\\blergh4",
398 "\\gentest\\blah\\blergh5.txt",
399 "\\gentest\\blah\\blergh5",
400 "\\gentest\\blah\\.",
402 /* this causes problem with w2k3 */
403 "\\gentest\\blah\\..",
405 "\\gentest\\a_very_long_name.bin",
411 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
412 } while (ignore_pattern(names
[i
]));
418 generate a filename with a higher chance of choosing an already
421 static const char *gen_fname_open(int instance
)
424 h
= gen_fnum(instance
);
425 if (h
== BAD_HANDLE
) {
428 return open_handles
[h
].name
;
432 generate a wildcard pattern
434 static const char *gen_pattern(void)
437 const char *names
[] = {"\\gentest\\*.dat",
440 "\\gentest\\blah\\*.*",
441 "\\gentest\\blah\\*",
444 if (gen_chance(50)) return gen_fname();
447 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
448 } while (ignore_pattern(names
[i
]));
456 static uint32_t gen_bits_mask(uint_t mask
)
458 uint_t ret
= random();
463 generate a bitmask with high probability of the first mask
464 and low of the second
466 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
468 if (gen_chance(10)) return gen_bits_mask(mask2
);
469 return gen_bits_mask(mask1
);
475 static BOOL
gen_bool(void)
477 return gen_bits_mask2(0x1, 0xFF);
481 generate ntrename flags
483 static uint16_t gen_rename_flags(void)
485 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
486 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
487 if (gen_chance(30)) return RENAME_FLAG_COPY
;
488 return gen_bits_mask(0xFFFF);
493 return a lockingx lock mode
495 static uint16_t gen_lock_mode(void)
497 if (gen_chance(5)) return gen_bits_mask(0xFFFF);
498 if (gen_chance(20)) return gen_bits_mask(0x1F);
499 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
505 static uint16_t gen_pid(void)
507 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
512 generate a lock count
514 static off_t
gen_lock_count(void)
516 return gen_int_range(0, 3);
520 generate a ntcreatex flags field
522 static uint32_t gen_ntcreatex_flags(void)
524 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
525 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
529 generate a NT access mask
531 static uint32_t gen_access_mask(void)
533 if (gen_chance(50)) return SEC_FLAG_MAXIMUM_ALLOWED
;
534 if (gen_chance(20)) return SEC_FILE_ALL
;
535 return gen_bits_mask(0xFFFFFFFF);
539 generate a ntcreatex create options bitfield
541 static uint32_t gen_create_options(void)
543 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
544 if (gen_chance(50)) return 0;
545 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
549 generate a ntcreatex open disposition
551 static uint32_t gen_open_disp(void)
553 if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
554 return gen_int_range(0, 5);
558 generate an openx open mode
560 static uint16_t gen_openx_mode(void)
562 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
563 if (gen_chance(20)) return gen_bits_mask(0xFF);
564 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
568 generate an openx flags field
570 static uint16_t gen_openx_flags(void)
572 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
573 return gen_bits_mask(0x7);
577 generate an openx open function
579 static uint16_t gen_openx_func(void)
581 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
582 return gen_bits_mask(0x13);
586 generate a file attrib combination
588 static uint32_t gen_attrib(void)
590 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
591 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
595 generate a unix timestamp
597 static time_t gen_timet(void)
599 if (gen_chance(30)) return 0;
600 return (time_t)random();
604 generate a unix timestamp
606 static NTTIME
gen_nttime(void)
609 unix_to_nt_time(&ret
, gen_timet());
614 generate a milliseconds protocol timeout
616 static uint32_t gen_timeout(void)
618 if (gen_chance(98)) return 0;
619 return random() % 50;
623 generate a file allocation size
625 static uint_t
gen_alloc_size(void)
629 if (gen_chance(30)) return 0;
631 ret
= random() % 4*1024*1024;
632 /* give a high chance of a round number */
633 if (gen_chance(60)) {
634 ret
&= ~(1024*1024 - 1);
640 generate an ea_struct
642 static struct ea_struct
gen_ea_struct(void)
645 const char *names
[] = {"EAONE",
650 "AVERYLONGATTRIBUTENAME"};
651 const char *values
[] = {"VALUE1",
656 "ASOMEWHATLONGERATTRIBUTEVALUE"};
660 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
661 } while (ignore_pattern(names
[i
]));
663 ea
.name
.s
= names
[i
];
666 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
667 } while (ignore_pattern(values
[i
]));
669 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
671 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
679 this is called when a change notify reply comes in
681 static void async_notify(struct smbcli_request
*req
)
683 struct smb_notify notify
;
687 struct smbcli_transport
*transport
= req
->transport
;
689 tid
= SVAL(req
->in
.hdr
, HDR_TID
);
691 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
692 if (NT_STATUS_IS_OK(status
)) {
693 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
695 notify
.out
.num_changes
,
696 notify
.out
.changes
[0].action
,
697 notify
.out
.changes
[0].name
.s
);
700 for (i
=0;i
<NSERVERS
;i
++) {
701 for (j
=0;j
<NINSTANCES
;j
++) {
702 if (transport
== servers
[i
].cli
[j
]->transport
&&
703 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
704 notifies
[i
][j
].notify_count
++;
705 notifies
[i
][j
].status
= status
;
706 notifies
[i
][j
].notify
= notify
;
712 static void oplock_handler_close_recv(struct smbcli_request
*req
)
715 status
= smbcli_request_simple_recv(req
);
716 if (!NT_STATUS_IS_OK(status
)) {
717 printf("close failed in oplock_handler\n");
718 smb_panic("close failed in oplock_handler");
723 the oplock handler will either ack the break or close the file
725 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private)
731 struct smbcli_tree
*tree
= NULL
;
732 struct smbcli_request
*req
;
734 srandom(current_op
.seed
);
735 do_close
= gen_chance(50);
737 for (i
=0;i
<NSERVERS
;i
++) {
738 for (j
=0;j
<NINSTANCES
;j
++) {
739 if (transport
== servers
[i
].cli
[j
]->transport
&&
740 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
741 oplocks
[i
][j
].got_break
= True
;
742 oplocks
[i
][j
].fnum
= fnum
;
743 oplocks
[i
][j
].handle
= fnum_to_handle(i
, j
, fnum
);
744 oplocks
[i
][j
].level
= level
;
745 oplocks
[i
][j
].do_close
= do_close
;
746 tree
= servers
[i
].cli
[j
]->tree
;
752 printf("Oplock break not for one of our trees!?\n");
757 printf("oplock ack fnum=%d\n", fnum
);
758 return smbcli_oplock_ack(tree
, fnum
, level
);
761 printf("oplock close fnum=%d\n", fnum
);
763 io
.close
.level
= RAW_CLOSE_CLOSE
;
764 io
.close
.in
.fnum
= fnum
;
765 io
.close
.in
.write_time
= 0;
766 req
= smb_raw_close_send(tree
, &io
);
769 printf("WARNING: close failed in oplock_handler_close - %s\n",
774 req
->async
.fn
= oplock_handler_close_recv
;
775 req
->async
.private = NULL
;
782 the idle function tries to cope with getting an oplock break on a connection, and
783 an operation on another connection blocking until that break is acked
784 we check for operations on all transports in the idle function
786 static void idle_func(struct smbcli_transport
*transport
, void *private)
789 for (i
=0;i
<NSERVERS
;i
++) {
790 for (j
=0;j
<NINSTANCES
;j
++) {
791 if (servers
[i
].cli
[j
] &&
792 transport
!= servers
[i
].cli
[j
]->transport
) {
793 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
802 compare NTSTATUS, using checking ignored patterns
804 static BOOL
compare_status(NTSTATUS status1
, NTSTATUS status2
)
806 if (NT_STATUS_EQUAL(status1
, status2
)) return True
;
808 /* one code being an error and the other OK is always an error */
809 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) return False
;
811 /* if we are ignoring one of the status codes then consider this a match */
812 if (ignore_pattern(nt_errstr(status1
)) ||
813 ignore_pattern(nt_errstr(status2
))) {
821 check for pending packets on all connections
823 static void check_pending(void)
829 for (j
=0;j
<NINSTANCES
;j
++) {
830 for (i
=0;i
<NSERVERS
;i
++) {
831 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
837 check that the same oplock breaks have been received by all instances
839 static BOOL
check_oplocks(const char *call
)
847 for (j
=0;j
<NINSTANCES
;j
++) {
848 for (i
=1;i
<NSERVERS
;i
++) {
849 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
850 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
851 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
852 if (tries
++ < 10) goto again
;
853 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
854 oplocks
[0][j
].got_break
,
855 oplocks
[0][j
].handle
,
857 oplocks
[i
][j
].got_break
,
858 oplocks
[i
][j
].handle
,
859 oplocks
[i
][j
].level
);
865 /* if we got a break and closed then remove the handle */
866 for (j
=0;j
<NINSTANCES
;j
++) {
867 if (oplocks
[0][j
].got_break
&&
868 oplocks
[0][j
].do_close
) {
869 uint16_t fnums
[NSERVERS
];
870 for (i
=0;i
<NSERVERS
;i
++) {
871 fnums
[i
] = oplocks
[i
][j
].fnum
;
873 gen_remove_handle(j
, fnums
);
882 check that the same change notify info has been received by all instances
884 static BOOL
check_notifies(const char *call
)
892 for (j
=0;j
<NINSTANCES
;j
++) {
893 for (i
=1;i
<NSERVERS
;i
++) {
895 struct smb_notify not1
, not2
;
897 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
898 if (tries
++ < 10) goto again
;
899 printf("Notify count inconsistent %d %d\n",
900 notifies
[0][j
].notify_count
,
901 notifies
[i
][j
].notify_count
);
905 if (notifies
[0][j
].notify_count
== 0) continue;
907 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
908 notifies
[i
][j
].status
)) {
909 printf("Notify status mismatch - %s - %s\n",
910 nt_errstr(notifies
[0][j
].status
),
911 nt_errstr(notifies
[i
][j
].status
));
915 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
919 not1
= notifies
[0][j
].notify
;
920 not2
= notifies
[i
][j
].notify
;
922 for (n
=0;n
<not1
.out
.num_changes
;n
++) {
923 if (not1
.out
.changes
[n
].action
!=
924 not2
.out
.changes
[n
].action
) {
925 printf("Notify action %d inconsistent %d %d\n", n
,
926 not1
.out
.changes
[n
].action
,
927 not2
.out
.changes
[n
].action
);
930 if (strcmp(not1
.out
.changes
[n
].name
.s
,
931 not2
.out
.changes
[n
].name
.s
)) {
932 printf("Notify name %d inconsistent %s %s\n", n
,
933 not1
.out
.changes
[n
].name
.s
,
934 not2
.out
.changes
[n
].name
.s
);
937 if (not1
.out
.changes
[n
].name
.private_length
!=
938 not2
.out
.changes
[n
].name
.private_length
) {
939 printf("Notify name length %d inconsistent %d %d\n", n
,
940 not1
.out
.changes
[n
].name
.private_length
,
941 not2
.out
.changes
[n
].name
.private_length
);
948 ZERO_STRUCT(notifies
);
954 #define GEN_COPY_PARM do { \
956 for (i=1;i<NSERVERS;i++) { \
961 #define GEN_CALL(call) do { \
963 ZERO_STRUCT(oplocks); \
964 ZERO_STRUCT(notifies); \
965 for (i=0;i<NSERVERS;i++) { \
966 struct smbcli_tree *tree = servers[i].cli[instance]->tree; \
969 current_op.status = status[0]; \
970 for (i=1;i<NSERVERS;i++) { \
971 if (!compare_status(status[i], status[0])) { \
972 printf("status different in %s - %s %s\n", #call, \
973 nt_errstr(status[0]), nt_errstr(status[i])); \
977 if (!check_oplocks(#call)) return False; \
978 if (!check_notifies(#call)) return False; \
979 if (!NT_STATUS_IS_OK(status[0])) { \
984 #define ADD_HANDLE(name, field) do { \
985 uint16_t fnums[NSERVERS]; \
987 for (i=0;i<NSERVERS;i++) { \
988 fnums[i] = parm[i].field; \
990 gen_add_handle(instance, name, fnums); \
993 #define REMOVE_HANDLE(field) do { \
994 uint16_t fnums[NSERVERS]; \
996 for (i=0;i<NSERVERS;i++) { \
997 fnums[i] = parm[i].field; \
999 gen_remove_handle(instance, fnums); \
1002 #define GEN_SET_FNUM(field) do { \
1004 for (i=0;i<NSERVERS;i++) { \
1005 parm[i].field = gen_lookup_fnum(i, parm[i].field); \
1009 #define CHECK_EQUAL(field) do { \
1010 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1011 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1012 (int)parm[0].field, (int)parm[1].field); \
1017 #define CHECK_WSTR_EQUAL(field) do { \
1018 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1019 printf("%s is NULL!\n", #field); \
1022 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1023 printf("Mismatch in %s - %s %s\n", #field, \
1024 parm[0].field.s, parm[1].field.s); \
1027 CHECK_EQUAL(field.private_length); \
1030 #define CHECK_BLOB_EQUAL(field) do { \
1031 if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1032 printf("Mismatch in %s\n", #field); \
1035 CHECK_EQUAL(field.length); \
1038 #define CHECK_TIMES_EQUAL(field) do { \
1039 if (ABS(parm[0].field - parm[1].field) > time_skew() && \
1040 !ignore_pattern(#field)) { \
1041 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1042 (int)parm[0].field, (int)parm[1].field); \
1047 #define CHECK_NTTIMES_EQUAL(field) do { \
1048 if (ABS(nt_time_to_unix(parm[0].field) - \
1049 nt_time_to_unix(parm[1].field)) > time_skew() && \
1050 !ignore_pattern(#field)) { \
1051 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1052 (int)nt_time_to_unix(parm[0].field), \
1053 (int)nt_time_to_unix(parm[1].field)); \
1059 generate openx operations
1061 static BOOL
handler_openx(int instance
)
1063 union smb_open parm
[NSERVERS
];
1064 NTSTATUS status
[NSERVERS
];
1066 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1067 parm
[0].openx
.in
.flags
= gen_openx_flags();
1068 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1069 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1070 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1071 parm
[0].openx
.in
.write_time
= gen_timet();
1072 parm
[0].openx
.in
.open_func
= gen_openx_func();
1073 parm
[0].openx
.in
.size
= gen_io_count();
1074 parm
[0].openx
.in
.timeout
= gen_timeout();
1075 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1077 if (!options
.use_oplocks
) {
1078 /* mask out oplocks */
1079 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1080 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1084 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1086 CHECK_EQUAL(openx
.out
.attrib
);
1087 CHECK_EQUAL(openx
.out
.size
);
1088 CHECK_EQUAL(openx
.out
.access
);
1089 CHECK_EQUAL(openx
.out
.ftype
);
1090 CHECK_EQUAL(openx
.out
.devstate
);
1091 CHECK_EQUAL(openx
.out
.action
);
1092 CHECK_EQUAL(openx
.out
.access_mask
);
1093 CHECK_EQUAL(openx
.out
.unknown
);
1094 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1096 /* open creates a new file handle */
1097 ADD_HANDLE(parm
[0].openx
.in
.fname
, openx
.out
.fnum
);
1104 generate open operations
1106 static BOOL
handler_open(int instance
)
1108 union smb_open parm
[NSERVERS
];
1109 NTSTATUS status
[NSERVERS
];
1111 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1112 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1113 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1114 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1116 if (!options
.use_oplocks
) {
1117 /* mask out oplocks */
1118 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1119 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1123 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1125 CHECK_EQUAL(openold
.out
.attrib
);
1126 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1127 CHECK_EQUAL(openold
.out
.size
);
1128 CHECK_EQUAL(openold
.out
.rmode
);
1130 /* open creates a new file handle */
1131 ADD_HANDLE(parm
[0].openold
.in
.fname
, openold
.out
.fnum
);
1138 generate ntcreatex operations
1140 static BOOL
handler_ntcreatex(int instance
)
1142 union smb_open parm
[NSERVERS
];
1143 NTSTATUS status
[NSERVERS
];
1145 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1146 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1147 parm
[0].ntcreatex
.in
.root_fid
= gen_root_fid(instance
);
1148 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1149 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1150 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1151 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1152 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1153 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1154 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1155 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1156 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1158 if (!options
.use_oplocks
) {
1159 /* mask out oplocks */
1160 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1161 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1165 if (parm
[0].ntcreatex
.in
.root_fid
!= 0) {
1166 GEN_SET_FNUM(ntcreatex
.in
.root_fid
);
1168 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1170 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1171 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1172 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1173 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1174 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1175 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1176 CHECK_EQUAL(ntcreatex
.out
.attrib
);
1177 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1178 CHECK_EQUAL(ntcreatex
.out
.size
);
1179 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1180 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1181 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1183 /* ntcreatex creates a new file handle */
1184 ADD_HANDLE(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.fnum
);
1190 generate close operations
1192 static BOOL
handler_close(int instance
)
1194 union smb_close parm
[NSERVERS
];
1195 NTSTATUS status
[NSERVERS
];
1197 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1198 parm
[0].close
.in
.fnum
= gen_fnum_close(instance
);
1199 parm
[0].close
.in
.write_time
= gen_timet();
1202 GEN_SET_FNUM(close
.in
.fnum
);
1203 GEN_CALL(smb_raw_close(tree
, &parm
[i
]));
1205 REMOVE_HANDLE(close
.in
.fnum
);
1211 generate unlink operations
1213 static BOOL
handler_unlink(int instance
)
1215 struct smb_unlink parm
[NSERVERS
];
1216 NTSTATUS status
[NSERVERS
];
1218 parm
[0].in
.pattern
= gen_pattern();
1219 parm
[0].in
.attrib
= gen_attrib();
1222 GEN_CALL(smb_raw_unlink(tree
, &parm
[i
]));
1228 generate chkpath operations
1230 static BOOL
handler_chkpath(int instance
)
1232 struct smb_chkpath parm
[NSERVERS
];
1233 NTSTATUS status
[NSERVERS
];
1235 parm
[0].in
.path
= gen_fname_open(instance
);
1238 GEN_CALL(smb_raw_chkpath(tree
, &parm
[i
]));
1244 generate mkdir operations
1246 static BOOL
handler_mkdir(int instance
)
1248 union smb_mkdir parm
[NSERVERS
];
1249 NTSTATUS status
[NSERVERS
];
1251 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1252 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1255 GEN_CALL(smb_raw_mkdir(tree
, &parm
[i
]));
1261 generate rmdir operations
1263 static BOOL
handler_rmdir(int instance
)
1265 struct smb_rmdir parm
[NSERVERS
];
1266 NTSTATUS status
[NSERVERS
];
1268 parm
[0].in
.path
= gen_fname_open(instance
);
1271 GEN_CALL(smb_raw_rmdir(tree
, &parm
[i
]));
1277 generate rename operations
1279 static BOOL
handler_rename(int instance
)
1281 union smb_rename parm
[NSERVERS
];
1282 NTSTATUS status
[NSERVERS
];
1284 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1285 parm
[0].rename
.in
.pattern1
= gen_pattern();
1286 parm
[0].rename
.in
.pattern2
= gen_pattern();
1287 parm
[0].rename
.in
.attrib
= gen_attrib();
1290 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1296 generate ntrename operations
1298 static BOOL
handler_ntrename(int instance
)
1300 union smb_rename parm
[NSERVERS
];
1301 NTSTATUS status
[NSERVERS
];
1303 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1304 parm
[0].ntrename
.in
.old_name
= gen_fname();
1305 parm
[0].ntrename
.in
.new_name
= gen_fname();
1306 parm
[0].ntrename
.in
.attrib
= gen_attrib();
1307 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
1308 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
1311 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1318 generate seek operations
1320 static BOOL
handler_seek(int instance
)
1322 struct smb_seek parm
[NSERVERS
];
1323 NTSTATUS status
[NSERVERS
];
1325 parm
[0].in
.fnum
= gen_fnum(instance
);
1326 parm
[0].in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
1327 parm
[0].in
.offset
= gen_offset();
1330 GEN_SET_FNUM(in
.fnum
);
1331 GEN_CALL(smb_raw_seek(tree
, &parm
[i
]));
1333 CHECK_EQUAL(out
.offset
);
1340 generate readx operations
1342 static BOOL
handler_readx(int instance
)
1344 union smb_read parm
[NSERVERS
];
1345 NTSTATUS status
[NSERVERS
];
1347 parm
[0].readx
.level
= RAW_READ_READX
;
1348 parm
[0].readx
.in
.fnum
= gen_fnum(instance
);
1349 parm
[0].readx
.in
.offset
= gen_offset();
1350 parm
[0].readx
.in
.mincnt
= gen_io_count();
1351 parm
[0].readx
.in
.maxcnt
= gen_io_count();
1352 parm
[0].readx
.in
.remaining
= gen_io_count();
1353 parm
[0].readx
.out
.data
= talloc_size(current_op
.mem_ctx
,
1354 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
1357 GEN_SET_FNUM(readx
.in
.fnum
);
1358 GEN_CALL(smb_raw_read(tree
, &parm
[i
]));
1360 CHECK_EQUAL(readx
.out
.remaining
);
1361 CHECK_EQUAL(readx
.out
.compaction_mode
);
1362 CHECK_EQUAL(readx
.out
.nread
);
1368 generate writex operations
1370 static BOOL
handler_writex(int instance
)
1372 union smb_write parm
[NSERVERS
];
1373 NTSTATUS status
[NSERVERS
];
1375 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
1376 parm
[0].writex
.in
.fnum
= gen_fnum(instance
);
1377 parm
[0].writex
.in
.offset
= gen_offset();
1378 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
1379 parm
[0].writex
.in
.remaining
= gen_io_count();
1380 parm
[0].writex
.in
.count
= gen_io_count();
1381 parm
[0].writex
.in
.data
= talloc_zero_size(current_op
.mem_ctx
, parm
[0].writex
.in
.count
);
1384 GEN_SET_FNUM(writex
.in
.fnum
);
1385 GEN_CALL(smb_raw_write(tree
, &parm
[i
]));
1387 CHECK_EQUAL(writex
.out
.nwritten
);
1388 CHECK_EQUAL(writex
.out
.remaining
);
1394 generate lockingx operations
1396 static BOOL
handler_lockingx(int instance
)
1398 union smb_lock parm
[NSERVERS
];
1399 NTSTATUS status
[NSERVERS
];
1402 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
1403 parm
[0].lockx
.in
.fnum
= gen_fnum(instance
);
1404 parm
[0].lockx
.in
.mode
= gen_lock_mode();
1405 parm
[0].lockx
.in
.timeout
= gen_timeout();
1407 /* make sure we don't accidentially generate an oplock
1408 break ack - otherwise the server can just block forever */
1409 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
1410 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
1411 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
1412 } while (nlocks
== 0);
1415 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
1416 struct smb_lock_entry
,
1418 for (n
=0;n
<nlocks
;n
++) {
1419 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
1420 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
1421 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
1426 GEN_SET_FNUM(lockx
.in
.fnum
);
1427 GEN_CALL(smb_raw_lock(tree
, &parm
[i
]));
1433 generate a fileinfo query structure
1435 static void gen_fileinfo(int instance
, union smb_fileinfo
*info
)
1438 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1440 enum smb_fileinfo_level level
;
1443 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
1444 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
1445 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
1446 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
1447 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
1448 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
1449 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
1450 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
1451 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
1452 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
1455 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1456 } while (ignore_pattern(levels
[i
].name
));
1458 info
->generic
.level
= levels
[i
].level
;
1462 compare returned fileinfo structures
1464 static BOOL
cmp_fileinfo(int instance
,
1465 union smb_fileinfo parm
[NSERVERS
],
1466 NTSTATUS status
[NSERVERS
])
1470 switch (parm
[0].generic
.level
) {
1471 case RAW_FILEINFO_GENERIC
:
1474 case RAW_FILEINFO_GETATTR
:
1475 CHECK_EQUAL(getattr
.out
.attrib
);
1476 CHECK_EQUAL(getattr
.out
.size
);
1477 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1480 case RAW_FILEINFO_GETATTRE
:
1481 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1482 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1483 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1484 CHECK_EQUAL(getattre
.out
.size
);
1485 CHECK_EQUAL(getattre
.out
.alloc_size
);
1486 CHECK_EQUAL(getattre
.out
.attrib
);
1489 case RAW_FILEINFO_STANDARD
:
1490 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1491 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1492 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1493 CHECK_EQUAL(standard
.out
.size
);
1494 CHECK_EQUAL(standard
.out
.alloc_size
);
1495 CHECK_EQUAL(standard
.out
.attrib
);
1498 case RAW_FILEINFO_EA_SIZE
:
1499 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1500 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1501 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1502 CHECK_EQUAL(ea_size
.out
.size
);
1503 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1504 CHECK_EQUAL(ea_size
.out
.attrib
);
1505 CHECK_EQUAL(ea_size
.out
.ea_size
);
1508 case RAW_FILEINFO_ALL_EAS
:
1509 CHECK_EQUAL(all_eas
.out
.num_eas
);
1510 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1511 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1512 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1513 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1517 case RAW_FILEINFO_IS_NAME_VALID
:
1520 case RAW_FILEINFO_BASIC_INFO
:
1521 case RAW_FILEINFO_BASIC_INFORMATION
:
1522 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1523 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1524 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1525 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1526 CHECK_EQUAL(basic_info
.out
.attrib
);
1529 case RAW_FILEINFO_STANDARD_INFO
:
1530 case RAW_FILEINFO_STANDARD_INFORMATION
:
1531 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1532 CHECK_EQUAL(standard_info
.out
.size
);
1533 CHECK_EQUAL(standard_info
.out
.nlink
);
1534 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1535 CHECK_EQUAL(standard_info
.out
.directory
);
1538 case RAW_FILEINFO_EA_INFO
:
1539 case RAW_FILEINFO_EA_INFORMATION
:
1540 CHECK_EQUAL(ea_info
.out
.ea_size
);
1543 case RAW_FILEINFO_NAME_INFO
:
1544 case RAW_FILEINFO_NAME_INFORMATION
:
1545 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1548 case RAW_FILEINFO_ALL_INFO
:
1549 case RAW_FILEINFO_ALL_INFORMATION
:
1550 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1551 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1552 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1553 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1554 CHECK_EQUAL(all_info
.out
.attrib
);
1555 CHECK_EQUAL(all_info
.out
.alloc_size
);
1556 CHECK_EQUAL(all_info
.out
.size
);
1557 CHECK_EQUAL(all_info
.out
.nlink
);
1558 CHECK_EQUAL(all_info
.out
.delete_pending
);
1559 CHECK_EQUAL(all_info
.out
.directory
);
1560 CHECK_EQUAL(all_info
.out
.ea_size
);
1561 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1564 case RAW_FILEINFO_ALT_NAME_INFO
:
1565 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1566 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1569 case RAW_FILEINFO_STREAM_INFO
:
1570 case RAW_FILEINFO_STREAM_INFORMATION
:
1571 CHECK_EQUAL(stream_info
.out
.num_streams
);
1572 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1573 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1574 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1575 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1579 case RAW_FILEINFO_COMPRESSION_INFO
:
1580 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1581 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1582 CHECK_EQUAL(compression_info
.out
.format
);
1583 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1584 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1585 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1588 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1589 CHECK_EQUAL(internal_information
.out
.file_id
);
1592 case RAW_FILEINFO_ACCESS_INFORMATION
:
1593 CHECK_EQUAL(access_information
.out
.access_flags
);
1596 case RAW_FILEINFO_POSITION_INFORMATION
:
1597 CHECK_EQUAL(position_information
.out
.position
);
1600 case RAW_FILEINFO_MODE_INFORMATION
:
1601 CHECK_EQUAL(mode_information
.out
.mode
);
1604 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1605 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1608 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1609 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1610 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1611 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1612 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1613 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1614 CHECK_EQUAL(network_open_information
.out
.size
);
1615 CHECK_EQUAL(network_open_information
.out
.attrib
);
1618 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1619 CHECK_EQUAL(attribute_tag_information
.out
.attrib
);
1620 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1623 /* Unhandled levels */
1625 case RAW_FILEINFO_SEC_DESC
:
1626 case RAW_FILEINFO_EA_LIST
:
1627 case RAW_FILEINFO_UNIX_BASIC
:
1628 case RAW_FILEINFO_UNIX_LINK
:
1636 generate qpathinfo operations
1638 static BOOL
handler_qpathinfo(int instance
)
1640 union smb_fileinfo parm
[NSERVERS
];
1641 NTSTATUS status
[NSERVERS
];
1643 parm
[0].generic
.in
.fname
= gen_fname_open(instance
);
1645 gen_fileinfo(instance
, &parm
[0]);
1648 GEN_CALL(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1650 return cmp_fileinfo(instance
, parm
, status
);
1654 generate qfileinfo operations
1656 static BOOL
handler_qfileinfo(int instance
)
1658 union smb_fileinfo parm
[NSERVERS
];
1659 NTSTATUS status
[NSERVERS
];
1661 parm
[0].generic
.in
.fnum
= gen_fnum(instance
);
1663 gen_fileinfo(instance
, &parm
[0]);
1666 GEN_SET_FNUM(generic
.in
.fnum
);
1667 GEN_CALL(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1669 return cmp_fileinfo(instance
, parm
, status
);
1674 generate a fileinfo query structure
1676 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
1680 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1682 enum smb_setfileinfo_level level
;
1686 /* disabled until win2003 can handle them ... */
1687 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
1688 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
1690 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
1691 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
1692 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
1693 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
1694 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1697 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1698 } while (ignore_pattern(levels
[i
].name
));
1700 info
->generic
.level
= levels
[i
].level
;
1702 switch (info
->generic
.level
) {
1703 case RAW_SFILEINFO_SETATTR
:
1704 info
->setattr
.in
.attrib
= gen_attrib();
1705 info
->setattr
.in
.write_time
= gen_timet();
1707 case RAW_SFILEINFO_SETATTRE
:
1708 info
->setattre
.in
.create_time
= gen_timet();
1709 info
->setattre
.in
.access_time
= gen_timet();
1710 info
->setattre
.in
.write_time
= gen_timet();
1712 case RAW_SFILEINFO_STANDARD
:
1713 info
->standard
.in
.create_time
= gen_timet();
1714 info
->standard
.in
.access_time
= gen_timet();
1715 info
->standard
.in
.write_time
= gen_timet();
1717 case RAW_SFILEINFO_EA_SET
: {
1718 static struct ea_struct ea
;
1719 info
->ea_set
.in
.num_eas
= 1;
1720 info
->ea_set
.in
.eas
= &ea
;
1721 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
1724 case RAW_SFILEINFO_BASIC_INFO
:
1725 case RAW_SFILEINFO_BASIC_INFORMATION
:
1726 info
->basic_info
.in
.create_time
= gen_nttime();
1727 info
->basic_info
.in
.access_time
= gen_nttime();
1728 info
->basic_info
.in
.write_time
= gen_nttime();
1729 info
->basic_info
.in
.change_time
= gen_nttime();
1730 info
->basic_info
.in
.attrib
= gen_attrib();
1732 case RAW_SFILEINFO_DISPOSITION_INFO
:
1733 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
1734 info
->disposition_info
.in
.delete_on_close
= gen_bool();
1736 case RAW_SFILEINFO_ALLOCATION_INFO
:
1737 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
1738 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
1740 case RAW_SFILEINFO_END_OF_FILE_INFO
:
1741 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
1742 info
->end_of_file_info
.in
.size
= gen_offset();
1744 case RAW_SFILEINFO_RENAME_INFORMATION
:
1745 info
->rename_information
.in
.overwrite
= gen_bool();
1746 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
1747 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
1749 case RAW_SFILEINFO_POSITION_INFORMATION
:
1750 info
->position_information
.in
.position
= gen_offset();
1752 case RAW_SFILEINFO_MODE_INFORMATION
:
1753 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
1755 case RAW_SFILEINFO_GENERIC
:
1756 case RAW_SFILEINFO_SEC_DESC
:
1757 case RAW_SFILEINFO_UNIX_BASIC
:
1758 case RAW_SFILEINFO_UNIX_LINK
:
1759 case RAW_SFILEINFO_UNIX_HLINK
:
1760 case RAW_SFILEINFO_1023
:
1761 case RAW_SFILEINFO_1025
:
1762 case RAW_SFILEINFO_1029
:
1763 case RAW_SFILEINFO_1032
:
1764 case RAW_SFILEINFO_1039
:
1765 case RAW_SFILEINFO_1040
:
1772 generate setpathinfo operations
1774 static BOOL
handler_spathinfo(int instance
)
1776 union smb_setfileinfo parm
[NSERVERS
];
1777 NTSTATUS status
[NSERVERS
];
1779 parm
[0].generic
.file
.fname
= gen_fname_open(instance
);
1781 gen_setfileinfo(instance
, &parm
[0]);
1785 /* a special case for the fid in a RENAME */
1786 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
1787 parm
[0].rename_information
.in
.root_fid
!= 0) {
1788 GEN_SET_FNUM(rename_information
.in
.root_fid
);
1791 GEN_CALL(smb_raw_setpathinfo(tree
, &parm
[i
]));
1798 generate setfileinfo operations
1800 static BOOL
handler_sfileinfo(int instance
)
1802 union smb_setfileinfo parm
[NSERVERS
];
1803 NTSTATUS status
[NSERVERS
];
1805 parm
[0].generic
.file
.fnum
= gen_fnum(instance
);
1807 gen_setfileinfo(instance
, &parm
[0]);
1810 GEN_SET_FNUM(generic
.file
.fnum
);
1811 GEN_CALL(smb_raw_setfileinfo(tree
, &parm
[i
]));
1818 generate change notify operations
1820 static BOOL
handler_notify(int instance
)
1822 struct smb_notify parm
[NSERVERS
];
1825 parm
[0].in
.buffer_size
= gen_io_count();
1826 parm
[0].in
.completion_filter
= gen_bits_mask(0xFF);
1827 parm
[0].in
.fnum
= gen_fnum(instance
);
1828 parm
[0].in
.recursive
= gen_bool();
1831 GEN_SET_FNUM(in
.fnum
);
1833 for (n
=0;n
<NSERVERS
;n
++) {
1834 struct smbcli_request
*req
;
1835 req
= smb_raw_changenotify_send(servers
[n
].cli
[instance
]->tree
, &parm
[n
]);
1836 req
->async
.fn
= async_notify
;
1843 wipe any relevant files
1845 static void wipe_files(void)
1848 for (i
=0;i
<NSERVERS
;i
++) {
1849 int n
= smbcli_deltree(servers
[i
].cli
[0]->tree
, "\\gentest");
1851 printf("Failed to wipe tree on server %d\n", i
);
1854 if (NT_STATUS_IS_ERR(smbcli_mkdir(servers
[i
].cli
[0]->tree
, "\\gentest"))) {
1855 printf("Failed to create \\gentest - %s\n",
1856 smbcli_errstr(servers
[i
].cli
[0]->tree
));
1860 printf("Deleted %d files on server %d\n", n
, i
);
1866 dump the current seeds - useful for continuing a backtrack
1868 static void dump_seeds(void)
1873 if (!options
.seeds_file
) {
1876 f
= fopen("seeds.tmp", "w");
1879 for (i
=0;i
<options
.numops
;i
++) {
1880 fprintf(f
, "%u\n", op_parms
[i
].seed
);
1883 rename("seeds.tmp", options
.seeds_file
);
1889 the list of top-level operations that we will generate
1893 BOOL (*handler
)(int instance
);
1894 int count
, success_count
;
1896 {"OPEN", handler_open
},
1897 {"OPENX", handler_openx
},
1898 {"NTCREATEX", handler_ntcreatex
},
1899 {"CLOSE", handler_close
},
1900 {"UNLINK", handler_unlink
},
1901 {"MKDIR", handler_mkdir
},
1902 {"RMDIR", handler_rmdir
},
1903 {"RENAME", handler_rename
},
1904 {"NTRENAME", handler_ntrename
},
1905 {"READX", handler_readx
},
1906 {"WRITEX", handler_writex
},
1907 {"CHKPATH", handler_chkpath
},
1908 {"LOCKINGX", handler_lockingx
},
1909 {"QPATHINFO", handler_qpathinfo
},
1910 {"QFILEINFO", handler_qfileinfo
},
1911 {"SPATHINFO", handler_spathinfo
},
1912 {"SFILEINFO", handler_sfileinfo
},
1913 {"NOTIFY", handler_notify
},
1914 {"SEEK", handler_seek
},
1919 run the test with the current set of op_parms parameters
1920 return the number of operations that completed successfully
1922 static int run_test(void)
1926 if (!connect_servers()) {
1927 printf("Failed to connect to servers\n");
1933 /* wipe any leftover files from old runs */
1936 /* reset the open handles array */
1937 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
1938 num_open_handles
= 0;
1940 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1941 gen_ops
[i
].count
= 0;
1942 gen_ops
[i
].success_count
= 0;
1945 for (op
=0; op
<options
.numops
; op
++) {
1946 int instance
, which_op
;
1949 if (op_parms
[op
].disabled
) continue;
1951 srandom(op_parms
[op
].seed
);
1953 instance
= gen_int_range(0, NINSTANCES
-1);
1955 /* generate a non-ignored operation */
1957 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
1958 } while (ignore_pattern(gen_ops
[which_op
].name
));
1960 DEBUG(3,("Generating op %s on instance %d\n",
1961 gen_ops
[which_op
].name
, instance
));
1963 current_op
.seed
= op_parms
[op
].seed
;
1964 current_op
.opnum
= op
;
1965 current_op
.name
= gen_ops
[which_op
].name
;
1966 current_op
.status
= NT_STATUS_OK
;
1967 current_op
.mem_ctx
= talloc_init("%s", current_op
.name
);
1969 ret
= gen_ops
[which_op
].handler(instance
);
1971 talloc_free(current_op
.mem_ctx
);
1973 gen_ops
[which_op
].count
++;
1974 if (NT_STATUS_IS_OK(current_op
.status
)) {
1975 gen_ops
[which_op
].success_count
++;
1979 printf("Failed at operation %d - %s\n",
1980 op
, gen_ops
[which_op
].name
);
1984 if (op
% 100 == 0) {
1989 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1990 printf("Op %-10s got %d/%d success\n",
1992 gen_ops
[i
].success_count
,
2000 perform a backtracking analysis of the minimal set of operations
2001 to generate an error
2003 static void backtrack_analyze(void)
2007 chunk
= options
.numops
/ 2;
2012 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
2015 chunk
= MIN(chunk
, options
.numops
/ 2);
2017 /* mark this range as disabled */
2018 max
= MIN(options
.numops
, base
+chunk
);
2019 for (i
=base
;i
<max
; i
++) {
2020 op_parms
[i
].disabled
= True
;
2022 printf("Testing %d ops with %d-%d disabled\n",
2023 options
.numops
, base
, max
-1);
2025 printf("Completed %d of %d ops\n", ret
, options
.numops
);
2026 for (i
=base
;i
<max
; i
++) {
2027 op_parms
[i
].disabled
= False
;
2029 if (ret
== options
.numops
) {
2030 /* this chunk is needed */
2032 } else if (ret
< base
) {
2033 printf("damn - inconsistent errors! found early error\n");
2034 options
.numops
= ret
+1;
2037 /* it failed - this chunk isn't needed for a failure */
2038 memmove(&op_parms
[base
], &op_parms
[max
],
2039 sizeof(op_parms
[0]) * (options
.numops
- max
));
2040 options
.numops
= (ret
+1) - (max
- base
);
2050 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
2053 } while (chunk
> 0);
2055 printf("Reduced to %d ops\n", options
.numops
);
2057 if (ret
!= options
.numops
- 1) {
2058 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
2063 start the main gentest process
2065 static BOOL
start_gentest(void)
2070 /* allocate the open_handles array */
2071 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
2073 srandom(options
.seed
);
2074 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
2076 /* generate the seeds - after this everything is deterministic */
2077 if (options
.use_preset_seeds
) {
2079 char **preset
= file_lines_load(options
.seeds_file
, &numops
, NULL
);
2081 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
2084 if (numops
< options
.numops
) {
2085 options
.numops
= numops
;
2087 for (op
=0;op
<options
.numops
;op
++) {
2089 printf("Not enough seeds in %s\n", options
.seeds_file
);
2092 op_parms
[op
].seed
= atoi(preset
[op
]);
2094 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
2096 for (op
=0; op
<options
.numops
; op
++) {
2097 op_parms
[op
].seed
= random();
2103 if (ret
!= options
.numops
&& options
.analyze
) {
2104 options
.numops
= ret
+1;
2105 backtrack_analyze();
2106 } else if (options
.analyze_always
) {
2107 backtrack_analyze();
2108 } else if (options
.analyze_continuous
) {
2109 while (run_test() == options
.numops
) ;
2112 return ret
== options
.numops
;
2116 static void usage(void)
2120 gentest2 //server1/share1 //server2/share2 [options..]\n\
2122 -U user%%pass (can be specified twice)\n\
2125 -a (show all ops)\n\
2126 -A backtrack to find minimal ops\n\
2127 -i FILE add a list of wildcard exclusions\n\
2128 -O enable oplocks\n\
2129 -S FILE set preset seeds file\n\
2130 -L use preset seeds\n\
2131 -F fast reconnect (just close files)\n\
2132 -C continuous analysis mode\n\
2133 -X analyse even when test OK\n\
2137 /****************************************************************************
2139 ****************************************************************************/
2140 int main(int argc
, char *argv
[])
2143 int i
, username_count
=0;
2148 setup_logging("gentest", DEBUG_STDOUT
);
2150 if (argc
< 3 || argv
[1][0] == '-') {
2155 setup_logging(argv
[0], DEBUG_STDOUT
);
2157 for (i
=0;i
<NSERVERS
;i
++) {
2158 const char *share
= argv
[1+i
];
2159 servers
[i
].credentials
= cli_credentials_init(NULL
);
2160 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
2161 printf("Invalid share name '%s'\n", share
);
2171 servers
[0].credentials
= cli_credentials_init(talloc_autofree_context());
2172 servers
[1].credentials
= cli_credentials_init(talloc_autofree_context());
2173 cli_credentials_guess(servers
[0].credentials
);
2174 cli_credentials_guess(servers
[1].credentials
);
2176 options
.seed
= time(NULL
);
2177 options
.numops
= 1000;
2178 options
.max_open_handles
= 20;
2179 options
.seeds_file
= "gentest_seeds.dat";
2181 while ((opt
= getopt(argc
, argv
, "U:s:o:ad:i:AOhS:LFXC")) != EOF
) {
2184 if (username_count
== 2) {
2188 cli_credentials_parse_string(servers
[username_count
].credentials
,
2189 optarg
, CRED_SPECIFIED
);
2193 DEBUGLEVEL
= atoi(optarg
);
2194 setup_logging(NULL
, DEBUG_STDOUT
);
2197 options
.seed
= atoi(optarg
);
2200 options
.seeds_file
= optarg
;
2203 options
.use_preset_seeds
= True
;
2206 options
.fast_reconnect
= True
;
2209 options
.numops
= atoi(optarg
);
2212 options
.use_oplocks
= True
;
2215 options
.showall
= True
;
2218 options
.analyze
= True
;
2221 options
.analyze_always
= True
;
2224 options
.analyze_continuous
= True
;
2227 options
.ignore_patterns
= file_lines_load(optarg
, NULL
, NULL
);
2233 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
2240 if (username_count
== 0) {
2244 if (username_count
== 1) {
2245 servers
[1].credentials
= servers
[0].credentials
;
2248 printf("seed=%u\n", options
.seed
);
2250 ret
= start_gentest();
2253 printf("gentest completed - no errors\n");
2255 printf("gentest failed\n");