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/security.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
35 static struct gentest_options
{
39 BOOL analyze_continuous
;
40 uint_t max_open_handles
;
44 char **ignore_patterns
;
45 const char *seeds_file
;
46 BOOL use_preset_seeds
;
50 /* mapping between open handles on the server and local handles */
54 uint_t server_fnum
[NSERVERS
];
57 static uint_t num_open_handles
;
59 /* state information for the servers. We open NINSTANCES connections to
62 struct smbcli_state
*cli
[NINSTANCES
];
65 struct cli_credentials
*credentials
;
68 /* the seeds and flags for each operation */
75 /* oplock break info */
82 } oplocks
[NSERVERS
][NINSTANCES
];
84 /* change notify reply info */
88 union smb_notify notify
;
89 } notifies
[NSERVERS
][NINSTANCES
];
91 /* info relevant to the current operation */
102 #define BAD_HANDLE 0xFFFE
104 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private);
105 static void idle_func(struct smbcli_transport
*transport
, void *private);
108 check if a string should be ignored. This is used as the basis
109 for all error ignore settings
111 static BOOL
ignore_pattern(const char *str
)
114 if (!options
.ignore_patterns
) return False
;
116 for (i
=0;options
.ignore_patterns
[i
];i
++) {
117 if (strcmp(options
.ignore_patterns
[i
], str
) == 0 ||
118 gen_fnmatch(options
.ignore_patterns
[i
], str
) == 0) {
119 DEBUG(2,("Ignoring '%s'\n", str
));
126 /*****************************************************
127 connect to the servers
128 *******************************************************/
129 static BOOL
connect_servers_fast(void)
133 /* close all open files */
134 for (h
=0;h
<options
.max_open_handles
;h
++) {
135 if (!open_handles
[h
].active
) continue;
136 for (i
=0;i
<NSERVERS
;i
++) {
137 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
138 open_handles
[h
].server_fnum
[i
])))) {
141 open_handles
[h
].active
= False
;
151 /*****************************************************
152 connect to the servers
153 *******************************************************/
154 static BOOL
connect_servers(void)
158 if (options
.fast_reconnect
&& servers
[0].cli
[0]) {
159 if (connect_servers_fast()) {
164 /* close any existing connections */
165 for (i
=0;i
<NSERVERS
;i
++) {
166 for (j
=0;j
<NINSTANCES
;j
++) {
167 if (servers
[i
].cli
[j
]) {
168 smbcli_tdis(servers
[i
].cli
[j
]);
169 talloc_free(servers
[i
].cli
[j
]);
170 servers
[i
].cli
[j
] = NULL
;
175 for (i
=0;i
<NSERVERS
;i
++) {
176 for (j
=0;j
<NINSTANCES
;j
++) {
178 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
179 servers
[i
].server_name
, servers
[i
].share_name
,
180 servers
[i
].credentials
->username
, j
);
182 cli_credentials_set_workstation(servers
[i
].credentials
,
183 "gentest", CRED_SPECIFIED
);
185 status
= smbcli_full_connection(NULL
, &servers
[i
].cli
[j
],
186 servers
[i
].server_name
,
187 servers
[i
].share_name
, NULL
,
188 servers
[i
].credentials
, NULL
);
189 if (!NT_STATUS_IS_OK(status
)) {
190 printf("Failed to connect to \\\\%s\\%s - %s\n",
191 servers
[i
].server_name
, servers
[i
].share_name
,
196 smbcli_oplock_handler(servers
[i
].cli
[j
]->transport
, oplock_handler
, NULL
);
197 smbcli_transport_idle_handler(servers
[i
].cli
[j
]->transport
, idle_func
, 50000, NULL
);
205 work out the time skew between the servers - be conservative
207 static uint_t
time_skew(void)
210 ret
= labs(servers
[0].cli
[0]->transport
->negotiate
.server_time
-
211 servers
[1].cli
[0]->transport
->negotiate
.server_time
);
216 turn an fnum for an instance into a handle
218 static uint_t
fnum_to_handle(int server
, int instance
, uint16_t fnum
)
221 for (i
=0;i
<options
.max_open_handles
;i
++) {
222 if (!open_handles
[i
].active
||
223 instance
!= open_handles
[i
].instance
) continue;
224 if (open_handles
[i
].server_fnum
[server
] == fnum
) {
228 printf("Invalid fnum %d in fnum_to_handle on server %d instance %d\n",
229 fnum
, server
, instance
);
234 add some newly opened handles
236 static void gen_add_handle(int instance
, const char *name
, uint16_t fnums
[NSERVERS
])
239 for (h
=0;h
<options
.max_open_handles
;h
++) {
240 if (!open_handles
[h
].active
) break;
242 if (h
== options
.max_open_handles
) {
243 /* we have to force close a random handle */
244 h
= random() % options
.max_open_handles
;
245 for (i
=0;i
<NSERVERS
;i
++) {
246 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
247 open_handles
[h
].server_fnum
[i
])))) {
248 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
249 smbcli_errstr(servers
[i
].cli
[open_handles
[h
].instance
]->tree
));
252 printf("Recovered handle %d\n", h
);
255 for (i
=0;i
<NSERVERS
;i
++) {
256 open_handles
[h
].server_fnum
[i
] = fnums
[i
];
257 open_handles
[h
].instance
= instance
;
258 open_handles
[h
].active
= True
;
259 open_handles
[h
].name
= name
;
263 printf("OPEN num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
265 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
270 remove a closed handle
272 static void gen_remove_handle(int instance
, uint16_t fnums
[NSERVERS
])
275 for (h
=0;h
<options
.max_open_handles
;h
++) {
276 if (instance
== open_handles
[h
].instance
&&
277 open_handles
[h
].server_fnum
[0] == fnums
[0]) {
278 open_handles
[h
].active
= False
;
280 printf("CLOSE num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
282 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
283 open_handles
[h
].name
);
287 printf("Removing invalid handle!?\n");
292 return True with 'chance' probability as a percentage
294 static BOOL
gen_chance(uint_t chance
)
296 return ((random() % 100) <= chance
);
300 map an internal handle number to a server fnum
302 static uint16_t gen_lookup_fnum(int server
, uint16_t handle
)
304 if (handle
== BAD_HANDLE
) return handle
;
305 return open_handles
[handle
].server_fnum
[server
];
311 static uint16_t gen_fnum(int instance
)
316 if (gen_chance(20)) return BAD_HANDLE
;
318 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
319 h
= random() % options
.max_open_handles
;
320 if (open_handles
[h
].active
&&
321 open_handles
[h
].instance
== instance
) {
329 return a file handle, but skewed so we don't close the last
330 couple of handles too readily
332 static uint16_t gen_fnum_close(int instance
)
334 if (num_open_handles
< 3) {
335 if (gen_chance(80)) return BAD_HANDLE
;
338 return gen_fnum(instance
);
342 generate an integer in a specified range
344 static int gen_int_range(uint_t min
, uint_t max
)
347 return min
+ (r
% (1+max
-min
));
351 return a fnum for use as a root fid
352 be careful to call GEN_SET_FNUM() when you use this!
354 static uint16_t gen_root_fid(int instance
)
356 if (gen_chance(5)) return gen_fnum(instance
);
361 generate a file offset
363 static int gen_offset(void)
365 if (gen_chance(20)) return 0;
366 return gen_int_range(0, 1024*1024);
372 static int gen_io_count(void)
374 if (gen_chance(20)) return 0;
375 return gen_int_range(0, 4096);
381 static const char *gen_fname(void)
383 const char *names
[] = {"\\gentest\\gentest.dat",
385 "\\gentest\\foo2.sym",
386 "\\gentest\\foo3.dll",
388 "\\gentest\\foo4:teststream1",
389 "\\gentest\\foo4:teststream2",
390 "\\gentest\\foo5.exe",
391 "\\gentest\\foo5.exe:teststream3",
392 "\\gentest\\foo5.exe:teststream4",
393 "\\gentest\\foo6.com",
395 "\\gentest\\blah\\blergh.txt",
396 "\\gentest\\blah\\blergh2",
397 "\\gentest\\blah\\blergh3.txt",
398 "\\gentest\\blah\\blergh4",
399 "\\gentest\\blah\\blergh5.txt",
400 "\\gentest\\blah\\blergh5",
401 "\\gentest\\blah\\.",
403 /* this causes problem with w2k3 */
404 "\\gentest\\blah\\..",
406 "\\gentest\\a_very_long_name.bin",
412 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
413 } while (ignore_pattern(names
[i
]));
419 generate a filename with a higher chance of choosing an already
422 static const char *gen_fname_open(int instance
)
425 h
= gen_fnum(instance
);
426 if (h
== BAD_HANDLE
) {
429 return open_handles
[h
].name
;
433 generate a wildcard pattern
435 static const char *gen_pattern(void)
438 const char *names
[] = {"\\gentest\\*.dat",
441 "\\gentest\\blah\\*.*",
442 "\\gentest\\blah\\*",
445 if (gen_chance(50)) return gen_fname();
448 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
449 } while (ignore_pattern(names
[i
]));
457 static uint32_t gen_bits_mask(uint_t mask
)
459 uint_t ret
= random();
464 generate a bitmask with high probability of the first mask
465 and low of the second
467 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
469 if (gen_chance(10)) return gen_bits_mask(mask2
);
470 return gen_bits_mask(mask1
);
476 static BOOL
gen_bool(void)
478 return gen_bits_mask2(0x1, 0xFF);
482 generate ntrename flags
484 static uint16_t gen_rename_flags(void)
486 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
487 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
488 if (gen_chance(30)) return RENAME_FLAG_COPY
;
489 return gen_bits_mask(0xFFFF);
494 return a lockingx lock mode
496 static uint16_t gen_lock_mode(void)
498 if (gen_chance(5)) return gen_bits_mask(0xFFFF);
499 if (gen_chance(20)) return gen_bits_mask(0x1F);
500 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
506 static uint16_t gen_pid(void)
508 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
513 generate a lock count
515 static off_t
gen_lock_count(void)
517 return gen_int_range(0, 3);
521 generate a ntcreatex flags field
523 static uint32_t gen_ntcreatex_flags(void)
525 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
526 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
530 generate a NT access mask
532 static uint32_t gen_access_mask(void)
534 if (gen_chance(50)) return SEC_FLAG_MAXIMUM_ALLOWED
;
535 if (gen_chance(20)) return SEC_FILE_ALL
;
536 return gen_bits_mask(0xFFFFFFFF);
540 generate a ntcreatex create options bitfield
542 static uint32_t gen_create_options(void)
544 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
545 if (gen_chance(50)) return 0;
546 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
550 generate a ntcreatex open disposition
552 static uint32_t gen_open_disp(void)
554 if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
555 return gen_int_range(0, 5);
559 generate an openx open mode
561 static uint16_t gen_openx_mode(void)
563 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
564 if (gen_chance(20)) return gen_bits_mask(0xFF);
565 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
569 generate an openx flags field
571 static uint16_t gen_openx_flags(void)
573 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
574 return gen_bits_mask(0x7);
578 generate an openx open function
580 static uint16_t gen_openx_func(void)
582 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
583 return gen_bits_mask(0x13);
587 generate a file attrib combination
589 static uint32_t gen_attrib(void)
591 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
592 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
596 generate a unix timestamp
598 static time_t gen_timet(void)
600 if (gen_chance(30)) return 0;
601 return (time_t)random();
605 generate a unix timestamp
607 static NTTIME
gen_nttime(void)
610 unix_to_nt_time(&ret
, gen_timet());
615 generate a milliseconds protocol timeout
617 static uint32_t gen_timeout(void)
619 if (gen_chance(98)) return 0;
620 return random() % 50;
624 generate a file allocation size
626 static uint_t
gen_alloc_size(void)
630 if (gen_chance(30)) return 0;
632 ret
= random() % 4*1024*1024;
633 /* give a high chance of a round number */
634 if (gen_chance(60)) {
635 ret
&= ~(1024*1024 - 1);
641 generate an ea_struct
643 static struct ea_struct
gen_ea_struct(void)
646 const char *names
[] = {"EAONE",
651 "AVERYLONGATTRIBUTENAME"};
652 const char *values
[] = {"VALUE1",
657 "ASOMEWHATLONGERATTRIBUTEVALUE"};
663 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
664 } while (ignore_pattern(names
[i
]));
666 ea
.name
.s
= names
[i
];
669 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
670 } while (ignore_pattern(values
[i
]));
672 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
674 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
682 this is called when a change notify reply comes in
684 static void async_notify(struct smbcli_request
*req
)
686 union smb_notify notify
;
690 struct smbcli_transport
*transport
= req
->transport
;
692 tid
= SVAL(req
->in
.hdr
, HDR_TID
);
694 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
695 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
696 if (NT_STATUS_IS_OK(status
)) {
697 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
699 notify
.nttrans
.out
.num_changes
,
700 notify
.nttrans
.out
.changes
[0].action
,
701 notify
.nttrans
.out
.changes
[0].name
.s
);
704 for (i
=0;i
<NSERVERS
;i
++) {
705 for (j
=0;j
<NINSTANCES
;j
++) {
706 if (transport
== servers
[i
].cli
[j
]->transport
&&
707 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
708 notifies
[i
][j
].notify_count
++;
709 notifies
[i
][j
].status
= status
;
710 notifies
[i
][j
].notify
= notify
;
716 static void oplock_handler_close_recv(struct smbcli_request
*req
)
719 status
= smbcli_request_simple_recv(req
);
720 if (!NT_STATUS_IS_OK(status
)) {
721 printf("close failed in oplock_handler\n");
722 smb_panic("close failed in oplock_handler");
727 the oplock handler will either ack the break or close the file
729 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private)
734 struct smbcli_tree
*tree
= NULL
;
735 struct smbcli_request
*req
;
737 srandom(current_op
.seed
);
738 do_close
= gen_chance(50);
740 for (i
=0;i
<NSERVERS
;i
++) {
741 for (j
=0;j
<NINSTANCES
;j
++) {
742 if (transport
== servers
[i
].cli
[j
]->transport
&&
743 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
744 oplocks
[i
][j
].got_break
= True
;
745 oplocks
[i
][j
].fnum
= fnum
;
746 oplocks
[i
][j
].handle
= fnum_to_handle(i
, j
, fnum
);
747 oplocks
[i
][j
].level
= level
;
748 oplocks
[i
][j
].do_close
= do_close
;
749 tree
= servers
[i
].cli
[j
]->tree
;
755 printf("Oplock break not for one of our trees!?\n");
760 printf("oplock ack fnum=%d\n", fnum
);
761 return smbcli_oplock_ack(tree
, fnum
, level
);
764 printf("oplock close fnum=%d\n", fnum
);
766 io
.close
.level
= RAW_CLOSE_CLOSE
;
767 io
.close
.in
.file
.fnum
= fnum
;
768 io
.close
.in
.write_time
= 0;
769 req
= smb_raw_close_send(tree
, &io
);
772 printf("WARNING: close failed in oplock_handler_close\n");
776 req
->async
.fn
= oplock_handler_close_recv
;
777 req
->async
.private = NULL
;
784 the idle function tries to cope with getting an oplock break on a connection, and
785 an operation on another connection blocking until that break is acked
786 we check for operations on all transports in the idle function
788 static void idle_func(struct smbcli_transport
*transport
, void *private)
791 for (i
=0;i
<NSERVERS
;i
++) {
792 for (j
=0;j
<NINSTANCES
;j
++) {
793 if (servers
[i
].cli
[j
] &&
794 transport
!= servers
[i
].cli
[j
]->transport
) {
795 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
804 compare NTSTATUS, using checking ignored patterns
806 static BOOL
compare_status(NTSTATUS status1
, NTSTATUS status2
)
808 if (NT_STATUS_EQUAL(status1
, status2
)) return True
;
810 /* one code being an error and the other OK is always an error */
811 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) return False
;
813 /* if we are ignoring one of the status codes then consider this a match */
814 if (ignore_pattern(nt_errstr(status1
)) ||
815 ignore_pattern(nt_errstr(status2
))) {
823 check for pending packets on all connections
825 static void check_pending(void)
831 for (j
=0;j
<NINSTANCES
;j
++) {
832 for (i
=0;i
<NSERVERS
;i
++) {
833 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
839 check that the same oplock breaks have been received by all instances
841 static BOOL
check_oplocks(const char *call
)
849 for (j
=0;j
<NINSTANCES
;j
++) {
850 for (i
=1;i
<NSERVERS
;i
++) {
851 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
852 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
853 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
854 if (tries
++ < 10) goto again
;
855 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
856 oplocks
[0][j
].got_break
,
857 oplocks
[0][j
].handle
,
859 oplocks
[i
][j
].got_break
,
860 oplocks
[i
][j
].handle
,
861 oplocks
[i
][j
].level
);
867 /* if we got a break and closed then remove the handle */
868 for (j
=0;j
<NINSTANCES
;j
++) {
869 if (oplocks
[0][j
].got_break
&&
870 oplocks
[0][j
].do_close
) {
871 uint16_t fnums
[NSERVERS
];
872 for (i
=0;i
<NSERVERS
;i
++) {
873 fnums
[i
] = oplocks
[i
][j
].fnum
;
875 gen_remove_handle(j
, fnums
);
884 check that the same change notify info has been received by all instances
886 static BOOL
check_notifies(const char *call
)
894 for (j
=0;j
<NINSTANCES
;j
++) {
895 for (i
=1;i
<NSERVERS
;i
++) {
897 union smb_notify not1
, not2
;
899 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
900 if (tries
++ < 10) goto again
;
901 printf("Notify count inconsistent %d %d\n",
902 notifies
[0][j
].notify_count
,
903 notifies
[i
][j
].notify_count
);
907 if (notifies
[0][j
].notify_count
== 0) continue;
909 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
910 notifies
[i
][j
].status
)) {
911 printf("Notify status mismatch - %s - %s\n",
912 nt_errstr(notifies
[0][j
].status
),
913 nt_errstr(notifies
[i
][j
].status
));
917 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
921 not1
= notifies
[0][j
].notify
;
922 not2
= notifies
[i
][j
].notify
;
924 for (n
=0;n
<not1
.nttrans
.out
.num_changes
;n
++) {
925 if (not1
.nttrans
.out
.changes
[n
].action
!=
926 not2
.nttrans
.out
.changes
[n
].action
) {
927 printf("Notify action %d inconsistent %d %d\n", n
,
928 not1
.nttrans
.out
.changes
[n
].action
,
929 not2
.nttrans
.out
.changes
[n
].action
);
932 if (strcmp(not1
.nttrans
.out
.changes
[n
].name
.s
,
933 not2
.nttrans
.out
.changes
[n
].name
.s
)) {
934 printf("Notify name %d inconsistent %s %s\n", n
,
935 not1
.nttrans
.out
.changes
[n
].name
.s
,
936 not2
.nttrans
.out
.changes
[n
].name
.s
);
939 if (not1
.nttrans
.out
.changes
[n
].name
.private_length
!=
940 not2
.nttrans
.out
.changes
[n
].name
.private_length
) {
941 printf("Notify name length %d inconsistent %d %d\n", n
,
942 not1
.nttrans
.out
.changes
[n
].name
.private_length
,
943 not2
.nttrans
.out
.changes
[n
].name
.private_length
);
950 ZERO_STRUCT(notifies
);
956 #define GEN_COPY_PARM do { \
958 for (i=1;i<NSERVERS;i++) { \
963 #define GEN_CALL(call) do { \
965 ZERO_STRUCT(oplocks); \
966 ZERO_STRUCT(notifies); \
967 for (i=0;i<NSERVERS;i++) { \
968 struct smbcli_tree *tree = servers[i].cli[instance]->tree; \
971 current_op.status = status[0]; \
972 for (i=1;i<NSERVERS;i++) { \
973 if (!compare_status(status[i], status[0])) { \
974 printf("status different in %s - %s %s\n", #call, \
975 nt_errstr(status[0]), nt_errstr(status[i])); \
979 if (!check_oplocks(#call)) return False; \
980 if (!check_notifies(#call)) return False; \
981 if (!NT_STATUS_IS_OK(status[0])) { \
986 #define ADD_HANDLE(name, field) do { \
987 uint16_t fnums[NSERVERS]; \
989 for (i=0;i<NSERVERS;i++) { \
990 fnums[i] = parm[i].field; \
992 gen_add_handle(instance, name, fnums); \
995 #define REMOVE_HANDLE(field) do { \
996 uint16_t fnums[NSERVERS]; \
998 for (i=0;i<NSERVERS;i++) { \
999 fnums[i] = parm[i].field; \
1001 gen_remove_handle(instance, fnums); \
1004 #define GEN_SET_FNUM(field) do { \
1006 for (i=0;i<NSERVERS;i++) { \
1007 parm[i].field = gen_lookup_fnum(i, parm[i].field); \
1011 #define CHECK_EQUAL(field) do { \
1012 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1013 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1014 (int)parm[0].field, (int)parm[1].field); \
1019 #define CHECK_WSTR_EQUAL(field) do { \
1020 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1021 printf("%s is NULL!\n", #field); \
1024 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1025 printf("Mismatch in %s - %s %s\n", #field, \
1026 parm[0].field.s, parm[1].field.s); \
1029 CHECK_EQUAL(field.private_length); \
1032 #define CHECK_BLOB_EQUAL(field) do { \
1033 if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1034 printf("Mismatch in %s\n", #field); \
1037 CHECK_EQUAL(field.length); \
1040 #define CHECK_TIMES_EQUAL(field) do { \
1041 if (labs(parm[0].field - parm[1].field) > time_skew() && \
1042 !ignore_pattern(#field)) { \
1043 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1044 (int)parm[0].field, (int)parm[1].field); \
1049 #define CHECK_NTTIMES_EQUAL(field) do { \
1050 if (labs(nt_time_to_unix(parm[0].field) - \
1051 nt_time_to_unix(parm[1].field)) > time_skew() && \
1052 !ignore_pattern(#field)) { \
1053 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1054 (int)nt_time_to_unix(parm[0].field), \
1055 (int)nt_time_to_unix(parm[1].field)); \
1061 generate openx operations
1063 static BOOL
handler_openx(int instance
)
1065 union smb_open parm
[NSERVERS
];
1066 NTSTATUS status
[NSERVERS
];
1068 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1069 parm
[0].openx
.in
.flags
= gen_openx_flags();
1070 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1071 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1072 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1073 parm
[0].openx
.in
.write_time
= gen_timet();
1074 parm
[0].openx
.in
.open_func
= gen_openx_func();
1075 parm
[0].openx
.in
.size
= gen_io_count();
1076 parm
[0].openx
.in
.timeout
= gen_timeout();
1077 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1079 if (!options
.use_oplocks
) {
1080 /* mask out oplocks */
1081 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1082 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1086 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1088 CHECK_EQUAL(openx
.out
.attrib
);
1089 CHECK_EQUAL(openx
.out
.size
);
1090 CHECK_EQUAL(openx
.out
.access
);
1091 CHECK_EQUAL(openx
.out
.ftype
);
1092 CHECK_EQUAL(openx
.out
.devstate
);
1093 CHECK_EQUAL(openx
.out
.action
);
1094 CHECK_EQUAL(openx
.out
.access_mask
);
1095 CHECK_EQUAL(openx
.out
.unknown
);
1096 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1098 /* open creates a new file handle */
1099 ADD_HANDLE(parm
[0].openx
.in
.fname
, openx
.out
.file
.fnum
);
1106 generate open operations
1108 static BOOL
handler_open(int instance
)
1110 union smb_open parm
[NSERVERS
];
1111 NTSTATUS status
[NSERVERS
];
1113 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1114 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1115 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1116 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1118 if (!options
.use_oplocks
) {
1119 /* mask out oplocks */
1120 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1121 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1125 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1127 CHECK_EQUAL(openold
.out
.attrib
);
1128 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1129 CHECK_EQUAL(openold
.out
.size
);
1130 CHECK_EQUAL(openold
.out
.rmode
);
1132 /* open creates a new file handle */
1133 ADD_HANDLE(parm
[0].openold
.in
.fname
, openold
.out
.file
.fnum
);
1140 generate ntcreatex operations
1142 static BOOL
handler_ntcreatex(int instance
)
1144 union smb_open parm
[NSERVERS
];
1145 NTSTATUS status
[NSERVERS
];
1147 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1148 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1149 parm
[0].ntcreatex
.in
.root_fid
= gen_root_fid(instance
);
1150 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1151 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1152 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1153 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1154 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1155 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1156 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1157 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1158 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1160 if (!options
.use_oplocks
) {
1161 /* mask out oplocks */
1162 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1163 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1167 if (parm
[0].ntcreatex
.in
.root_fid
!= 0) {
1168 GEN_SET_FNUM(ntcreatex
.in
.root_fid
);
1170 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1172 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1173 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1174 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1175 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1176 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1177 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1178 CHECK_EQUAL(ntcreatex
.out
.attrib
);
1179 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1180 CHECK_EQUAL(ntcreatex
.out
.size
);
1181 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1182 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1183 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1185 /* ntcreatex creates a new file handle */
1186 ADD_HANDLE(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.file
.fnum
);
1192 generate close operations
1194 static BOOL
handler_close(int instance
)
1196 union smb_close parm
[NSERVERS
];
1197 NTSTATUS status
[NSERVERS
];
1199 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1200 parm
[0].close
.in
.file
.fnum
= gen_fnum_close(instance
);
1201 parm
[0].close
.in
.write_time
= gen_timet();
1204 GEN_SET_FNUM(close
.in
.file
.fnum
);
1205 GEN_CALL(smb_raw_close(tree
, &parm
[i
]));
1207 REMOVE_HANDLE(close
.in
.file
.fnum
);
1213 generate unlink operations
1215 static BOOL
handler_unlink(int instance
)
1217 union smb_unlink parm
[NSERVERS
];
1218 NTSTATUS status
[NSERVERS
];
1220 parm
[0].unlink
.in
.pattern
= gen_pattern();
1221 parm
[0].unlink
.in
.attrib
= gen_attrib();
1224 GEN_CALL(smb_raw_unlink(tree
, &parm
[i
]));
1230 generate chkpath operations
1232 static BOOL
handler_chkpath(int instance
)
1234 union smb_chkpath parm
[NSERVERS
];
1235 NTSTATUS status
[NSERVERS
];
1237 parm
[0].chkpath
.in
.path
= gen_fname_open(instance
);
1240 GEN_CALL(smb_raw_chkpath(tree
, &parm
[i
]));
1246 generate mkdir operations
1248 static BOOL
handler_mkdir(int instance
)
1250 union smb_mkdir parm
[NSERVERS
];
1251 NTSTATUS status
[NSERVERS
];
1253 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1254 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1257 GEN_CALL(smb_raw_mkdir(tree
, &parm
[i
]));
1263 generate rmdir operations
1265 static BOOL
handler_rmdir(int instance
)
1267 struct smb_rmdir parm
[NSERVERS
];
1268 NTSTATUS status
[NSERVERS
];
1270 parm
[0].in
.path
= gen_fname_open(instance
);
1273 GEN_CALL(smb_raw_rmdir(tree
, &parm
[i
]));
1279 generate rename operations
1281 static BOOL
handler_rename(int instance
)
1283 union smb_rename parm
[NSERVERS
];
1284 NTSTATUS status
[NSERVERS
];
1286 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1287 parm
[0].rename
.in
.pattern1
= gen_pattern();
1288 parm
[0].rename
.in
.pattern2
= gen_pattern();
1289 parm
[0].rename
.in
.attrib
= gen_attrib();
1292 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1298 generate ntrename operations
1300 static BOOL
handler_ntrename(int instance
)
1302 union smb_rename parm
[NSERVERS
];
1303 NTSTATUS status
[NSERVERS
];
1305 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1306 parm
[0].ntrename
.in
.old_name
= gen_fname();
1307 parm
[0].ntrename
.in
.new_name
= gen_fname();
1308 parm
[0].ntrename
.in
.attrib
= gen_attrib();
1309 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
1310 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
1313 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1320 generate seek operations
1322 static BOOL
handler_seek(int instance
)
1324 union smb_seek parm
[NSERVERS
];
1325 NTSTATUS status
[NSERVERS
];
1327 parm
[0].lseek
.in
.file
.fnum
= gen_fnum(instance
);
1328 parm
[0].lseek
.in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
1329 parm
[0].lseek
.in
.offset
= gen_offset();
1332 GEN_SET_FNUM(lseek
.in
.file
.fnum
);
1333 GEN_CALL(smb_raw_seek(tree
, &parm
[i
]));
1335 CHECK_EQUAL(lseek
.out
.offset
);
1342 generate readx operations
1344 static BOOL
handler_readx(int instance
)
1346 union smb_read parm
[NSERVERS
];
1347 NTSTATUS status
[NSERVERS
];
1349 parm
[0].readx
.level
= RAW_READ_READX
;
1350 parm
[0].readx
.in
.file
.fnum
= gen_fnum(instance
);
1351 parm
[0].readx
.in
.offset
= gen_offset();
1352 parm
[0].readx
.in
.mincnt
= gen_io_count();
1353 parm
[0].readx
.in
.maxcnt
= gen_io_count();
1354 parm
[0].readx
.in
.remaining
= gen_io_count();
1355 parm
[0].readx
.in
.read_for_execute
= gen_bool();
1356 parm
[0].readx
.out
.data
= talloc_size(current_op
.mem_ctx
,
1357 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
1360 GEN_SET_FNUM(readx
.in
.file
.fnum
);
1361 GEN_CALL(smb_raw_read(tree
, &parm
[i
]));
1363 CHECK_EQUAL(readx
.out
.remaining
);
1364 CHECK_EQUAL(readx
.out
.compaction_mode
);
1365 CHECK_EQUAL(readx
.out
.nread
);
1371 generate writex operations
1373 static BOOL
handler_writex(int instance
)
1375 union smb_write parm
[NSERVERS
];
1376 NTSTATUS status
[NSERVERS
];
1378 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
1379 parm
[0].writex
.in
.file
.fnum
= gen_fnum(instance
);
1380 parm
[0].writex
.in
.offset
= gen_offset();
1381 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
1382 parm
[0].writex
.in
.remaining
= gen_io_count();
1383 parm
[0].writex
.in
.count
= gen_io_count();
1384 parm
[0].writex
.in
.data
= talloc_zero_size(current_op
.mem_ctx
, parm
[0].writex
.in
.count
);
1387 GEN_SET_FNUM(writex
.in
.file
.fnum
);
1388 GEN_CALL(smb_raw_write(tree
, &parm
[i
]));
1390 CHECK_EQUAL(writex
.out
.nwritten
);
1391 CHECK_EQUAL(writex
.out
.remaining
);
1397 generate lockingx operations
1399 static BOOL
handler_lockingx(int instance
)
1401 union smb_lock parm
[NSERVERS
];
1402 NTSTATUS status
[NSERVERS
];
1405 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
1406 parm
[0].lockx
.in
.file
.fnum
= gen_fnum(instance
);
1407 parm
[0].lockx
.in
.mode
= gen_lock_mode();
1408 parm
[0].lockx
.in
.timeout
= gen_timeout();
1410 /* make sure we don't accidentially generate an oplock
1411 break ack - otherwise the server can just block forever */
1412 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
1413 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
1414 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
1415 } while (nlocks
== 0);
1418 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
1419 struct smb_lock_entry
,
1421 for (n
=0;n
<nlocks
;n
++) {
1422 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
1423 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
1424 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
1429 GEN_SET_FNUM(lockx
.in
.file
.fnum
);
1430 GEN_CALL(smb_raw_lock(tree
, &parm
[i
]));
1436 generate a fileinfo query structure
1438 static void gen_fileinfo(int instance
, union smb_fileinfo
*info
)
1441 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1443 enum smb_fileinfo_level level
;
1446 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
1447 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
1448 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
1449 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
1450 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
1451 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
1452 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
1453 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
1454 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
1455 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
1458 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1459 } while (ignore_pattern(levels
[i
].name
));
1461 info
->generic
.level
= levels
[i
].level
;
1465 compare returned fileinfo structures
1467 static BOOL
cmp_fileinfo(int instance
,
1468 union smb_fileinfo parm
[NSERVERS
],
1469 NTSTATUS status
[NSERVERS
])
1473 switch (parm
[0].generic
.level
) {
1474 case RAW_FILEINFO_GENERIC
:
1477 case RAW_FILEINFO_GETATTR
:
1478 CHECK_EQUAL(getattr
.out
.attrib
);
1479 CHECK_EQUAL(getattr
.out
.size
);
1480 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1483 case RAW_FILEINFO_GETATTRE
:
1484 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1485 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1486 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1487 CHECK_EQUAL(getattre
.out
.size
);
1488 CHECK_EQUAL(getattre
.out
.alloc_size
);
1489 CHECK_EQUAL(getattre
.out
.attrib
);
1492 case RAW_FILEINFO_STANDARD
:
1493 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1494 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1495 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1496 CHECK_EQUAL(standard
.out
.size
);
1497 CHECK_EQUAL(standard
.out
.alloc_size
);
1498 CHECK_EQUAL(standard
.out
.attrib
);
1501 case RAW_FILEINFO_EA_SIZE
:
1502 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1503 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1504 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1505 CHECK_EQUAL(ea_size
.out
.size
);
1506 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1507 CHECK_EQUAL(ea_size
.out
.attrib
);
1508 CHECK_EQUAL(ea_size
.out
.ea_size
);
1511 case RAW_FILEINFO_ALL_EAS
:
1512 CHECK_EQUAL(all_eas
.out
.num_eas
);
1513 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1514 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1515 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1516 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1520 case RAW_FILEINFO_IS_NAME_VALID
:
1523 case RAW_FILEINFO_BASIC_INFO
:
1524 case RAW_FILEINFO_BASIC_INFORMATION
:
1525 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1526 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1527 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1528 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1529 CHECK_EQUAL(basic_info
.out
.attrib
);
1532 case RAW_FILEINFO_STANDARD_INFO
:
1533 case RAW_FILEINFO_STANDARD_INFORMATION
:
1534 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1535 CHECK_EQUAL(standard_info
.out
.size
);
1536 CHECK_EQUAL(standard_info
.out
.nlink
);
1537 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1538 CHECK_EQUAL(standard_info
.out
.directory
);
1541 case RAW_FILEINFO_EA_INFO
:
1542 case RAW_FILEINFO_EA_INFORMATION
:
1543 CHECK_EQUAL(ea_info
.out
.ea_size
);
1546 case RAW_FILEINFO_NAME_INFO
:
1547 case RAW_FILEINFO_NAME_INFORMATION
:
1548 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1551 case RAW_FILEINFO_ALL_INFO
:
1552 case RAW_FILEINFO_ALL_INFORMATION
:
1553 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1554 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1555 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1556 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1557 CHECK_EQUAL(all_info
.out
.attrib
);
1558 CHECK_EQUAL(all_info
.out
.alloc_size
);
1559 CHECK_EQUAL(all_info
.out
.size
);
1560 CHECK_EQUAL(all_info
.out
.nlink
);
1561 CHECK_EQUAL(all_info
.out
.delete_pending
);
1562 CHECK_EQUAL(all_info
.out
.directory
);
1563 CHECK_EQUAL(all_info
.out
.ea_size
);
1564 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1567 case RAW_FILEINFO_ALT_NAME_INFO
:
1568 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1569 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1572 case RAW_FILEINFO_STREAM_INFO
:
1573 case RAW_FILEINFO_STREAM_INFORMATION
:
1574 CHECK_EQUAL(stream_info
.out
.num_streams
);
1575 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1576 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1577 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1578 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1582 case RAW_FILEINFO_COMPRESSION_INFO
:
1583 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1584 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1585 CHECK_EQUAL(compression_info
.out
.format
);
1586 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1587 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1588 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1591 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1592 CHECK_EQUAL(internal_information
.out
.file_id
);
1595 case RAW_FILEINFO_ACCESS_INFORMATION
:
1596 CHECK_EQUAL(access_information
.out
.access_flags
);
1599 case RAW_FILEINFO_POSITION_INFORMATION
:
1600 CHECK_EQUAL(position_information
.out
.position
);
1603 case RAW_FILEINFO_MODE_INFORMATION
:
1604 CHECK_EQUAL(mode_information
.out
.mode
);
1607 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1608 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1611 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1612 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1613 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1614 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1615 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1616 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1617 CHECK_EQUAL(network_open_information
.out
.size
);
1618 CHECK_EQUAL(network_open_information
.out
.attrib
);
1621 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1622 CHECK_EQUAL(attribute_tag_information
.out
.attrib
);
1623 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1626 /* Unhandled levels */
1628 case RAW_FILEINFO_SEC_DESC
:
1629 case RAW_FILEINFO_EA_LIST
:
1630 case RAW_FILEINFO_UNIX_BASIC
:
1631 case RAW_FILEINFO_UNIX_LINK
:
1632 case RAW_FILEINFO_SMB2_ALL_EAS
:
1633 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
1641 generate qpathinfo operations
1643 static BOOL
handler_qpathinfo(int instance
)
1645 union smb_fileinfo parm
[NSERVERS
];
1646 NTSTATUS status
[NSERVERS
];
1648 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
1650 gen_fileinfo(instance
, &parm
[0]);
1653 GEN_CALL(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1655 return cmp_fileinfo(instance
, parm
, status
);
1659 generate qfileinfo operations
1661 static BOOL
handler_qfileinfo(int instance
)
1663 union smb_fileinfo parm
[NSERVERS
];
1664 NTSTATUS status
[NSERVERS
];
1666 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
1668 gen_fileinfo(instance
, &parm
[0]);
1671 GEN_SET_FNUM(generic
.in
.file
.fnum
);
1672 GEN_CALL(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1674 return cmp_fileinfo(instance
, parm
, status
);
1679 generate a fileinfo query structure
1681 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
1685 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1687 enum smb_setfileinfo_level level
;
1691 /* disabled until win2003 can handle them ... */
1692 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
1693 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
1695 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
1696 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
1697 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
1698 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
1699 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1702 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1703 } while (ignore_pattern(levels
[i
].name
));
1705 info
->generic
.level
= levels
[i
].level
;
1707 switch (info
->generic
.level
) {
1708 case RAW_SFILEINFO_SETATTR
:
1709 info
->setattr
.in
.attrib
= gen_attrib();
1710 info
->setattr
.in
.write_time
= gen_timet();
1712 case RAW_SFILEINFO_SETATTRE
:
1713 info
->setattre
.in
.create_time
= gen_timet();
1714 info
->setattre
.in
.access_time
= gen_timet();
1715 info
->setattre
.in
.write_time
= gen_timet();
1717 case RAW_SFILEINFO_STANDARD
:
1718 info
->standard
.in
.create_time
= gen_timet();
1719 info
->standard
.in
.access_time
= gen_timet();
1720 info
->standard
.in
.write_time
= gen_timet();
1722 case RAW_SFILEINFO_EA_SET
: {
1723 static struct ea_struct ea
;
1724 info
->ea_set
.in
.num_eas
= 1;
1725 info
->ea_set
.in
.eas
= &ea
;
1726 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
1729 case RAW_SFILEINFO_BASIC_INFO
:
1730 case RAW_SFILEINFO_BASIC_INFORMATION
:
1731 info
->basic_info
.in
.create_time
= gen_nttime();
1732 info
->basic_info
.in
.access_time
= gen_nttime();
1733 info
->basic_info
.in
.write_time
= gen_nttime();
1734 info
->basic_info
.in
.change_time
= gen_nttime();
1735 info
->basic_info
.in
.attrib
= gen_attrib();
1737 case RAW_SFILEINFO_DISPOSITION_INFO
:
1738 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
1739 info
->disposition_info
.in
.delete_on_close
= gen_bool();
1741 case RAW_SFILEINFO_ALLOCATION_INFO
:
1742 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
1743 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
1745 case RAW_SFILEINFO_END_OF_FILE_INFO
:
1746 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
1747 info
->end_of_file_info
.in
.size
= gen_offset();
1749 case RAW_SFILEINFO_RENAME_INFORMATION
:
1750 info
->rename_information
.in
.overwrite
= gen_bool();
1751 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
1752 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
1754 case RAW_SFILEINFO_POSITION_INFORMATION
:
1755 info
->position_information
.in
.position
= gen_offset();
1757 case RAW_SFILEINFO_MODE_INFORMATION
:
1758 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
1760 case RAW_SFILEINFO_GENERIC
:
1761 case RAW_SFILEINFO_SEC_DESC
:
1762 case RAW_SFILEINFO_UNIX_BASIC
:
1763 case RAW_SFILEINFO_UNIX_LINK
:
1764 case RAW_SFILEINFO_UNIX_HLINK
:
1765 case RAW_SFILEINFO_1023
:
1766 case RAW_SFILEINFO_1025
:
1767 case RAW_SFILEINFO_1029
:
1768 case RAW_SFILEINFO_1032
:
1769 case RAW_SFILEINFO_1039
:
1770 case RAW_SFILEINFO_1040
:
1777 generate setpathinfo operations
1779 static BOOL
handler_spathinfo(int instance
)
1781 union smb_setfileinfo parm
[NSERVERS
];
1782 NTSTATUS status
[NSERVERS
];
1784 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
1786 gen_setfileinfo(instance
, &parm
[0]);
1790 /* a special case for the fid in a RENAME */
1791 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
1792 parm
[0].rename_information
.in
.root_fid
!= 0) {
1793 GEN_SET_FNUM(rename_information
.in
.root_fid
);
1796 GEN_CALL(smb_raw_setpathinfo(tree
, &parm
[i
]));
1803 generate setfileinfo operations
1805 static BOOL
handler_sfileinfo(int instance
)
1807 union smb_setfileinfo parm
[NSERVERS
];
1808 NTSTATUS status
[NSERVERS
];
1810 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
1812 gen_setfileinfo(instance
, &parm
[0]);
1815 GEN_SET_FNUM(generic
.in
.file
.fnum
);
1816 GEN_CALL(smb_raw_setfileinfo(tree
, &parm
[i
]));
1823 generate change notify operations
1825 static BOOL
handler_notify(int instance
)
1827 union smb_notify parm
[NSERVERS
];
1830 ZERO_STRUCT(parm
[0]);
1831 parm
[0].nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1832 parm
[0].nttrans
.in
.buffer_size
= gen_io_count();
1833 parm
[0].nttrans
.in
.completion_filter
= gen_bits_mask(0xFF);
1834 parm
[0].nttrans
.in
.file
.fnum
= gen_fnum(instance
);
1835 parm
[0].nttrans
.in
.recursive
= gen_bool();
1838 GEN_SET_FNUM(nttrans
.in
.file
.fnum
);
1840 for (n
=0;n
<NSERVERS
;n
++) {
1841 struct smbcli_request
*req
;
1842 req
= smb_raw_changenotify_send(servers
[n
].cli
[instance
]->tree
, &parm
[n
]);
1843 req
->async
.fn
= async_notify
;
1850 wipe any relevant files
1852 static void wipe_files(void)
1855 for (i
=0;i
<NSERVERS
;i
++) {
1856 int n
= smbcli_deltree(servers
[i
].cli
[0]->tree
, "\\gentest");
1858 printf("Failed to wipe tree on server %d\n", i
);
1861 if (NT_STATUS_IS_ERR(smbcli_mkdir(servers
[i
].cli
[0]->tree
, "\\gentest"))) {
1862 printf("Failed to create \\gentest - %s\n",
1863 smbcli_errstr(servers
[i
].cli
[0]->tree
));
1867 printf("Deleted %d files on server %d\n", n
, i
);
1873 dump the current seeds - useful for continuing a backtrack
1875 static void dump_seeds(void)
1880 if (!options
.seeds_file
) {
1883 f
= fopen("seeds.tmp", "w");
1886 for (i
=0;i
<options
.numops
;i
++) {
1887 fprintf(f
, "%u\n", op_parms
[i
].seed
);
1890 rename("seeds.tmp", options
.seeds_file
);
1896 the list of top-level operations that we will generate
1900 BOOL (*handler
)(int instance
);
1901 int count
, success_count
;
1903 {"OPEN", handler_open
},
1904 {"OPENX", handler_openx
},
1905 {"NTCREATEX", handler_ntcreatex
},
1906 {"CLOSE", handler_close
},
1907 {"UNLINK", handler_unlink
},
1908 {"MKDIR", handler_mkdir
},
1909 {"RMDIR", handler_rmdir
},
1910 {"RENAME", handler_rename
},
1911 {"NTRENAME", handler_ntrename
},
1912 {"READX", handler_readx
},
1913 {"WRITEX", handler_writex
},
1914 {"CHKPATH", handler_chkpath
},
1915 {"LOCKINGX", handler_lockingx
},
1916 {"QPATHINFO", handler_qpathinfo
},
1917 {"QFILEINFO", handler_qfileinfo
},
1918 {"SPATHINFO", handler_spathinfo
},
1919 {"SFILEINFO", handler_sfileinfo
},
1920 {"NOTIFY", handler_notify
},
1921 {"SEEK", handler_seek
},
1926 run the test with the current set of op_parms parameters
1927 return the number of operations that completed successfully
1929 static int run_test(void)
1933 if (!connect_servers()) {
1934 printf("Failed to connect to servers\n");
1940 /* wipe any leftover files from old runs */
1943 /* reset the open handles array */
1944 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
1945 num_open_handles
= 0;
1947 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1948 gen_ops
[i
].count
= 0;
1949 gen_ops
[i
].success_count
= 0;
1952 for (op
=0; op
<options
.numops
; op
++) {
1953 int instance
, which_op
;
1956 if (op_parms
[op
].disabled
) continue;
1958 srandom(op_parms
[op
].seed
);
1960 instance
= gen_int_range(0, NINSTANCES
-1);
1962 /* generate a non-ignored operation */
1964 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
1965 } while (ignore_pattern(gen_ops
[which_op
].name
));
1967 DEBUG(3,("Generating op %s on instance %d\n",
1968 gen_ops
[which_op
].name
, instance
));
1970 current_op
.seed
= op_parms
[op
].seed
;
1971 current_op
.opnum
= op
;
1972 current_op
.name
= gen_ops
[which_op
].name
;
1973 current_op
.status
= NT_STATUS_OK
;
1974 current_op
.mem_ctx
= talloc_named(NULL
, 0, "%s", current_op
.name
);
1976 ret
= gen_ops
[which_op
].handler(instance
);
1978 talloc_free(current_op
.mem_ctx
);
1980 gen_ops
[which_op
].count
++;
1981 if (NT_STATUS_IS_OK(current_op
.status
)) {
1982 gen_ops
[which_op
].success_count
++;
1986 printf("Failed at operation %d - %s\n",
1987 op
, gen_ops
[which_op
].name
);
1991 if (op
% 100 == 0) {
1996 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1997 printf("Op %-10s got %d/%d success\n",
1999 gen_ops
[i
].success_count
,
2007 perform a backtracking analysis of the minimal set of operations
2008 to generate an error
2010 static void backtrack_analyze(void)
2014 chunk
= options
.numops
/ 2;
2019 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
2022 chunk
= MIN(chunk
, options
.numops
/ 2);
2024 /* mark this range as disabled */
2025 max
= MIN(options
.numops
, base
+chunk
);
2026 for (i
=base
;i
<max
; i
++) {
2027 op_parms
[i
].disabled
= True
;
2029 printf("Testing %d ops with %d-%d disabled\n",
2030 options
.numops
, base
, max
-1);
2032 printf("Completed %d of %d ops\n", ret
, options
.numops
);
2033 for (i
=base
;i
<max
; i
++) {
2034 op_parms
[i
].disabled
= False
;
2036 if (ret
== options
.numops
) {
2037 /* this chunk is needed */
2039 } else if (ret
< base
) {
2040 printf("damn - inconsistent errors! found early error\n");
2041 options
.numops
= ret
+1;
2044 /* it failed - this chunk isn't needed for a failure */
2045 memmove(&op_parms
[base
], &op_parms
[max
],
2046 sizeof(op_parms
[0]) * (options
.numops
- max
));
2047 options
.numops
= (ret
+1) - (max
- base
);
2057 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
2060 } while (chunk
> 0);
2062 printf("Reduced to %d ops\n", options
.numops
);
2064 if (ret
!= options
.numops
- 1) {
2065 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
2070 start the main gentest process
2072 static BOOL
start_gentest(void)
2077 /* allocate the open_handles array */
2078 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
2080 srandom(options
.seed
);
2081 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
2083 /* generate the seeds - after this everything is deterministic */
2084 if (options
.use_preset_seeds
) {
2086 char **preset
= file_lines_load(options
.seeds_file
, &numops
, NULL
);
2088 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
2091 if (numops
< options
.numops
) {
2092 options
.numops
= numops
;
2094 for (op
=0;op
<options
.numops
;op
++) {
2096 printf("Not enough seeds in %s\n", options
.seeds_file
);
2099 op_parms
[op
].seed
= atoi(preset
[op
]);
2101 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
2103 for (op
=0; op
<options
.numops
; op
++) {
2104 op_parms
[op
].seed
= random();
2110 if (ret
!= options
.numops
&& options
.analyze
) {
2111 options
.numops
= ret
+1;
2112 backtrack_analyze();
2113 } else if (options
.analyze_always
) {
2114 backtrack_analyze();
2115 } else if (options
.analyze_continuous
) {
2116 while (run_test() == options
.numops
) ;
2119 return ret
== options
.numops
;
2123 static void usage(void)
2127 gentest2 //server1/share1 //server2/share2 [options..]\n\
2129 -U user%%pass (can be specified twice)\n\
2132 -a (show all ops)\n\
2133 -A backtrack to find minimal ops\n\
2134 -i FILE add a list of wildcard exclusions\n\
2135 -O enable oplocks\n\
2136 -S FILE set preset seeds file\n\
2137 -L use preset seeds\n\
2138 -F fast reconnect (just close files)\n\
2139 -C continuous analysis mode\n\
2140 -X analyse even when test OK\n\
2145 split a UNC name into server and share names
2147 static BOOL
split_unc_name(const char *unc
, char **server
, char **share
)
2149 char *p
= strdup(unc
);
2150 if (!p
) return False
;
2151 all_string_sub(p
, "\\", "/", 0);
2152 if (strncmp(p
, "//", 2) != 0) return False
;
2155 p
= strchr(*server
, '/');
2156 if (!p
) return False
;
2166 /****************************************************************************
2168 ****************************************************************************/
2169 int main(int argc
, char *argv
[])
2172 int i
, username_count
=0;
2177 setup_logging("gentest", DEBUG_STDOUT
);
2179 if (argc
< 3 || argv
[1][0] == '-') {
2184 setup_logging(argv
[0], DEBUG_STDOUT
);
2186 for (i
=0;i
<NSERVERS
;i
++) {
2187 const char *share
= argv
[1+i
];
2188 servers
[i
].credentials
= cli_credentials_init(NULL
);
2189 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
2190 printf("Invalid share name '%s'\n", share
);
2200 servers
[0].credentials
= cli_credentials_init(talloc_autofree_context());
2201 servers
[1].credentials
= cli_credentials_init(talloc_autofree_context());
2202 cli_credentials_guess(servers
[0].credentials
);
2203 cli_credentials_guess(servers
[1].credentials
);
2205 options
.seed
= time(NULL
);
2206 options
.numops
= 1000;
2207 options
.max_open_handles
= 20;
2208 options
.seeds_file
= "gentest_seeds.dat";
2210 while ((opt
= getopt(argc
, argv
, "U:s:o:ad:i:AOhS:LFXC")) != EOF
) {
2213 if (username_count
== 2) {
2217 cli_credentials_parse_string(servers
[username_count
].credentials
,
2218 optarg
, CRED_SPECIFIED
);
2222 DEBUGLEVEL
= atoi(optarg
);
2223 setup_logging(NULL
, DEBUG_STDOUT
);
2226 options
.seed
= atoi(optarg
);
2229 options
.seeds_file
= optarg
;
2232 options
.use_preset_seeds
= True
;
2235 options
.fast_reconnect
= True
;
2238 options
.numops
= atoi(optarg
);
2241 options
.use_oplocks
= True
;
2244 options
.showall
= True
;
2247 options
.analyze
= True
;
2250 options
.analyze_always
= True
;
2253 options
.analyze_continuous
= True
;
2256 options
.ignore_patterns
= file_lines_load(optarg
, NULL
, NULL
);
2262 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
2269 if (username_count
== 0) {
2273 if (username_count
== 1) {
2274 servers
[1].credentials
= servers
[0].credentials
;
2277 printf("seed=%u\n", options
.seed
);
2279 ret
= start_gentest();
2282 printf("gentest completed - no errors\n");
2284 printf("gentest failed\n");