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 "dynconfig.h"
23 #include "system/time.h"
24 #include "system/filesys.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "librpc/gen_ndr/ndr_security.h"
33 static struct gentest_options
{
37 BOOL analyze_continuous
;
38 uint_t max_open_handles
;
42 char **ignore_patterns
;
43 const char *seeds_file
;
44 BOOL use_preset_seeds
;
48 /* mapping between open handles on the server and local handles */
52 uint_t server_fnum
[NSERVERS
];
55 static uint_t num_open_handles
;
57 /* state information for the servers. We open NINSTANCES connections to
60 struct smbcli_state
*cli
[NINSTANCES
];
63 struct cli_credentials
*credentials
;
66 /* the seeds and flags for each operation */
73 /* oplock break info */
80 } oplocks
[NSERVERS
][NINSTANCES
];
82 /* change notify reply info */
86 struct smb_notify notify
;
87 } notifies
[NSERVERS
][NINSTANCES
];
89 /* info relevant to the current operation */
100 #define BAD_HANDLE 0xFFFE
102 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private);
103 static void idle_func(struct smbcli_transport
*transport
, void *private);
106 check if a string should be ignored. This is used as the basis
107 for all error ignore settings
109 static BOOL
ignore_pattern(const char *str
)
112 if (!options
.ignore_patterns
) return False
;
114 for (i
=0;options
.ignore_patterns
[i
];i
++) {
115 if (strcmp(options
.ignore_patterns
[i
], str
) == 0 ||
116 gen_fnmatch(options
.ignore_patterns
[i
], str
) == 0) {
117 DEBUG(2,("Ignoring '%s'\n", str
));
124 /*****************************************************
125 connect to the servers
126 *******************************************************/
127 static BOOL
connect_servers_fast(void)
131 /* close all open files */
132 for (h
=0;h
<options
.max_open_handles
;h
++) {
133 if (!open_handles
[h
].active
) continue;
134 for (i
=0;i
<NSERVERS
;i
++) {
135 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
136 open_handles
[h
].server_fnum
[i
])))) {
139 open_handles
[h
].active
= False
;
149 /*****************************************************
150 connect to the servers
151 *******************************************************/
152 static BOOL
connect_servers(void)
156 if (options
.fast_reconnect
&& servers
[0].cli
[0]) {
157 if (connect_servers_fast()) {
162 /* close any existing connections */
163 for (i
=0;i
<NSERVERS
;i
++) {
164 for (j
=0;j
<NINSTANCES
;j
++) {
165 if (servers
[i
].cli
[j
]) {
166 smbcli_tdis(servers
[i
].cli
[j
]);
167 smbcli_shutdown(servers
[i
].cli
[j
]);
168 servers
[i
].cli
[j
] = NULL
;
173 for (i
=0;i
<NSERVERS
;i
++) {
174 for (j
=0;j
<NINSTANCES
;j
++) {
176 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
177 servers
[i
].server_name
, servers
[i
].share_name
,
178 servers
[i
].credentials
->username
, j
);
180 status
= smbcli_full_connection(NULL
, &servers
[i
].cli
[j
],
182 servers
[i
].server_name
,
183 servers
[i
].share_name
, NULL
,
184 servers
[i
].credentials
);
185 if (!NT_STATUS_IS_OK(status
)) {
186 printf("Failed to connect to \\\\%s\\%s - %s\n",
187 servers
[i
].server_name
, servers
[i
].share_name
,
192 smbcli_oplock_handler(servers
[i
].cli
[j
]->transport
, oplock_handler
, NULL
);
193 smbcli_transport_idle_handler(servers
[i
].cli
[j
]->transport
, idle_func
, 50000, NULL
);
201 work out the time skew between the servers - be conservative
203 static uint_t
time_skew(void)
206 ret
= ABS(servers
[0].cli
[0]->transport
->negotiate
.server_time
-
207 servers
[1].cli
[0]->transport
->negotiate
.server_time
);
212 turn an fnum for an instance into a handle
214 static uint_t
fnum_to_handle(int server
, int instance
, uint16_t fnum
)
217 for (i
=0;i
<options
.max_open_handles
;i
++) {
218 if (!open_handles
[i
].active
||
219 instance
!= open_handles
[i
].instance
) continue;
220 if (open_handles
[i
].server_fnum
[server
] == fnum
) {
224 printf("Invalid fnum %d in fnum_to_handle on server %d instance %d\n",
225 fnum
, server
, instance
);
230 add some newly opened handles
232 static void gen_add_handle(int instance
, const char *name
, uint16_t fnums
[NSERVERS
])
235 for (h
=0;h
<options
.max_open_handles
;h
++) {
236 if (!open_handles
[h
].active
) break;
238 if (h
== options
.max_open_handles
) {
239 /* we have to force close a random handle */
240 h
= random() % options
.max_open_handles
;
241 for (i
=0;i
<NSERVERS
;i
++) {
242 if (NT_STATUS_IS_ERR((smbcli_close(servers
[i
].cli
[open_handles
[h
].instance
]->tree
,
243 open_handles
[h
].server_fnum
[i
])))) {
244 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
245 smbcli_errstr(servers
[i
].cli
[open_handles
[h
].instance
]->tree
));
248 printf("Recovered handle %d\n", h
);
251 for (i
=0;i
<NSERVERS
;i
++) {
252 open_handles
[h
].server_fnum
[i
] = fnums
[i
];
253 open_handles
[h
].instance
= instance
;
254 open_handles
[h
].active
= True
;
255 open_handles
[h
].name
= name
;
259 printf("OPEN num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
261 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
266 remove a closed handle
268 static void gen_remove_handle(int instance
, uint16_t fnums
[NSERVERS
])
271 for (h
=0;h
<options
.max_open_handles
;h
++) {
272 if (instance
== open_handles
[h
].instance
&&
273 open_handles
[h
].server_fnum
[0] == fnums
[0]) {
274 open_handles
[h
].active
= False
;
276 printf("CLOSE num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n",
278 open_handles
[h
].server_fnum
[0], open_handles
[h
].server_fnum
[1],
279 open_handles
[h
].name
);
283 printf("Removing invalid handle!?\n");
288 return True with 'chance' probability as a percentage
290 static BOOL
gen_chance(uint_t chance
)
292 return ((random() % 100) <= chance
);
296 map an internal handle number to a server fnum
298 static uint16_t gen_lookup_fnum(int server
, uint16_t handle
)
300 if (handle
== BAD_HANDLE
) return handle
;
301 return open_handles
[handle
].server_fnum
[server
];
307 static uint16_t gen_fnum(int instance
)
312 if (gen_chance(20)) return BAD_HANDLE
;
314 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
315 h
= random() % options
.max_open_handles
;
316 if (open_handles
[h
].active
&&
317 open_handles
[h
].instance
== instance
) {
325 return a file handle, but skewed so we don't close the last
326 couple of handles too readily
328 static uint16_t gen_fnum_close(int instance
)
330 if (num_open_handles
< 3) {
331 if (gen_chance(80)) return BAD_HANDLE
;
334 return gen_fnum(instance
);
338 generate an integer in a specified range
340 static int gen_int_range(uint_t min
, uint_t max
)
343 return min
+ (r
% (1+max
-min
));
347 return a fnum for use as a root fid
348 be careful to call GEN_SET_FNUM() when you use this!
350 static uint16_t gen_root_fid(int instance
)
352 if (gen_chance(5)) return gen_fnum(instance
);
357 generate a file offset
359 static int gen_offset(void)
361 if (gen_chance(20)) return 0;
362 return gen_int_range(0, 1024*1024);
368 static int gen_io_count(void)
370 if (gen_chance(20)) return 0;
371 return gen_int_range(0, 4096);
377 static const char *gen_fname(void)
379 const char *names
[] = {"\\gentest\\gentest.dat",
381 "\\gentest\\foo2.sym",
382 "\\gentest\\foo3.dll",
384 "\\gentest\\foo4:teststream1",
385 "\\gentest\\foo4:teststream2",
386 "\\gentest\\foo5.exe",
387 "\\gentest\\foo5.exe:teststream3",
388 "\\gentest\\foo5.exe:teststream4",
389 "\\gentest\\foo6.com",
391 "\\gentest\\blah\\blergh.txt",
392 "\\gentest\\blah\\blergh2",
393 "\\gentest\\blah\\blergh3.txt",
394 "\\gentest\\blah\\blergh4",
395 "\\gentest\\blah\\blergh5.txt",
396 "\\gentest\\blah\\blergh5",
397 "\\gentest\\blah\\.",
399 /* this causes problem with w2k3 */
400 "\\gentest\\blah\\..",
402 "\\gentest\\a_very_long_name.bin",
408 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
409 } while (ignore_pattern(names
[i
]));
415 generate a filename with a higher chance of choosing an already
418 static const char *gen_fname_open(int instance
)
421 h
= gen_fnum(instance
);
422 if (h
== BAD_HANDLE
) {
425 return open_handles
[h
].name
;
429 generate a wildcard pattern
431 static const char *gen_pattern(void)
434 const char *names
[] = {"\\gentest\\*.dat",
437 "\\gentest\\blah\\*.*",
438 "\\gentest\\blah\\*",
441 if (gen_chance(50)) return gen_fname();
444 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
445 } while (ignore_pattern(names
[i
]));
453 static uint32_t gen_bits_mask(uint_t mask
)
455 uint_t ret
= random();
460 generate a bitmask with high probability of the first mask
461 and low of the second
463 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
465 if (gen_chance(10)) return gen_bits_mask(mask2
);
466 return gen_bits_mask(mask1
);
472 static BOOL
gen_bool(void)
474 return gen_bits_mask2(0x1, 0xFF);
478 generate ntrename flags
480 static uint16_t gen_rename_flags(void)
482 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
483 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
484 if (gen_chance(30)) return RENAME_FLAG_COPY
;
485 return gen_bits_mask(0xFFFF);
490 return a lockingx lock mode
492 static uint16_t gen_lock_mode(void)
494 if (gen_chance(5)) return gen_bits_mask(0xFFFF);
495 if (gen_chance(20)) return gen_bits_mask(0x1F);
496 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
502 static uint16_t gen_pid(void)
504 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
509 generate a lock count
511 static off_t
gen_lock_count(void)
513 return gen_int_range(0, 3);
517 generate a ntcreatex flags field
519 static uint32_t gen_ntcreatex_flags(void)
521 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
522 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
526 generate a NT access mask
528 static uint32_t gen_access_mask(void)
530 if (gen_chance(50)) return SEC_FLAG_MAXIMUM_ALLOWED
;
531 if (gen_chance(20)) return SEC_FILE_ALL
;
532 return gen_bits_mask(0xFFFFFFFF);
536 generate a ntcreatex create options bitfield
538 static uint32_t gen_create_options(void)
540 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
541 if (gen_chance(50)) return 0;
542 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
546 generate a ntcreatex open disposition
548 static uint32_t gen_open_disp(void)
550 if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
551 return gen_int_range(0, 5);
555 generate an openx open mode
557 static uint16_t gen_openx_mode(void)
559 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
560 if (gen_chance(20)) return gen_bits_mask(0xFF);
561 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
565 generate an openx flags field
567 static uint16_t gen_openx_flags(void)
569 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
570 return gen_bits_mask(0x7);
574 generate an openx open function
576 static uint16_t gen_openx_func(void)
578 if (gen_chance(20)) return gen_bits_mask(0xFFFF);
579 return gen_bits_mask(0x13);
583 generate a file attrib combination
585 static uint32_t gen_attrib(void)
587 if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
588 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
592 generate a unix timestamp
594 static time_t gen_timet(void)
596 if (gen_chance(30)) return 0;
597 return (time_t)random();
601 generate a unix timestamp
603 static NTTIME
gen_nttime(void)
606 unix_to_nt_time(&ret
, gen_timet());
611 generate a milliseconds protocol timeout
613 static uint32_t gen_timeout(void)
615 if (gen_chance(98)) return 0;
616 return random() % 50;
620 generate a file allocation size
622 static uint_t
gen_alloc_size(void)
626 if (gen_chance(30)) return 0;
628 ret
= random() % 4*1024*1024;
629 /* give a high chance of a round number */
630 if (gen_chance(60)) {
631 ret
&= ~(1024*1024 - 1);
637 generate an ea_struct
639 static struct ea_struct
gen_ea_struct(void)
642 const char *names
[] = {"EAONE",
647 "AVERYLONGATTRIBUTENAME"};
648 const char *values
[] = {"VALUE1",
653 "ASOMEWHATLONGERATTRIBUTEVALUE"};
657 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
658 } while (ignore_pattern(names
[i
]));
660 ea
.name
.s
= names
[i
];
663 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
664 } while (ignore_pattern(values
[i
]));
666 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
668 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
676 this is called when a change notify reply comes in
678 static void async_notify(struct smbcli_request
*req
)
680 struct smb_notify notify
;
684 struct smbcli_transport
*transport
= req
->transport
;
686 tid
= SVAL(req
->in
.hdr
, HDR_TID
);
688 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
689 if (NT_STATUS_IS_OK(status
)) {
690 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
692 notify
.out
.num_changes
,
693 notify
.out
.changes
[0].action
,
694 notify
.out
.changes
[0].name
.s
);
697 for (i
=0;i
<NSERVERS
;i
++) {
698 for (j
=0;j
<NINSTANCES
;j
++) {
699 if (transport
== servers
[i
].cli
[j
]->transport
&&
700 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
701 notifies
[i
][j
].notify_count
++;
702 notifies
[i
][j
].status
= status
;
703 notifies
[i
][j
].notify
= notify
;
710 the oplock handler will either ack the break or close the file
712 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private)
718 struct smbcli_tree
*tree
= NULL
;
720 srandom(current_op
.seed
);
721 do_close
= gen_chance(50);
723 for (i
=0;i
<NSERVERS
;i
++) {
724 for (j
=0;j
<NINSTANCES
;j
++) {
725 if (transport
== servers
[i
].cli
[j
]->transport
&&
726 tid
== servers
[i
].cli
[j
]->tree
->tid
) {
727 oplocks
[i
][j
].got_break
= True
;
728 oplocks
[i
][j
].fnum
= fnum
;
729 oplocks
[i
][j
].handle
= fnum_to_handle(i
, j
, fnum
);
730 oplocks
[i
][j
].level
= level
;
731 oplocks
[i
][j
].do_close
= do_close
;
732 tree
= servers
[i
].cli
[j
]->tree
;
738 printf("Oplock break not for one of our trees!?\n");
743 printf("oplock ack fnum=%d\n", fnum
);
744 return smbcli_oplock_ack(tree
, fnum
, level
);
747 printf("oplock close fnum=%d\n", fnum
);
749 io
.close
.level
= RAW_CLOSE_CLOSE
;
750 io
.close
.in
.fnum
= fnum
;
751 io
.close
.in
.write_time
= 0;
752 status
= smb_raw_close(tree
, &io
);
754 if (!NT_STATUS_IS_OK(status
)) {
755 printf("WARNING: close failed in oplock_handler_close - %s\n", nt_errstr(status
));
762 the idle function tries to cope with getting an oplock break on a connection, and
763 an operation on another connection blocking until that break is acked
764 we check for operations on all transports in the idle function
766 static void idle_func(struct smbcli_transport
*transport
, void *private)
769 for (i
=0;i
<NSERVERS
;i
++) {
770 for (j
=0;j
<NINSTANCES
;j
++) {
771 if (servers
[i
].cli
[j
] &&
772 transport
!= servers
[i
].cli
[j
]->transport
) {
773 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
782 compare NTSTATUS, using checking ignored patterns
784 static BOOL
compare_status(NTSTATUS status1
, NTSTATUS status2
)
786 if (NT_STATUS_EQUAL(status1
, status2
)) return True
;
788 /* one code being an error and the other OK is always an error */
789 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) return False
;
791 /* if we are ignoring one of the status codes then consider this a match */
792 if (ignore_pattern(nt_errstr(status1
)) ||
793 ignore_pattern(nt_errstr(status2
))) {
801 check for pending packets on all connections
803 static void check_pending(void)
809 for (j
=0;j
<NINSTANCES
;j
++) {
810 for (i
=0;i
<NSERVERS
;i
++) {
811 smbcli_transport_process(servers
[i
].cli
[j
]->transport
);
817 check that the same oplock breaks have been received by all instances
819 static BOOL
check_oplocks(const char *call
)
827 for (j
=0;j
<NINSTANCES
;j
++) {
828 for (i
=1;i
<NSERVERS
;i
++) {
829 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
830 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
831 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
832 if (tries
++ < 10) goto again
;
833 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
834 oplocks
[0][j
].got_break
,
835 oplocks
[0][j
].handle
,
837 oplocks
[i
][j
].got_break
,
838 oplocks
[i
][j
].handle
,
839 oplocks
[i
][j
].level
);
845 /* if we got a break and closed then remove the handle */
846 for (j
=0;j
<NINSTANCES
;j
++) {
847 if (oplocks
[0][j
].got_break
&&
848 oplocks
[0][j
].do_close
) {
849 uint16_t fnums
[NSERVERS
];
850 for (i
=0;i
<NSERVERS
;i
++) {
851 fnums
[i
] = oplocks
[i
][j
].fnum
;
853 gen_remove_handle(j
, fnums
);
862 check that the same change notify info has been received by all instances
864 static BOOL
check_notifies(const char *call
)
872 for (j
=0;j
<NINSTANCES
;j
++) {
873 for (i
=1;i
<NSERVERS
;i
++) {
875 struct smb_notify not1
, not2
;
877 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
878 if (tries
++ < 10) goto again
;
879 printf("Notify count inconsistent %d %d\n",
880 notifies
[0][j
].notify_count
,
881 notifies
[i
][j
].notify_count
);
885 if (notifies
[0][j
].notify_count
== 0) continue;
887 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
888 notifies
[i
][j
].status
)) {
889 printf("Notify status mismatch - %s - %s\n",
890 nt_errstr(notifies
[0][j
].status
),
891 nt_errstr(notifies
[i
][j
].status
));
895 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
899 not1
= notifies
[0][j
].notify
;
900 not2
= notifies
[i
][j
].notify
;
902 for (n
=0;n
<not1
.out
.num_changes
;n
++) {
903 if (not1
.out
.changes
[n
].action
!=
904 not2
.out
.changes
[n
].action
) {
905 printf("Notify action %d inconsistent %d %d\n", n
,
906 not1
.out
.changes
[n
].action
,
907 not2
.out
.changes
[n
].action
);
910 if (strcmp(not1
.out
.changes
[n
].name
.s
,
911 not2
.out
.changes
[n
].name
.s
)) {
912 printf("Notify name %d inconsistent %s %s\n", n
,
913 not1
.out
.changes
[n
].name
.s
,
914 not2
.out
.changes
[n
].name
.s
);
917 if (not1
.out
.changes
[n
].name
.private_length
!=
918 not2
.out
.changes
[n
].name
.private_length
) {
919 printf("Notify name length %d inconsistent %d %d\n", n
,
920 not1
.out
.changes
[n
].name
.private_length
,
921 not2
.out
.changes
[n
].name
.private_length
);
928 ZERO_STRUCT(notifies
);
934 #define GEN_COPY_PARM do { \
936 for (i=1;i<NSERVERS;i++) { \
941 #define GEN_CALL(call) do { \
943 ZERO_STRUCT(oplocks); \
944 ZERO_STRUCT(notifies); \
945 for (i=0;i<NSERVERS;i++) { \
946 struct smbcli_tree *tree = servers[i].cli[instance]->tree; \
949 current_op.status = status[0]; \
950 for (i=1;i<NSERVERS;i++) { \
951 if (!compare_status(status[i], status[0])) { \
952 printf("status different in %s - %s %s\n", #call, \
953 nt_errstr(status[0]), nt_errstr(status[i])); \
957 if (!check_oplocks(#call)) return False; \
958 if (!check_notifies(#call)) return False; \
959 if (!NT_STATUS_IS_OK(status[0])) { \
964 #define ADD_HANDLE(name, field) do { \
965 uint16_t fnums[NSERVERS]; \
967 for (i=0;i<NSERVERS;i++) { \
968 fnums[i] = parm[i].field; \
970 gen_add_handle(instance, name, fnums); \
973 #define REMOVE_HANDLE(field) do { \
974 uint16_t fnums[NSERVERS]; \
976 for (i=0;i<NSERVERS;i++) { \
977 fnums[i] = parm[i].field; \
979 gen_remove_handle(instance, fnums); \
982 #define GEN_SET_FNUM(field) do { \
984 for (i=0;i<NSERVERS;i++) { \
985 parm[i].field = gen_lookup_fnum(i, parm[i].field); \
989 #define CHECK_EQUAL(field) do { \
990 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
991 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
992 (int)parm[0].field, (int)parm[1].field); \
997 #define CHECK_WSTR_EQUAL(field) do { \
998 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
999 printf("%s is NULL!\n", #field); \
1002 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1003 printf("Mismatch in %s - %s %s\n", #field, \
1004 parm[0].field.s, parm[1].field.s); \
1007 CHECK_EQUAL(field.private_length); \
1010 #define CHECK_BLOB_EQUAL(field) do { \
1011 if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1012 printf("Mismatch in %s\n", #field); \
1015 CHECK_EQUAL(field.length); \
1018 #define CHECK_TIMES_EQUAL(field) do { \
1019 if (ABS(parm[0].field - parm[1].field) > time_skew() && \
1020 !ignore_pattern(#field)) { \
1021 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1022 (int)parm[0].field, (int)parm[1].field); \
1027 #define CHECK_NTTIMES_EQUAL(field) do { \
1028 if (ABS(nt_time_to_unix(parm[0].field) - \
1029 nt_time_to_unix(parm[1].field)) > time_skew() && \
1030 !ignore_pattern(#field)) { \
1031 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1032 (int)nt_time_to_unix(parm[0].field), \
1033 (int)nt_time_to_unix(parm[1].field)); \
1039 generate openx operations
1041 static BOOL
handler_openx(int instance
)
1043 union smb_open parm
[NSERVERS
];
1044 NTSTATUS status
[NSERVERS
];
1046 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1047 parm
[0].openx
.in
.flags
= gen_openx_flags();
1048 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1049 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1050 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1051 parm
[0].openx
.in
.write_time
= gen_timet();
1052 parm
[0].openx
.in
.open_func
= gen_openx_func();
1053 parm
[0].openx
.in
.size
= gen_io_count();
1054 parm
[0].openx
.in
.timeout
= gen_timeout();
1055 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1057 if (!options
.use_oplocks
) {
1058 /* mask out oplocks */
1059 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1060 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1064 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1066 CHECK_EQUAL(openx
.out
.attrib
);
1067 CHECK_EQUAL(openx
.out
.size
);
1068 CHECK_EQUAL(openx
.out
.access
);
1069 CHECK_EQUAL(openx
.out
.ftype
);
1070 CHECK_EQUAL(openx
.out
.devstate
);
1071 CHECK_EQUAL(openx
.out
.action
);
1072 CHECK_EQUAL(openx
.out
.access_mask
);
1073 CHECK_EQUAL(openx
.out
.unknown
);
1074 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1076 /* open creates a new file handle */
1077 ADD_HANDLE(parm
[0].openx
.in
.fname
, openx
.out
.fnum
);
1084 generate open operations
1086 static BOOL
handler_open(int instance
)
1088 union smb_open parm
[NSERVERS
];
1089 NTSTATUS status
[NSERVERS
];
1091 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1092 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1093 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1094 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1096 if (!options
.use_oplocks
) {
1097 /* mask out oplocks */
1098 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1099 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1103 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1105 CHECK_EQUAL(openold
.out
.attrib
);
1106 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1107 CHECK_EQUAL(openold
.out
.size
);
1108 CHECK_EQUAL(openold
.out
.rmode
);
1110 /* open creates a new file handle */
1111 ADD_HANDLE(parm
[0].openold
.in
.fname
, openold
.out
.fnum
);
1118 generate ntcreatex operations
1120 static BOOL
handler_ntcreatex(int instance
)
1122 union smb_open parm
[NSERVERS
];
1123 NTSTATUS status
[NSERVERS
];
1125 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1126 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1127 parm
[0].ntcreatex
.in
.root_fid
= gen_root_fid(instance
);
1128 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1129 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1130 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1131 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1132 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1133 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1134 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1135 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1136 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1138 if (!options
.use_oplocks
) {
1139 /* mask out oplocks */
1140 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1141 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1145 if (parm
[0].ntcreatex
.in
.root_fid
!= 0) {
1146 GEN_SET_FNUM(ntcreatex
.in
.root_fid
);
1148 GEN_CALL(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1150 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1151 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1152 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1153 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1154 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1155 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1156 CHECK_EQUAL(ntcreatex
.out
.attrib
);
1157 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1158 CHECK_EQUAL(ntcreatex
.out
.size
);
1159 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1160 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1161 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1163 /* ntcreatex creates a new file handle */
1164 ADD_HANDLE(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.fnum
);
1170 generate close operations
1172 static BOOL
handler_close(int instance
)
1174 union smb_close parm
[NSERVERS
];
1175 NTSTATUS status
[NSERVERS
];
1177 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1178 parm
[0].close
.in
.fnum
= gen_fnum_close(instance
);
1179 parm
[0].close
.in
.write_time
= gen_timet();
1182 GEN_SET_FNUM(close
.in
.fnum
);
1183 GEN_CALL(smb_raw_close(tree
, &parm
[i
]));
1185 REMOVE_HANDLE(close
.in
.fnum
);
1191 generate unlink operations
1193 static BOOL
handler_unlink(int instance
)
1195 struct smb_unlink parm
[NSERVERS
];
1196 NTSTATUS status
[NSERVERS
];
1198 parm
[0].in
.pattern
= gen_pattern();
1199 parm
[0].in
.attrib
= gen_attrib();
1202 GEN_CALL(smb_raw_unlink(tree
, &parm
[i
]));
1208 generate chkpath operations
1210 static BOOL
handler_chkpath(int instance
)
1212 struct smb_chkpath parm
[NSERVERS
];
1213 NTSTATUS status
[NSERVERS
];
1215 parm
[0].in
.path
= gen_fname_open(instance
);
1218 GEN_CALL(smb_raw_chkpath(tree
, &parm
[i
]));
1224 generate mkdir operations
1226 static BOOL
handler_mkdir(int instance
)
1228 union smb_mkdir parm
[NSERVERS
];
1229 NTSTATUS status
[NSERVERS
];
1231 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1232 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1235 GEN_CALL(smb_raw_mkdir(tree
, &parm
[i
]));
1241 generate rmdir operations
1243 static BOOL
handler_rmdir(int instance
)
1245 struct smb_rmdir parm
[NSERVERS
];
1246 NTSTATUS status
[NSERVERS
];
1248 parm
[0].in
.path
= gen_fname_open(instance
);
1251 GEN_CALL(smb_raw_rmdir(tree
, &parm
[i
]));
1257 generate rename operations
1259 static BOOL
handler_rename(int instance
)
1261 union smb_rename parm
[NSERVERS
];
1262 NTSTATUS status
[NSERVERS
];
1264 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1265 parm
[0].rename
.in
.pattern1
= gen_pattern();
1266 parm
[0].rename
.in
.pattern2
= gen_pattern();
1267 parm
[0].rename
.in
.attrib
= gen_attrib();
1270 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1276 generate ntrename operations
1278 static BOOL
handler_ntrename(int instance
)
1280 union smb_rename parm
[NSERVERS
];
1281 NTSTATUS status
[NSERVERS
];
1283 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1284 parm
[0].ntrename
.in
.old_name
= gen_fname();
1285 parm
[0].ntrename
.in
.new_name
= gen_fname();
1286 parm
[0].ntrename
.in
.attrib
= gen_attrib();
1287 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
1288 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
1291 GEN_CALL(smb_raw_rename(tree
, &parm
[i
]));
1298 generate seek operations
1300 static BOOL
handler_seek(int instance
)
1302 struct smb_seek parm
[NSERVERS
];
1303 NTSTATUS status
[NSERVERS
];
1305 parm
[0].in
.fnum
= gen_fnum(instance
);
1306 parm
[0].in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
1307 parm
[0].in
.offset
= gen_offset();
1310 GEN_SET_FNUM(in
.fnum
);
1311 GEN_CALL(smb_raw_seek(tree
, &parm
[i
]));
1313 CHECK_EQUAL(out
.offset
);
1320 generate readx operations
1322 static BOOL
handler_readx(int instance
)
1324 union smb_read parm
[NSERVERS
];
1325 NTSTATUS status
[NSERVERS
];
1327 parm
[0].readx
.level
= RAW_READ_READX
;
1328 parm
[0].readx
.in
.fnum
= gen_fnum(instance
);
1329 parm
[0].readx
.in
.offset
= gen_offset();
1330 parm
[0].readx
.in
.mincnt
= gen_io_count();
1331 parm
[0].readx
.in
.maxcnt
= gen_io_count();
1332 parm
[0].readx
.in
.remaining
= gen_io_count();
1333 parm
[0].readx
.out
.data
= talloc_size(current_op
.mem_ctx
,
1334 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
1337 GEN_SET_FNUM(readx
.in
.fnum
);
1338 GEN_CALL(smb_raw_read(tree
, &parm
[i
]));
1340 CHECK_EQUAL(readx
.out
.remaining
);
1341 CHECK_EQUAL(readx
.out
.compaction_mode
);
1342 CHECK_EQUAL(readx
.out
.nread
);
1348 generate writex operations
1350 static BOOL
handler_writex(int instance
)
1352 union smb_write parm
[NSERVERS
];
1353 NTSTATUS status
[NSERVERS
];
1355 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
1356 parm
[0].writex
.in
.fnum
= gen_fnum(instance
);
1357 parm
[0].writex
.in
.offset
= gen_offset();
1358 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
1359 parm
[0].writex
.in
.remaining
= gen_io_count();
1360 parm
[0].writex
.in
.count
= gen_io_count();
1361 parm
[0].writex
.in
.data
= talloc_zero_size(current_op
.mem_ctx
, parm
[0].writex
.in
.count
);
1364 GEN_SET_FNUM(writex
.in
.fnum
);
1365 GEN_CALL(smb_raw_write(tree
, &parm
[i
]));
1367 CHECK_EQUAL(writex
.out
.nwritten
);
1368 CHECK_EQUAL(writex
.out
.remaining
);
1374 generate lockingx operations
1376 static BOOL
handler_lockingx(int instance
)
1378 union smb_lock parm
[NSERVERS
];
1379 NTSTATUS status
[NSERVERS
];
1382 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
1383 parm
[0].lockx
.in
.fnum
= gen_fnum(instance
);
1384 parm
[0].lockx
.in
.mode
= gen_lock_mode();
1385 parm
[0].lockx
.in
.timeout
= gen_timeout();
1387 /* make sure we don't accidentially generate an oplock
1388 break ack - otherwise the server can just block forever */
1389 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
1390 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
1391 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
1392 } while (nlocks
== 0);
1395 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
1396 struct smb_lock_entry
,
1398 for (n
=0;n
<nlocks
;n
++) {
1399 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
1400 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
1401 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
1406 GEN_SET_FNUM(lockx
.in
.fnum
);
1407 GEN_CALL(smb_raw_lock(tree
, &parm
[i
]));
1413 generate a fileinfo query structure
1415 static void gen_fileinfo(int instance
, union smb_fileinfo
*info
)
1418 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1420 enum smb_fileinfo_level level
;
1423 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
1424 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
1425 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
1426 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
1427 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
1428 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
1429 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
1430 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
1431 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
1432 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
1435 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1436 } while (ignore_pattern(levels
[i
].name
));
1438 info
->generic
.level
= levels
[i
].level
;
1442 compare returned fileinfo structures
1444 static BOOL
cmp_fileinfo(int instance
,
1445 union smb_fileinfo parm
[NSERVERS
],
1446 NTSTATUS status
[NSERVERS
])
1450 switch (parm
[0].generic
.level
) {
1451 case RAW_FILEINFO_GENERIC
:
1454 case RAW_FILEINFO_GETATTR
:
1455 CHECK_EQUAL(getattr
.out
.attrib
);
1456 CHECK_EQUAL(getattr
.out
.size
);
1457 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1460 case RAW_FILEINFO_GETATTRE
:
1461 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1462 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1463 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1464 CHECK_EQUAL(getattre
.out
.size
);
1465 CHECK_EQUAL(getattre
.out
.alloc_size
);
1466 CHECK_EQUAL(getattre
.out
.attrib
);
1469 case RAW_FILEINFO_STANDARD
:
1470 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1471 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1472 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1473 CHECK_EQUAL(standard
.out
.size
);
1474 CHECK_EQUAL(standard
.out
.alloc_size
);
1475 CHECK_EQUAL(standard
.out
.attrib
);
1478 case RAW_FILEINFO_EA_SIZE
:
1479 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1480 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1481 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1482 CHECK_EQUAL(ea_size
.out
.size
);
1483 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1484 CHECK_EQUAL(ea_size
.out
.attrib
);
1485 CHECK_EQUAL(ea_size
.out
.ea_size
);
1488 case RAW_FILEINFO_ALL_EAS
:
1489 CHECK_EQUAL(all_eas
.out
.num_eas
);
1490 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1491 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1492 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1493 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1497 case RAW_FILEINFO_IS_NAME_VALID
:
1500 case RAW_FILEINFO_BASIC_INFO
:
1501 case RAW_FILEINFO_BASIC_INFORMATION
:
1502 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1503 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1504 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1505 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1506 CHECK_EQUAL(basic_info
.out
.attrib
);
1509 case RAW_FILEINFO_STANDARD_INFO
:
1510 case RAW_FILEINFO_STANDARD_INFORMATION
:
1511 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1512 CHECK_EQUAL(standard_info
.out
.size
);
1513 CHECK_EQUAL(standard_info
.out
.nlink
);
1514 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1515 CHECK_EQUAL(standard_info
.out
.directory
);
1518 case RAW_FILEINFO_EA_INFO
:
1519 case RAW_FILEINFO_EA_INFORMATION
:
1520 CHECK_EQUAL(ea_info
.out
.ea_size
);
1523 case RAW_FILEINFO_NAME_INFO
:
1524 case RAW_FILEINFO_NAME_INFORMATION
:
1525 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1528 case RAW_FILEINFO_ALL_INFO
:
1529 case RAW_FILEINFO_ALL_INFORMATION
:
1530 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1531 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1532 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1533 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1534 CHECK_EQUAL(all_info
.out
.attrib
);
1535 CHECK_EQUAL(all_info
.out
.alloc_size
);
1536 CHECK_EQUAL(all_info
.out
.size
);
1537 CHECK_EQUAL(all_info
.out
.nlink
);
1538 CHECK_EQUAL(all_info
.out
.delete_pending
);
1539 CHECK_EQUAL(all_info
.out
.directory
);
1540 CHECK_EQUAL(all_info
.out
.ea_size
);
1541 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1544 case RAW_FILEINFO_ALT_NAME_INFO
:
1545 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1546 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1549 case RAW_FILEINFO_STREAM_INFO
:
1550 case RAW_FILEINFO_STREAM_INFORMATION
:
1551 CHECK_EQUAL(stream_info
.out
.num_streams
);
1552 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1553 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1554 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1555 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1559 case RAW_FILEINFO_COMPRESSION_INFO
:
1560 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1561 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1562 CHECK_EQUAL(compression_info
.out
.format
);
1563 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1564 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1565 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1568 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1569 CHECK_EQUAL(internal_information
.out
.file_id
);
1572 case RAW_FILEINFO_ACCESS_INFORMATION
:
1573 CHECK_EQUAL(access_information
.out
.access_flags
);
1576 case RAW_FILEINFO_POSITION_INFORMATION
:
1577 CHECK_EQUAL(position_information
.out
.position
);
1580 case RAW_FILEINFO_MODE_INFORMATION
:
1581 CHECK_EQUAL(mode_information
.out
.mode
);
1584 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1585 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1588 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1589 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1590 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1591 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1592 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1593 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1594 CHECK_EQUAL(network_open_information
.out
.size
);
1595 CHECK_EQUAL(network_open_information
.out
.attrib
);
1598 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1599 CHECK_EQUAL(attribute_tag_information
.out
.attrib
);
1600 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1608 generate qpathinfo operations
1610 static BOOL
handler_qpathinfo(int instance
)
1612 union smb_fileinfo parm
[NSERVERS
];
1613 NTSTATUS status
[NSERVERS
];
1615 parm
[0].generic
.in
.fname
= gen_fname_open(instance
);
1617 gen_fileinfo(instance
, &parm
[0]);
1620 GEN_CALL(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1622 return cmp_fileinfo(instance
, parm
, status
);
1626 generate qfileinfo operations
1628 static BOOL
handler_qfileinfo(int instance
)
1630 union smb_fileinfo parm
[NSERVERS
];
1631 NTSTATUS status
[NSERVERS
];
1633 parm
[0].generic
.in
.fnum
= gen_fnum(instance
);
1635 gen_fileinfo(instance
, &parm
[0]);
1638 GEN_SET_FNUM(generic
.in
.fnum
);
1639 GEN_CALL(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
1641 return cmp_fileinfo(instance
, parm
, status
);
1646 generate a fileinfo query structure
1648 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
1652 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1654 enum smb_setfileinfo_level level
;
1658 /* disabled until win2003 can handle them ... */
1659 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
1660 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
1662 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
1663 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
1664 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
1665 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
1666 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1669 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
1670 } while (ignore_pattern(levels
[i
].name
));
1672 info
->generic
.level
= levels
[i
].level
;
1674 switch (info
->generic
.level
) {
1675 case RAW_SFILEINFO_SETATTR
:
1676 info
->setattr
.in
.attrib
= gen_attrib();
1677 info
->setattr
.in
.write_time
= gen_timet();
1679 case RAW_SFILEINFO_SETATTRE
:
1680 info
->setattre
.in
.create_time
= gen_timet();
1681 info
->setattre
.in
.access_time
= gen_timet();
1682 info
->setattre
.in
.write_time
= gen_timet();
1684 case RAW_SFILEINFO_STANDARD
:
1685 info
->standard
.in
.create_time
= gen_timet();
1686 info
->standard
.in
.access_time
= gen_timet();
1687 info
->standard
.in
.write_time
= gen_timet();
1689 case RAW_SFILEINFO_EA_SET
: {
1690 static struct ea_struct ea
;
1691 info
->ea_set
.in
.num_eas
= 1;
1692 info
->ea_set
.in
.eas
= &ea
;
1693 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
1696 case RAW_SFILEINFO_BASIC_INFO
:
1697 case RAW_SFILEINFO_BASIC_INFORMATION
:
1698 info
->basic_info
.in
.create_time
= gen_nttime();
1699 info
->basic_info
.in
.access_time
= gen_nttime();
1700 info
->basic_info
.in
.write_time
= gen_nttime();
1701 info
->basic_info
.in
.change_time
= gen_nttime();
1702 info
->basic_info
.in
.attrib
= gen_attrib();
1704 case RAW_SFILEINFO_DISPOSITION_INFO
:
1705 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
1706 info
->disposition_info
.in
.delete_on_close
= gen_bool();
1708 case RAW_SFILEINFO_ALLOCATION_INFO
:
1709 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
1710 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
1712 case RAW_SFILEINFO_END_OF_FILE_INFO
:
1713 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
1714 info
->end_of_file_info
.in
.size
= gen_offset();
1716 case RAW_SFILEINFO_RENAME_INFORMATION
:
1717 info
->rename_information
.in
.overwrite
= gen_bool();
1718 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
1719 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
1721 case RAW_SFILEINFO_POSITION_INFORMATION
:
1722 info
->position_information
.in
.position
= gen_offset();
1724 case RAW_SFILEINFO_MODE_INFORMATION
:
1725 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
1731 generate setpathinfo operations
1733 static BOOL
handler_spathinfo(int instance
)
1735 union smb_setfileinfo parm
[NSERVERS
];
1736 NTSTATUS status
[NSERVERS
];
1738 parm
[0].generic
.file
.fname
= gen_fname_open(instance
);
1740 gen_setfileinfo(instance
, &parm
[0]);
1744 /* a special case for the fid in a RENAME */
1745 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
1746 parm
[0].rename_information
.in
.root_fid
!= 0) {
1747 GEN_SET_FNUM(rename_information
.in
.root_fid
);
1750 GEN_CALL(smb_raw_setpathinfo(tree
, &parm
[i
]));
1757 generate setfileinfo operations
1759 static BOOL
handler_sfileinfo(int instance
)
1761 union smb_setfileinfo parm
[NSERVERS
];
1762 NTSTATUS status
[NSERVERS
];
1764 parm
[0].generic
.file
.fnum
= gen_fnum(instance
);
1766 gen_setfileinfo(instance
, &parm
[0]);
1769 GEN_SET_FNUM(generic
.file
.fnum
);
1770 GEN_CALL(smb_raw_setfileinfo(tree
, &parm
[i
]));
1777 generate change notify operations
1779 static BOOL
handler_notify(int instance
)
1781 struct smb_notify parm
[NSERVERS
];
1784 parm
[0].in
.buffer_size
= gen_io_count();
1785 parm
[0].in
.completion_filter
= gen_bits_mask(0xFF);
1786 parm
[0].in
.fnum
= gen_fnum(instance
);
1787 parm
[0].in
.recursive
= gen_bool();
1790 GEN_SET_FNUM(in
.fnum
);
1792 for (n
=0;n
<NSERVERS
;n
++) {
1793 struct smbcli_request
*req
;
1794 req
= smb_raw_changenotify_send(servers
[n
].cli
[instance
]->tree
, &parm
[n
]);
1795 req
->async
.fn
= async_notify
;
1802 wipe any relevant files
1804 static void wipe_files(void)
1807 for (i
=0;i
<NSERVERS
;i
++) {
1808 int n
= smbcli_deltree(servers
[i
].cli
[0]->tree
, "\\gentest");
1810 printf("Failed to wipe tree on server %d\n", i
);
1813 if (NT_STATUS_IS_ERR(smbcli_mkdir(servers
[i
].cli
[0]->tree
, "\\gentest"))) {
1814 printf("Failed to create \\gentest - %s\n",
1815 smbcli_errstr(servers
[i
].cli
[0]->tree
));
1819 printf("Deleted %d files on server %d\n", n
, i
);
1825 dump the current seeds - useful for continuing a backtrack
1827 static void dump_seeds(void)
1832 if (!options
.seeds_file
) {
1835 f
= fopen("seeds.tmp", "w");
1838 for (i
=0;i
<options
.numops
;i
++) {
1839 fprintf(f
, "%u\n", op_parms
[i
].seed
);
1842 rename("seeds.tmp", options
.seeds_file
);
1848 the list of top-level operations that we will generate
1852 BOOL (*handler
)(int instance
);
1853 int count
, success_count
;
1855 {"OPEN", handler_open
},
1856 {"OPENX", handler_openx
},
1857 {"NTCREATEX", handler_ntcreatex
},
1858 {"CLOSE", handler_close
},
1859 {"UNLINK", handler_unlink
},
1860 {"MKDIR", handler_mkdir
},
1861 {"RMDIR", handler_rmdir
},
1862 {"RENAME", handler_rename
},
1863 {"NTRENAME", handler_ntrename
},
1864 {"READX", handler_readx
},
1865 {"WRITEX", handler_writex
},
1866 {"CHKPATH", handler_chkpath
},
1867 {"LOCKINGX", handler_lockingx
},
1868 {"QPATHINFO", handler_qpathinfo
},
1869 {"QFILEINFO", handler_qfileinfo
},
1870 {"SPATHINFO", handler_spathinfo
},
1871 {"SFILEINFO", handler_sfileinfo
},
1872 {"NOTIFY", handler_notify
},
1873 {"SEEK", handler_seek
},
1878 run the test with the current set of op_parms parameters
1879 return the number of operations that completed successfully
1881 static int run_test(void)
1885 if (!connect_servers()) {
1886 printf("Failed to connect to servers\n");
1892 /* wipe any leftover files from old runs */
1895 /* reset the open handles array */
1896 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
1897 num_open_handles
= 0;
1899 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1900 gen_ops
[i
].count
= 0;
1901 gen_ops
[i
].success_count
= 0;
1904 for (op
=0; op
<options
.numops
; op
++) {
1905 int instance
, which_op
;
1908 if (op_parms
[op
].disabled
) continue;
1910 srandom(op_parms
[op
].seed
);
1912 instance
= gen_int_range(0, NINSTANCES
-1);
1914 /* generate a non-ignored operation */
1916 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
1917 } while (ignore_pattern(gen_ops
[which_op
].name
));
1919 DEBUG(3,("Generating op %s on instance %d\n",
1920 gen_ops
[which_op
].name
, instance
));
1922 current_op
.seed
= op_parms
[op
].seed
;
1923 current_op
.opnum
= op
;
1924 current_op
.name
= gen_ops
[which_op
].name
;
1925 current_op
.status
= NT_STATUS_OK
;
1926 current_op
.mem_ctx
= talloc_init("%s", current_op
.name
);
1928 ret
= gen_ops
[which_op
].handler(instance
);
1930 talloc_free(current_op
.mem_ctx
);
1932 gen_ops
[which_op
].count
++;
1933 if (NT_STATUS_IS_OK(current_op
.status
)) {
1934 gen_ops
[which_op
].success_count
++;
1938 printf("Failed at operation %d - %s\n",
1939 op
, gen_ops
[which_op
].name
);
1943 if (op
% 100 == 0) {
1948 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
1949 printf("Op %-10s got %d/%d success\n",
1951 gen_ops
[i
].success_count
,
1959 perform a backtracking analysis of the minimal set of operations
1960 to generate an error
1962 static void backtrack_analyze(void)
1966 chunk
= options
.numops
/ 2;
1971 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
1974 chunk
= MIN(chunk
, options
.numops
/ 2);
1976 /* mark this range as disabled */
1977 max
= MIN(options
.numops
, base
+chunk
);
1978 for (i
=base
;i
<max
; i
++) {
1979 op_parms
[i
].disabled
= True
;
1981 printf("Testing %d ops with %d-%d disabled\n",
1982 options
.numops
, base
, max
-1);
1984 printf("Completed %d of %d ops\n", ret
, options
.numops
);
1985 for (i
=base
;i
<max
; i
++) {
1986 op_parms
[i
].disabled
= False
;
1988 if (ret
== options
.numops
) {
1989 /* this chunk is needed */
1991 } else if (ret
< base
) {
1992 printf("damn - inconsistent errors! found early error\n");
1993 options
.numops
= ret
+1;
1996 /* it failed - this chunk isn't needed for a failure */
1997 memmove(&op_parms
[base
], &op_parms
[max
],
1998 sizeof(op_parms
[0]) * (options
.numops
- max
));
1999 options
.numops
= (ret
+1) - (max
- base
);
2009 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
2012 } while (chunk
> 0);
2014 printf("Reduced to %d ops\n", options
.numops
);
2016 if (ret
!= options
.numops
- 1) {
2017 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
2022 start the main gentest process
2024 static BOOL
start_gentest(void)
2029 /* allocate the open_handles array */
2030 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
2032 srandom(options
.seed
);
2033 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
2035 /* generate the seeds - after this everything is deterministic */
2036 if (options
.use_preset_seeds
) {
2038 char **preset
= file_lines_load(options
.seeds_file
, &numops
);
2040 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
2043 if (numops
< options
.numops
) {
2044 options
.numops
= numops
;
2046 for (op
=0;op
<options
.numops
;op
++) {
2048 printf("Not enough seeds in %s\n", options
.seeds_file
);
2051 op_parms
[op
].seed
= atoi(preset
[op
]);
2053 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
2055 for (op
=0; op
<options
.numops
; op
++) {
2056 op_parms
[op
].seed
= random();
2062 if (ret
!= options
.numops
&& options
.analyze
) {
2063 options
.numops
= ret
+1;
2064 backtrack_analyze();
2065 } else if (options
.analyze_always
) {
2066 backtrack_analyze();
2067 } else if (options
.analyze_continuous
) {
2068 while (run_test() == options
.numops
) ;
2071 return ret
== options
.numops
;
2075 static void usage(void)
2079 gentest2 //server1/share1 //server2/share2 [options..]\n\
2081 -U user%%pass (can be specified twice)\n\
2084 -a (show all ops)\n\
2085 -A backtrack to find minimal ops\n\
2086 -i FILE add a list of wildcard exclusions\n\
2087 -O enable oplocks\n\
2088 -S FILE set preset seeds file\n\
2089 -L use preset seeds\n\
2090 -F fast reconnect (just close files)\n\
2091 -C continuous analysis mode\n\
2092 -X analyse even when test OK\n\
2096 /****************************************************************************
2098 ****************************************************************************/
2099 int main(int argc
, char *argv
[])
2107 setup_logging("gentest", DEBUG_STDOUT
);
2109 if (argc
< 3 || argv
[1][0] == '-') {
2114 setup_logging(argv
[0], DEBUG_STDOUT
);
2116 for (i
=0;i
<NSERVERS
;i
++) {
2117 const char *share
= argv
[1+i
];
2118 servers
[i
].credentials
= cli_credentials_init(NULL
);
2119 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
2120 printf("Invalid share name '%s'\n", share
);
2128 lp_load(dyn_CONFIGFILE
,True
,False
,False
);
2131 options
.seed
= time(NULL
);
2132 options
.numops
= 1000;
2133 options
.max_open_handles
= 20;
2134 options
.seeds_file
= "gentest_seeds.dat";
2136 while ((opt
= getopt(argc
, argv
, "U:s:o:ad:i:AOhS:LFXC")) != EOF
) {
2139 i
= servers
[0].credentials
->username
?1:0;
2140 cli_credentials_parse_string(servers
[i
].credentials
, optarg
, CRED_SPECIFIED
);
2143 DEBUGLEVEL
= atoi(optarg
);
2144 setup_logging(NULL
, DEBUG_STDOUT
);
2147 options
.seed
= atoi(optarg
);
2150 options
.seeds_file
= optarg
;
2153 options
.use_preset_seeds
= True
;
2156 options
.fast_reconnect
= True
;
2159 options
.numops
= atoi(optarg
);
2162 options
.use_oplocks
= True
;
2165 options
.showall
= True
;
2168 options
.analyze
= True
;
2171 options
.analyze_always
= True
;
2174 options
.analyze_continuous
= True
;
2177 options
.ignore_patterns
= file_lines_load(optarg
, NULL
);
2183 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
2188 gentest_init_subsystems
;
2190 if (!servers
[0].credentials
->username
) {
2194 if (!servers
[1].credentials
->username
) {
2195 servers
[1].credentials
->username
= servers
[0].credentials
->username
;
2196 servers
[1].credentials
->password
= servers
[0].credentials
->password
;
2199 printf("seed=%u\n", options
.seed
);
2201 ret
= start_gentest();
2204 printf("gentest completed - no errors\n");
2206 printf("gentest failed\n");