smbd: Factor out get_share_mode_write_time of get_file_infos
[Samba.git] / source4 / torture / gentest.c
blob9e985ed68131a09aa42381ab208712b75c5fed96
1 /*
2 Unix SMB/CIFS implementation.
4 generic testing tool - version with both SMB and SMB2 support
6 Copyright (C) Andrew Tridgell 2003-2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "lib/events/events.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/request.h"
28 #include "libcli/libcli.h"
29 #include "libcli/raw/libcliraw.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/smb2/smb2_calls.h"
32 #include "librpc/gen_ndr/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "auth/credentials/credentials.h"
35 #include "libcli/resolve/resolve.h"
36 #include "auth/gensec/gensec.h"
37 #include "param/param.h"
38 #include "dynconfig/dynconfig.h"
39 #include "libcli/security/security.h"
40 #include "libcli/raw/raw_proto.h"
41 #include "../libcli/smb/smbXcli_base.h"
43 #define NSERVERS 2
44 #define NINSTANCES 2
46 /* global options */
47 static struct gentest_options {
48 int showall;
49 int analyze;
50 int analyze_always;
51 int analyze_continuous;
52 unsigned int max_open_handles;
53 unsigned int seed;
54 unsigned int numops;
55 int use_oplocks;
56 char **ignore_patterns;
57 const char *seeds_file;
58 int use_preset_seeds;
59 int fast_reconnect;
60 int mask_indexing;
61 int no_eas;
62 int no_acls;
63 int skip_cleanup;
64 int valid;
65 int smb2;
66 } options;
68 /* mapping between open handles on the server and local handles */
69 static struct {
70 bool active;
71 unsigned int instance;
72 struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */
73 uint16_t smb_handle[NSERVERS]; /* SMB */
74 const char *name;
75 } *open_handles;
76 static unsigned int num_open_handles;
78 /* state information for the servers. We open NINSTANCES connections to
79 each server */
80 static struct {
81 struct smb2_tree *smb2_tree[NINSTANCES];
82 struct smbcli_tree *smb_tree[NINSTANCES];
83 char *server_name;
84 char *share_name;
85 struct cli_credentials *credentials;
86 } servers[NSERVERS];
88 /* the seeds and flags for each operation */
89 static struct {
90 unsigned int seed;
91 bool disabled;
92 } *op_parms;
95 /* oplock break info */
96 static struct {
97 bool got_break;
98 struct smb2_handle smb2_handle;
99 uint16_t smb_handle;
100 uint16_t handle;
101 uint8_t level;
102 bool do_close;
103 } oplocks[NSERVERS][NINSTANCES];
105 /* change notify reply info */
106 static struct {
107 int notify_count;
108 NTSTATUS status;
109 union smb_notify notify;
110 } notifies[NSERVERS][NINSTANCES];
112 /* info relevant to the current operation */
113 static struct {
114 const char *name;
115 unsigned int seed;
116 NTSTATUS status;
117 unsigned int opnum;
118 TALLOC_CTX *mem_ctx;
119 const char *mismatch;
120 } current_op;
122 static struct smb2_handle bad_smb2_handle;
125 #define BAD_HANDLE 0xFFFE
127 static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle,
128 uint8_t level, void *private_data);
129 static void idle_func_smb2(struct smb2_transport *transport, void *private_data);
130 static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data);
131 static void idle_func_smb(struct smbcli_transport *transport, void *private_data);
134 check if a string should be ignored. This is used as the basis
135 for all error ignore settings
137 static bool ignore_pattern(const char *str)
139 int i;
140 if (!options.ignore_patterns) return false;
142 for (i=0;options.ignore_patterns[i];i++) {
143 if (strcmp(options.ignore_patterns[i], str) == 0 ||
144 gen_fnmatch(options.ignore_patterns[i], str) == 0) {
145 DEBUG(2,("Ignoring '%s'\n", str));
146 return true;
149 return false;
152 /*****************************************************
153 connect to the servers
154 *******************************************************/
155 static bool connect_servers_fast(void)
157 int h, i;
159 /* close all open files */
160 for (h=0;h<options.max_open_handles;h++) {
161 if (!open_handles[h].active) continue;
162 for (i=0;i<NSERVERS;i++) {
163 NTSTATUS status;
164 if (options.smb2) {
165 status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance],
166 open_handles[h].smb2_handle[i]);
167 } else {
168 status = smbcli_close(servers[i].smb_tree[open_handles[h].instance],
169 open_handles[h].smb_handle[i]);
171 if (NT_STATUS_IS_ERR(status)) {
172 return false;
174 open_handles[h].active = false;
178 return true;
184 /*****************************************************
185 connect to the servers
186 *******************************************************/
187 static bool connect_servers(struct tevent_context *ev,
188 struct loadparm_context *lp_ctx)
190 int i, j;
192 if (options.fast_reconnect && servers[0].smb2_tree[0]) {
193 if (connect_servers_fast()) {
194 return true;
198 /* close any existing connections */
199 for (i=0;i<NSERVERS;i++) {
200 for (j=0;j<NINSTANCES;j++) {
201 if (servers[i].smb2_tree[j]) {
202 smb2_tdis(servers[i].smb2_tree[j]);
203 talloc_free(servers[i].smb2_tree[j]);
204 servers[i].smb2_tree[j] = NULL;
206 if (servers[i].smb_tree[j]) {
207 smb_tree_disconnect(servers[i].smb_tree[j]);
208 talloc_free(servers[i].smb_tree[j]);
209 servers[i].smb_tree[j] = NULL;
214 for (i=0;i<NSERVERS;i++) {
215 for (j=0;j<NINSTANCES;j++) {
216 NTSTATUS status;
217 struct smbcli_options smb_options;
218 struct smbcli_session_options smb_session_options;
219 lpcfg_smbcli_options(lp_ctx, &smb_options);
220 lpcfg_smbcli_session_options(lp_ctx, &smb_session_options);
222 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
223 servers[i].server_name, servers[i].share_name,
224 cli_credentials_get_username(servers[i].credentials),
227 cli_credentials_set_workstation(servers[i].credentials,
228 "gentest", CRED_SPECIFIED);
230 if (options.smb2) {
231 status = smb2_connect(NULL, servers[i].server_name,
232 lpcfg_smb_ports(lp_ctx),
233 servers[i].share_name,
234 lpcfg_resolve_context(lp_ctx),
235 servers[i].credentials,
236 &servers[i].smb2_tree[j],
237 ev, &smb_options,
238 lpcfg_socket_options(lp_ctx),
239 lpcfg_gensec_settings(lp_ctx, lp_ctx)
241 } else {
242 status = smbcli_tree_full_connection(NULL,
243 &servers[i].smb_tree[j],
244 servers[i].server_name,
245 lpcfg_smb_ports(lp_ctx),
246 servers[i].share_name, "A:",
247 lpcfg_socket_options(lp_ctx),
248 servers[i].credentials,
249 lpcfg_resolve_context(lp_ctx), ev,
250 &smb_options,
251 &smb_session_options,
252 lpcfg_gensec_settings(lp_ctx, lp_ctx));
254 if (!NT_STATUS_IS_OK(status)) {
255 printf("Failed to connect to \\\\%s\\%s - %s\n",
256 servers[i].server_name, servers[i].share_name,
257 nt_errstr(status));
258 return false;
261 if (options.smb2) {
262 servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2;
263 servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j);
264 smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport,
265 idle_func_smb2, 50000, NULL);
266 } else {
267 smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb,
268 (void *)(uintptr_t)((i<<8)|j));
269 smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb,
270 50000, (void *)(uintptr_t)((i<<8)|j));
275 return true;
279 work out the time skew between the servers - be conservative
281 static unsigned int time_skew(void)
283 unsigned int ret;
284 NTTIME nt0, nt1;
286 if (options.smb2) {
287 struct smbXcli_conn *c0, *c1;
289 c0 = servers[0].smb2_tree[0]->session->transport->conn;
290 c1 = servers[1].smb2_tree[0]->session->transport->conn;
292 nt0 = smbXcli_conn_server_system_time(c0);
293 nt1 = smbXcli_conn_server_system_time(c1);
294 } else {
295 nt0 = servers[0].smb_tree[0]->session->transport->negotiate.server_time;
296 nt1 = servers[1].smb_tree[0]->session->transport->negotiate.server_time;
298 ret = labs(nt0 - nt1);
299 return ret + 300;
303 static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2)
305 return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0;
309 turn a server handle into a local handle
311 static unsigned int fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle)
313 unsigned int i;
314 for (i=0;i<options.max_open_handles;i++) {
315 if (!open_handles[i].active ||
316 instance != open_handles[i].instance) continue;
317 if (smb2_handle_equal(&open_handles[i].smb2_handle[server], &server_handle)) {
318 return i;
321 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
322 server, instance);
323 return BAD_HANDLE;
327 turn a server handle into a local handle
329 static unsigned int fnum_to_handle_smb(int server, int instance, uint16_t server_handle)
331 unsigned int i;
332 for (i=0;i<options.max_open_handles;i++) {
333 if (!open_handles[i].active ||
334 instance != open_handles[i].instance) continue;
335 if (open_handles[i].smb_handle[server] == server_handle) {
336 return i;
339 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
340 server, instance);
341 return BAD_HANDLE;
345 add some newly opened handles
347 static void gen_add_handle_smb2(int instance, const char *name, struct smb2_handle handles[NSERVERS])
349 int i, h;
350 for (h=0;h<options.max_open_handles;h++) {
351 if (!open_handles[h].active) break;
353 if (h == options.max_open_handles) {
354 /* we have to force close a random handle */
355 h = random() % options.max_open_handles;
356 for (i=0;i<NSERVERS;i++) {
357 NTSTATUS status;
358 status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance],
359 open_handles[h].smb2_handle[i]);
360 if (NT_STATUS_IS_ERR(status)) {
361 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
362 nt_errstr(status));
365 printf("Recovered handle %d\n", h);
366 num_open_handles--;
368 for (i=0;i<NSERVERS;i++) {
369 open_handles[h].smb2_handle[i] = handles[i];
370 open_handles[h].instance = instance;
371 open_handles[h].active = true;
372 open_handles[h].name = name;
374 num_open_handles++;
376 printf("OPEN num_open_handles=%d h=%d (%s)\n",
377 num_open_handles, h, name);
381 add some newly opened handles
383 static void gen_add_handle_smb(int instance, const char *name, uint16_t handles[NSERVERS])
385 int i, h;
386 for (h=0;h<options.max_open_handles;h++) {
387 if (!open_handles[h].active) break;
389 if (h == options.max_open_handles) {
390 /* we have to force close a random handle */
391 h = random() % options.max_open_handles;
392 for (i=0;i<NSERVERS;i++) {
393 NTSTATUS status;
394 status = smbcli_close(servers[i].smb_tree[open_handles[h].instance],
395 open_handles[h].smb_handle[i]);
396 if (NT_STATUS_IS_ERR(status)) {
397 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
398 nt_errstr(status));
401 printf("Recovered handle %d\n", h);
402 num_open_handles--;
404 for (i=0;i<NSERVERS;i++) {
405 open_handles[h].smb_handle[i] = handles[i];
406 open_handles[h].instance = instance;
407 open_handles[h].active = true;
408 open_handles[h].name = name;
410 num_open_handles++;
412 printf("OPEN num_open_handles=%d h=%d (%s)\n",
413 num_open_handles, h, name);
418 remove a closed handle
420 static void gen_remove_handle_smb2(int instance, struct smb2_handle handles[NSERVERS])
422 int h;
423 for (h=0;h<options.max_open_handles;h++) {
424 if (instance == open_handles[h].instance &&
425 smb2_handle_equal(&open_handles[h].smb2_handle[0], &handles[0])) {
426 open_handles[h].active = false;
427 num_open_handles--;
428 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
429 num_open_handles, h,
430 open_handles[h].name);
431 return;
434 printf("Removing invalid handle!?\n");
435 exit(1);
439 remove a closed handle
441 static void gen_remove_handle_smb(int instance, uint16_t handles[NSERVERS])
443 int h;
444 for (h=0;h<options.max_open_handles;h++) {
445 if (instance == open_handles[h].instance &&
446 open_handles[h].smb_handle[0] == handles[0]) {
447 open_handles[h].active = false;
448 num_open_handles--;
449 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
450 num_open_handles, h,
451 open_handles[h].name);
452 return;
455 printf("Removing invalid handle!?\n");
456 exit(1);
460 return true with 'chance' probability as a percentage
462 static bool gen_chance(unsigned int chance)
464 return ((random() % 100) <= chance);
468 map an internal handle number to a server handle
470 static struct smb2_handle gen_lookup_handle_smb2(int server, uint16_t handle)
472 if (handle == BAD_HANDLE) return bad_smb2_handle;
473 return open_handles[handle].smb2_handle[server];
477 map an internal handle number to a server handle
479 static uint16_t gen_lookup_handle_smb(int server, uint16_t handle)
481 if (handle == BAD_HANDLE) return BAD_HANDLE;
482 return open_handles[handle].smb_handle[server];
486 return a file handle
488 static uint16_t gen_fnum(int instance)
490 uint16_t h;
491 int count = 0;
493 if (gen_chance(20)) return BAD_HANDLE;
495 while (num_open_handles > 0 && count++ < 10*options.max_open_handles) {
496 h = random() % options.max_open_handles;
497 if (open_handles[h].active &&
498 open_handles[h].instance == instance) {
499 return h;
502 return BAD_HANDLE;
506 return a file handle, but skewed so we don't close the last
507 couple of handles too readily
509 static uint16_t gen_fnum_close(int instance)
511 if (num_open_handles < 5) {
512 if (gen_chance(90)) return BAD_HANDLE;
515 return gen_fnum(instance);
519 generate an integer in a specified range
521 static int gen_int_range(uint64_t min, uint64_t max)
523 unsigned int r = random();
524 return min + (r % (1+max-min));
528 return a fnum for use as a root fid
529 be careful to call GEN_SET_FNUM() when you use this!
531 static uint16_t gen_root_fid(int instance)
533 if (gen_chance(5)) return gen_fnum(instance);
534 return 0;
538 generate a file offset
540 static int gen_offset(void)
542 if (gen_chance(20)) return 0;
543 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
544 return gen_int_range(0, 1024*1024);
548 generate a io count
550 static int gen_io_count(void)
552 if (gen_chance(20)) return 0;
553 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
554 return gen_int_range(0, 4096);
558 generate a filename
560 static const char *gen_fname(void)
562 const char *names[] = {"gentest\\gentest.dat",
563 "gentest\\foo",
564 "gentest\\foo2.sym",
565 "gentest\\foo3.dll",
566 "gentest\\foo4",
567 "gentest\\foo4:teststream1",
568 "gentest\\foo4:teststream2",
569 "gentest\\foo5.exe",
570 "gentest\\foo5.exe:teststream3",
571 "gentest\\foo5.exe:teststream4",
572 "gentest\\foo6.com",
573 "gentest\\blah",
574 "gentest\\blah\\blergh.txt",
575 "gentest\\blah\\blergh2",
576 "gentest\\blah\\blergh3.txt",
577 "gentest\\blah\\blergh4",
578 "gentest\\blah\\blergh5.txt",
579 "gentest\\blah\\blergh5",
580 "gentest\\blah\\.",
581 "gentest\\blah\\..",
582 "gentest\\a_very_long_name.bin",
583 "gentest\\x.y",
584 "gentest\\blah"};
585 int i;
587 do {
588 i = gen_int_range(0, ARRAY_SIZE(names)-1);
589 } while (ignore_pattern(names[i]));
591 return names[i];
595 generate a filename with a higher chance of choosing an already
596 open file
598 static const char *gen_fname_open(int instance)
600 uint16_t h;
601 h = gen_fnum(instance);
602 if (h == BAD_HANDLE) {
603 return gen_fname();
605 return open_handles[h].name;
609 generate a wildcard pattern
611 static const char *gen_pattern(void)
613 int i;
614 const char *names[] = {"gentest\\*.dat",
615 "gentest\\*",
616 "gentest\\*.*",
617 "gentest\\blah\\*.*",
618 "gentest\\blah\\*",
619 "gentest\\?"};
621 if (gen_chance(50)) return gen_fname();
623 do {
624 i = gen_int_range(0, ARRAY_SIZE(names)-1);
625 } while (ignore_pattern(names[i]));
627 return names[i];
630 static uint32_t gen_bits_levels(int nlevels, ...)
632 va_list ap;
633 uint32_t pct;
634 uint32_t mask;
635 int i;
636 va_start(ap, nlevels);
637 for (i=0;i<nlevels;i++) {
638 pct = va_arg(ap, uint32_t);
639 mask = va_arg(ap, uint32_t);
640 if (pct == 100 || gen_chance(pct)) {
641 va_end(ap);
642 return mask & random();
645 va_end(ap);
646 return 0;
650 generate a bitmask
652 static uint32_t gen_bits_mask(unsigned int mask)
654 unsigned int ret = random();
655 return ret & mask;
659 generate a bitmask with high probability of the first mask
660 and low of the second
662 static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2)
664 if (!options.valid && gen_chance(10)) return gen_bits_mask(mask2);
665 return gen_bits_mask(mask1);
669 generate reserved values
671 static uint64_t gen_reserved8(void)
673 if (options.valid) return 0;
674 return gen_bits_mask(0xFF);
677 static uint64_t gen_reserved16(void)
679 if (options.valid) return 0;
680 return gen_bits_mask(0xFFFF);
683 static uint64_t gen_reserved32(void)
685 if (options.valid) return 0;
686 return gen_bits_mask(0xFFFFFFFF);
689 static uint64_t gen_reserved64(void)
691 if (options.valid) return 0;
692 return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
698 generate a boolean
700 static bool gen_bool(void)
702 return gen_bits_mask2(0x1, 0xFF);
706 generate ntrename flags
708 static uint16_t gen_rename_flags(void)
710 if (gen_chance(30)) return RENAME_FLAG_RENAME;
711 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK;
712 if (gen_chance(30)) return RENAME_FLAG_COPY;
713 return gen_bits_mask(0xFFFF);
717 generate a pid
719 static uint16_t gen_pid(void)
721 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
722 return getpid();
726 return a set of lock flags
728 static uint16_t gen_lock_flags_smb2(void)
730 if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF);
731 if (gen_chance(20)) return gen_bits_mask(0x1F);
732 if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK;
733 return gen_bits_mask(SMB2_LOCK_FLAG_SHARED |
734 SMB2_LOCK_FLAG_EXCLUSIVE |
735 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY);
739 generate a lock count
741 static off_t gen_lock_count(void)
743 return gen_int_range(0, 3);
747 generate a NT access mask
749 static uint32_t gen_access_mask(void)
751 uint32_t ret;
752 if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED;
753 if (gen_chance(70)) return SEC_FILE_ALL;
754 ret = gen_bits_mask(0xFFFFFFFF);
755 if (options.valid) ret &= ~SEC_MASK_INVALID;
756 return ret;
760 return a lockingx lock mode
762 static uint16_t gen_lock_mode(void)
764 if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF);
765 if (gen_chance(20)) return gen_bits_mask(0x1F);
766 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES);
770 generate a ntcreatex flags field
772 static uint32_t gen_ntcreatex_flags(void)
774 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED;
775 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
779 generate a ntcreatex create options bitfield
781 static uint32_t gen_create_options(void)
783 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
784 if (gen_chance(50)) return 0;
785 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY);
789 generate a ntcreatex open disposition
791 static uint32_t gen_open_disp(void)
793 if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF;
794 if (!options.valid && gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
795 return gen_int_range(0, 5);
799 generate an openx open mode
801 static uint16_t gen_openx_mode(void)
803 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
804 if (gen_chance(20)) return gen_bits_mask(0xFF);
805 return OPENX_MODE_DENY_NONE | gen_bits_mask(0x3);
809 generate an openx flags field
811 static uint16_t gen_openx_flags(void)
813 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
814 return gen_bits_mask(0x7);
818 generate an openx open function
820 static uint16_t gen_openx_func(void)
822 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
823 return gen_bits_mask(0x13);
827 generate a file attrib combination
829 static uint32_t gen_attrib(void)
831 uint32_t ret;
832 if (gen_chance(20)) {
833 ret = gen_bits_mask(0xFFFFFFFF);
834 if (options.valid) ret &= FILE_ATTRIBUTE_ALL_MASK;
835 return ret;
837 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
841 generate a unix timestamp
843 static time_t gen_timet(void)
845 if (gen_chance(30)) return 0;
846 return (time_t)random();
850 generate a milliseconds protocol timeout
852 static uint32_t gen_timeout(void)
854 if (gen_chance(98)) return 0;
855 return random() % 50;
859 generate a timestamp
861 static NTTIME gen_nttime(void)
863 NTTIME ret;
864 unix_to_nt_time(&ret, gen_timet());
865 return ret;
869 generate a timewarp value
871 static NTTIME gen_timewarp(void)
873 NTTIME ret = gen_nttime();
874 if (gen_chance(98)) ret = 0;
875 return ret;
879 generate a file allocation size
881 static unsigned int gen_alloc_size(void)
883 unsigned int ret;
885 if (gen_chance(30)) return 0;
887 ret = random() % 4*1024*1024;
888 /* give a high chance of a round number */
889 if (gen_chance(60)) {
890 ret &= ~(1024*1024 - 1);
892 return ret;
896 generate an ea_struct
898 static struct ea_struct gen_ea_struct(void)
900 struct ea_struct ea;
901 const char *names[] = {"EAONE",
902 "",
903 "FOO!",
904 " WITH SPACES ",
905 ".",
906 "AVERYLONGATTRIBUTENAME"};
907 const char *values[] = {"VALUE1",
908 "",
909 "NOT MUCH FOO",
910 " LEADING SPACES ",
911 ":",
912 "ASOMEWHATLONGERATTRIBUTEVALUE"};
913 int i;
915 ZERO_STRUCT(ea);
917 do {
918 i = gen_int_range(0, ARRAY_SIZE(names)-1);
919 } while (ignore_pattern(names[i]));
921 ea.name.s = names[i];
923 do {
924 i = gen_int_range(0, ARRAY_SIZE(values)-1);
925 } while (ignore_pattern(values[i]));
927 ea.value = data_blob(values[i], strlen(values[i]));
929 if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF);
930 ea.flags = 0;
932 return ea;
936 generate an ea_struct
938 static struct smb_ea_list gen_ea_list(void)
940 struct smb_ea_list eas;
941 int i;
942 if (options.no_eas) {
943 ZERO_STRUCT(eas);
944 return eas;
946 eas.num_eas = gen_int_range(0, 3);
947 eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas);
948 for (i=0;i<eas.num_eas;i++) {
949 eas.eas[i] = gen_ea_struct();
951 return eas;
954 /* generate a security descriptor */
955 static struct security_descriptor *gen_sec_desc(void)
957 struct security_descriptor *sd;
958 if (options.no_acls || gen_chance(90)) return NULL;
960 sd = security_descriptor_dacl_create(current_op.mem_ctx,
961 0, NULL, NULL,
962 NULL,
963 SEC_ACE_TYPE_ACCESS_ALLOWED,
964 SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
965 SEC_ACE_FLAG_OBJECT_INHERIT,
966 SID_WORLD,
967 SEC_ACE_TYPE_ACCESS_ALLOWED,
968 SEC_FILE_ALL | SEC_STD_ALL,
970 NULL);
971 return sd;
975 static void oplock_handler_close_recv_smb(struct smbcli_request *req)
977 NTSTATUS status;
978 status = smbcli_request_simple_recv(req);
979 if (!NT_STATUS_IS_OK(status)) {
980 printf("close failed in oplock_handler\n");
981 smb_panic("close failed in oplock_handler");
986 the oplock handler will either ack the break or close the file
988 static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data)
990 union smb_close io;
991 int i, j;
992 bool do_close;
993 struct smbcli_tree *tree = NULL;
994 struct smbcli_request *req;
996 srandom(current_op.seed);
997 do_close = gen_chance(50);
999 for (i=0;i<NSERVERS;i++) {
1000 for (j=0;j<NINSTANCES;j++) {
1001 if (transport == servers[i].smb_tree[j]->session->transport &&
1002 tid == servers[i].smb_tree[j]->tid) {
1003 oplocks[i][j].got_break = true;
1004 oplocks[i][j].smb_handle = fnum;
1005 oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum);
1006 oplocks[i][j].level = level;
1007 oplocks[i][j].do_close = do_close;
1008 tree = servers[i].smb_tree[j];
1013 if (!tree) {
1014 printf("Oplock break not for one of our trees!?\n");
1015 return false;
1018 if (!do_close) {
1019 printf("oplock ack fnum=%d\n", fnum);
1020 return smbcli_oplock_ack(tree, fnum, level);
1023 printf("oplock close fnum=%d\n", fnum);
1025 io.close.level = RAW_CLOSE_CLOSE;
1026 io.close.in.file.fnum = fnum;
1027 io.close.in.write_time = 0;
1028 req = smb_raw_close_send(tree, &io);
1030 if (req == NULL) {
1031 printf("WARNING: close failed in oplock_handler_close\n");
1032 return false;
1035 req->async.fn = oplock_handler_close_recv_smb;
1036 req->async.private_data = NULL;
1038 return true;
1043 the idle function tries to cope with getting an oplock break on a connection, and
1044 an operation on another connection blocking until that break is acked
1045 we check for operations on all transports in the idle function
1047 static void idle_func_smb(struct smbcli_transport *transport, void *private_data)
1049 int i, j;
1050 for (i=0;i<NSERVERS;i++) {
1051 for (j=0;j<NINSTANCES;j++) {
1052 if (servers[i].smb_tree[j] &&
1053 transport != servers[i].smb_tree[j]->session->transport) {
1054 smbcli_transport_process(servers[i].smb_tree[j]->session->transport);
1061 static void oplock_handler_close_recv_smb2(struct smb2_request *req)
1063 NTSTATUS status;
1064 struct smb2_close io;
1065 status = smb2_close_recv(req, &io);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 printf("close failed in oplock_handler\n");
1068 smb_panic("close failed in oplock_handler");
1072 static void oplock_handler_ack_callback_smb2(struct smb2_request *req)
1074 NTSTATUS status;
1075 struct smb2_break br;
1077 status = smb2_break_recv(req, &br);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 printf("oplock break ack failed in oplock_handler\n");
1080 smb_panic("oplock break ack failed in oplock_handler");
1084 static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle,
1085 uint8_t level)
1087 struct smb2_break br;
1088 struct smb2_request *req;
1090 ZERO_STRUCT(br);
1091 br.in.file.handle = handle;
1092 br.in.oplock_level = level;
1093 br.in.reserved = gen_reserved8();
1094 br.in.reserved2 = gen_reserved32();
1096 req = smb2_break_send(tree, &br);
1097 if (req == NULL) return false;
1098 req->async.fn = oplock_handler_ack_callback_smb2;
1099 req->async.private_data = NULL;
1100 return true;
1104 the oplock handler will either ack the break or close the file
1106 static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle,
1107 uint8_t level, void *private_data)
1109 struct smb2_close io;
1110 unsigned i, j;
1111 bool do_close;
1112 struct smb2_tree *tree = NULL;
1113 struct smb2_request *req;
1115 srandom(current_op.seed);
1116 do_close = gen_chance(50);
1118 i = ((uintptr_t)private_data) >> 8;
1119 j = ((uintptr_t)private_data) & 0xFF;
1121 if (i >= NSERVERS || j >= NINSTANCES) {
1122 printf("Bad private_data in oplock_handler\n");
1123 return false;
1126 oplocks[i][j].got_break = true;
1127 oplocks[i][j].smb2_handle = *handle;
1128 oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle);
1129 oplocks[i][j].level = level;
1130 oplocks[i][j].do_close = do_close;
1131 tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree);
1133 if (!tree) {
1134 printf("Oplock break not for one of our trees!?\n");
1135 return false;
1138 if (!do_close) {
1139 printf("oplock ack handle=%d\n", oplocks[i][j].handle);
1140 return send_oplock_ack_smb2(tree, *handle, level);
1143 printf("oplock close fnum=%d\n", oplocks[i][j].handle);
1145 ZERO_STRUCT(io);
1146 io.in.file.handle = *handle;
1147 io.in.flags = 0;
1148 req = smb2_close_send(tree, &io);
1150 if (req == NULL) {
1151 printf("WARNING: close failed in oplock_handler_close\n");
1152 return false;
1155 req->async.fn = oplock_handler_close_recv_smb2;
1156 req->async.private_data = NULL;
1158 return true;
1163 the idle function tries to cope with getting an oplock break on a connection, and
1164 an operation on another connection blocking until that break is acked
1165 we check for operations on all transports in the idle function
1167 static void idle_func_smb2(struct smb2_transport *transport, void *private_data)
1169 int i, j;
1170 for (i=0;i<NSERVERS;i++) {
1171 for (j=0;j<NINSTANCES;j++) {
1172 if (servers[i].smb2_tree[j] &&
1173 transport != servers[i].smb2_tree[j]->session->transport) {
1174 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1183 compare NTSTATUS, using checking ignored patterns
1185 static bool compare_status(NTSTATUS status1, NTSTATUS status2)
1187 char *s;
1189 if (NT_STATUS_EQUAL(status1, status2)) return true;
1191 /* one code being an error and the other OK is always an error */
1192 if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) {
1193 current_op.mismatch = nt_errstr(status1);
1194 return false;
1197 /* if we are ignoring one of the status codes then consider this a match */
1198 if (ignore_pattern(nt_errstr(status1)) ||
1199 ignore_pattern(nt_errstr(status2))) {
1200 return true;
1203 /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY
1204 meaning that the first server returns NT_STATUS_XX and the 2nd
1205 returns NT_STATUS_YY */
1206 s = talloc_asprintf(current_op.mem_ctx, "%s:%s",
1207 nt_errstr(status1),
1208 nt_errstr(status2));
1209 if (ignore_pattern(s)) {
1210 return true;
1213 current_op.mismatch = nt_errstr(status1);
1214 return false;
1218 check for pending packets on all connections
1220 static void check_pending(void)
1222 int i, j;
1224 smb_msleep(20);
1226 for (j=0;j<NINSTANCES;j++) {
1227 for (i=0;i<NSERVERS;i++) {
1228 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1234 check that the same oplock breaks have been received by all instances
1236 static bool check_oplocks(const char *call)
1238 int i, j;
1239 int tries = 0;
1241 if (!options.use_oplocks || options.smb2) {
1242 /* no smb2 oplocks in gentest yet */
1243 return true;
1246 again:
1247 check_pending();
1249 for (j=0;j<NINSTANCES;j++) {
1250 for (i=1;i<NSERVERS;i++) {
1251 if (oplocks[0][j].got_break != oplocks[i][j].got_break ||
1252 oplocks[0][j].handle != oplocks[i][j].handle ||
1253 oplocks[0][j].level != oplocks[i][j].level) {
1254 if (tries++ < 10) goto again;
1255 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
1256 oplocks[0][j].got_break,
1257 oplocks[0][j].handle,
1258 oplocks[0][j].level,
1259 oplocks[i][j].got_break,
1260 oplocks[i][j].handle,
1261 oplocks[i][j].level);
1262 current_op.mismatch = "oplock break";
1263 return false;
1268 /* if we got a break and closed then remove the handle */
1269 for (j=0;j<NINSTANCES;j++) {
1270 if (oplocks[0][j].got_break &&
1271 oplocks[0][j].do_close) {
1272 uint16_t fnums[NSERVERS];
1273 for (i=0;i<NSERVERS;i++) {
1274 fnums[i] = oplocks[i][j].smb_handle;
1276 gen_remove_handle_smb(j, fnums);
1277 break;
1280 return true;
1285 check that the same change notify info has been received by all instances
1287 static bool check_notifies(const char *call)
1289 int i, j;
1290 int tries = 0;
1292 if (options.smb2) {
1293 /* no smb2 notifies in gentest yet */
1294 return true;
1297 again:
1298 check_pending();
1300 for (j=0;j<NINSTANCES;j++) {
1301 for (i=1;i<NSERVERS;i++) {
1302 int n;
1303 union smb_notify not1, not2;
1305 if (notifies[0][j].notify_count != notifies[i][j].notify_count) {
1306 if (tries++ < 10) goto again;
1307 printf("Notify count inconsistent %d %d\n",
1308 notifies[0][j].notify_count,
1309 notifies[i][j].notify_count);
1310 current_op.mismatch = "notify count";
1311 return false;
1314 if (notifies[0][j].notify_count == 0) continue;
1316 if (!NT_STATUS_EQUAL(notifies[0][j].status,
1317 notifies[i][j].status)) {
1318 printf("Notify status mismatch - %s - %s\n",
1319 nt_errstr(notifies[0][j].status),
1320 nt_errstr(notifies[i][j].status));
1321 current_op.mismatch = "Notify status";
1322 return false;
1325 if (!NT_STATUS_IS_OK(notifies[0][j].status)) {
1326 continue;
1329 not1 = notifies[0][j].notify;
1330 not2 = notifies[i][j].notify;
1332 for (n=0;n<not1.nttrans.out.num_changes;n++) {
1333 if (not1.nttrans.out.changes[n].action !=
1334 not2.nttrans.out.changes[n].action) {
1335 printf("Notify action %d inconsistent %d %d\n", n,
1336 not1.nttrans.out.changes[n].action,
1337 not2.nttrans.out.changes[n].action);
1338 current_op.mismatch = "notify action";
1339 return false;
1341 if (strcmp(not1.nttrans.out.changes[n].name.s,
1342 not2.nttrans.out.changes[n].name.s)) {
1343 printf("Notify name %d inconsistent %s %s\n", n,
1344 not1.nttrans.out.changes[n].name.s,
1345 not2.nttrans.out.changes[n].name.s);
1346 current_op.mismatch = "notify name";
1347 return false;
1349 if (not1.nttrans.out.changes[n].name.private_length !=
1350 not2.nttrans.out.changes[n].name.private_length) {
1351 printf("Notify name length %d inconsistent %d %d\n", n,
1352 not1.nttrans.out.changes[n].name.private_length,
1353 not2.nttrans.out.changes[n].name.private_length);
1354 current_op.mismatch = "notify name length";
1355 return false;
1361 ZERO_STRUCT(notifies);
1363 return true;
1366 #define GEN_COPY_PARM do { \
1367 int i; \
1368 for (i=1;i<NSERVERS;i++) { \
1369 parm[i] = parm[0]; \
1371 } while (0)
1373 #define GEN_CALL(call, treetype, treefield) do { \
1374 int i; \
1375 ZERO_STRUCT(oplocks); \
1376 ZERO_STRUCT(notifies); \
1377 for (i=0;i<NSERVERS;i++) { \
1378 struct treetype *tree = servers[i].treefield[instance]; \
1379 status[i] = call; \
1381 current_op.status = status[0]; \
1382 for (i=1;i<NSERVERS;i++) { \
1383 if (!compare_status(status[0], status[1])) { \
1384 printf("status different in %s - %s %s\n", #call, \
1385 nt_errstr(status[0]), nt_errstr(status[i])); \
1386 current_op.mismatch = nt_errstr(status[0]); \
1387 return false; \
1390 if (!check_oplocks(#call)) return false; \
1391 if (!check_notifies(#call)) return false; \
1392 if (!NT_STATUS_IS_OK(status[0])) { \
1393 return true; \
1395 } while(0)
1397 #define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree)
1398 #define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree)
1400 #define ADD_HANDLE_SMB2(name, field) do { \
1401 struct smb2_handle handles[NSERVERS]; \
1402 int i; \
1403 for (i=0;i<NSERVERS;i++) { \
1404 handles[i] = parm[i].field; \
1406 gen_add_handle_smb2(instance, name, handles); \
1407 } while(0)
1409 #define REMOVE_HANDLE_SMB2(field) do { \
1410 struct smb2_handle handles[NSERVERS]; \
1411 int i; \
1412 for (i=0;i<NSERVERS;i++) { \
1413 handles[i] = parm[i].field; \
1415 gen_remove_handle_smb2(instance, handles); \
1416 } while(0)
1418 #define ADD_HANDLE_SMB(name, field) do { \
1419 uint16_t handles[NSERVERS]; \
1420 int i; \
1421 for (i=0;i<NSERVERS;i++) { \
1422 handles[i] = parm[i].field; \
1424 gen_add_handle_smb(instance, name, handles); \
1425 } while(0)
1427 #define REMOVE_HANDLE_SMB(field) do { \
1428 uint16_t handles[NSERVERS]; \
1429 int i; \
1430 for (i=0;i<NSERVERS;i++) { \
1431 handles[i] = parm[i].field; \
1433 gen_remove_handle_smb(instance, handles); \
1434 } while(0)
1436 #define GEN_SET_FNUM_SMB2(field) do { \
1437 int i; \
1438 for (i=0;i<NSERVERS;i++) { \
1439 parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \
1441 } while(0)
1443 #define GEN_SET_FNUM_SMB(field) do { \
1444 int i; \
1445 for (i=0;i<NSERVERS;i++) { \
1446 parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \
1448 } while(0)
1450 #define CHECK_EQUAL(field) do { \
1451 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1452 current_op.mismatch = #field; \
1453 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
1454 (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
1455 return false; \
1457 } while(0)
1459 #define CHECK_SECDESC(field) do { \
1460 if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \
1461 current_op.mismatch = #field; \
1462 printf("Mismatch in %s\n", #field); \
1463 return false; \
1465 } while(0)
1467 #define CHECK_ATTRIB(field) do { \
1468 if (!options.mask_indexing) { \
1469 CHECK_EQUAL(field); \
1470 } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
1471 current_op.mismatch = #field; \
1472 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1473 (int)parm[0].field, (int)parm[1].field); \
1474 return false; \
1476 } while(0)
1478 #define CHECK_WSTR_EQUAL(field) do { \
1479 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1480 current_op.mismatch = #field; \
1481 printf("%s is NULL!\n", #field); \
1482 return false; \
1484 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1485 current_op.mismatch = #field; \
1486 printf("Mismatch in %s - %s %s\n", #field, \
1487 parm[0].field.s, parm[1].field.s); \
1488 return false; \
1490 CHECK_EQUAL(field.private_length); \
1491 } while(0)
1493 #define CHECK_BLOB_EQUAL(field) do { \
1494 if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \
1495 (parm[1].field.data == NULL && parm[0].field.data != NULL) || \
1496 (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \
1497 current_op.mismatch = #field; \
1498 printf("Mismatch in %s\n", #field); \
1499 return false; \
1501 CHECK_EQUAL(field.length); \
1502 } while(0)
1504 #define CHECK_TIMES_EQUAL(field) do { \
1505 if (labs(parm[0].field - parm[1].field) > time_skew() && \
1506 !ignore_pattern(#field)) { \
1507 current_op.mismatch = #field; \
1508 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1509 (int)parm[0].field, (int)parm[1].field); \
1510 return false; \
1512 } while(0)
1514 #define CHECK_NTTIMES_EQUAL(field) do { \
1515 if (labs(nt_time_to_unix(parm[0].field) - \
1516 nt_time_to_unix(parm[1].field)) > time_skew() && \
1517 !ignore_pattern(#field)) { \
1518 current_op.mismatch = #field; \
1519 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1520 (int)nt_time_to_unix(parm[0].field), \
1521 (int)nt_time_to_unix(parm[1].field)); \
1522 return false; \
1524 } while(0)
1528 compare returned fileinfo structures
1530 static bool cmp_fileinfo(int instance,
1531 union smb_fileinfo parm[NSERVERS],
1532 NTSTATUS status[NSERVERS])
1534 int i;
1535 enum smb_fileinfo_level level = parm[0].generic.level;
1537 if (level == RAW_FILEINFO_ALL_INFORMATION &&
1538 options.smb2) {
1539 level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
1542 switch (level) {
1543 case RAW_FILEINFO_GENERIC:
1544 return false;
1546 case RAW_FILEINFO_GETATTR:
1547 CHECK_ATTRIB(getattr.out.attrib);
1548 CHECK_EQUAL(getattr.out.size);
1549 CHECK_TIMES_EQUAL(getattr.out.write_time);
1550 break;
1552 case RAW_FILEINFO_GETATTRE:
1553 CHECK_TIMES_EQUAL(getattre.out.create_time);
1554 CHECK_TIMES_EQUAL(getattre.out.access_time);
1555 CHECK_TIMES_EQUAL(getattre.out.write_time);
1556 CHECK_EQUAL(getattre.out.size);
1557 CHECK_EQUAL(getattre.out.alloc_size);
1558 CHECK_ATTRIB(getattre.out.attrib);
1559 break;
1561 case RAW_FILEINFO_STANDARD:
1562 CHECK_TIMES_EQUAL(standard.out.create_time);
1563 CHECK_TIMES_EQUAL(standard.out.access_time);
1564 CHECK_TIMES_EQUAL(standard.out.write_time);
1565 CHECK_EQUAL(standard.out.size);
1566 CHECK_EQUAL(standard.out.alloc_size);
1567 CHECK_ATTRIB(standard.out.attrib);
1568 break;
1570 case RAW_FILEINFO_EA_SIZE:
1571 CHECK_TIMES_EQUAL(ea_size.out.create_time);
1572 CHECK_TIMES_EQUAL(ea_size.out.access_time);
1573 CHECK_TIMES_EQUAL(ea_size.out.write_time);
1574 CHECK_EQUAL(ea_size.out.size);
1575 CHECK_EQUAL(ea_size.out.alloc_size);
1576 CHECK_ATTRIB(ea_size.out.attrib);
1577 CHECK_EQUAL(ea_size.out.ea_size);
1578 break;
1580 case RAW_FILEINFO_ALL_EAS:
1581 CHECK_EQUAL(all_eas.out.num_eas);
1582 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1583 CHECK_EQUAL(all_eas.out.eas[i].flags);
1584 CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1585 CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1587 break;
1589 case RAW_FILEINFO_IS_NAME_VALID:
1590 break;
1592 case RAW_FILEINFO_BASIC_INFO:
1593 case RAW_FILEINFO_BASIC_INFORMATION:
1594 CHECK_NTTIMES_EQUAL(basic_info.out.create_time);
1595 CHECK_NTTIMES_EQUAL(basic_info.out.access_time);
1596 CHECK_NTTIMES_EQUAL(basic_info.out.write_time);
1597 CHECK_NTTIMES_EQUAL(basic_info.out.change_time);
1598 CHECK_ATTRIB(basic_info.out.attrib);
1599 break;
1601 case RAW_FILEINFO_STANDARD_INFO:
1602 case RAW_FILEINFO_STANDARD_INFORMATION:
1603 CHECK_EQUAL(standard_info.out.alloc_size);
1604 CHECK_EQUAL(standard_info.out.size);
1605 CHECK_EQUAL(standard_info.out.nlink);
1606 CHECK_EQUAL(standard_info.out.delete_pending);
1607 CHECK_EQUAL(standard_info.out.directory);
1608 break;
1610 case RAW_FILEINFO_EA_INFO:
1611 case RAW_FILEINFO_EA_INFORMATION:
1612 CHECK_EQUAL(ea_info.out.ea_size);
1613 break;
1615 case RAW_FILEINFO_NAME_INFO:
1616 case RAW_FILEINFO_NAME_INFORMATION:
1617 CHECK_WSTR_EQUAL(name_info.out.fname);
1618 break;
1620 case RAW_FILEINFO_ALL_INFO:
1621 case RAW_FILEINFO_ALL_INFORMATION:
1622 CHECK_NTTIMES_EQUAL(all_info.out.create_time);
1623 CHECK_NTTIMES_EQUAL(all_info.out.access_time);
1624 CHECK_NTTIMES_EQUAL(all_info.out.write_time);
1625 CHECK_NTTIMES_EQUAL(all_info.out.change_time);
1626 CHECK_ATTRIB(all_info.out.attrib);
1627 CHECK_EQUAL(all_info.out.alloc_size);
1628 CHECK_EQUAL(all_info.out.size);
1629 CHECK_EQUAL(all_info.out.nlink);
1630 CHECK_EQUAL(all_info.out.delete_pending);
1631 CHECK_EQUAL(all_info.out.directory);
1632 CHECK_EQUAL(all_info.out.ea_size);
1633 CHECK_WSTR_EQUAL(all_info.out.fname);
1634 break;
1636 case RAW_FILEINFO_ALT_NAME_INFO:
1637 case RAW_FILEINFO_ALT_NAME_INFORMATION:
1638 CHECK_WSTR_EQUAL(alt_name_info.out.fname);
1639 break;
1641 case RAW_FILEINFO_STREAM_INFO:
1642 case RAW_FILEINFO_STREAM_INFORMATION:
1643 CHECK_EQUAL(stream_info.out.num_streams);
1644 for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
1645 CHECK_EQUAL(stream_info.out.streams[i].size);
1646 CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
1647 CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
1649 break;
1651 case RAW_FILEINFO_COMPRESSION_INFO:
1652 case RAW_FILEINFO_COMPRESSION_INFORMATION:
1653 CHECK_EQUAL(compression_info.out.compressed_size);
1654 CHECK_EQUAL(compression_info.out.format);
1655 CHECK_EQUAL(compression_info.out.unit_shift);
1656 CHECK_EQUAL(compression_info.out.chunk_shift);
1657 CHECK_EQUAL(compression_info.out.cluster_shift);
1658 break;
1660 case RAW_FILEINFO_INTERNAL_INFORMATION:
1661 CHECK_EQUAL(internal_information.out.file_id);
1662 break;
1664 case RAW_FILEINFO_ACCESS_INFORMATION:
1665 CHECK_EQUAL(access_information.out.access_flags);
1666 break;
1668 case RAW_FILEINFO_POSITION_INFORMATION:
1669 CHECK_EQUAL(position_information.out.position);
1670 break;
1672 case RAW_FILEINFO_MODE_INFORMATION:
1673 CHECK_EQUAL(mode_information.out.mode);
1674 break;
1676 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
1677 CHECK_EQUAL(alignment_information.out.alignment_requirement);
1678 break;
1680 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1681 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
1682 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
1683 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
1684 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
1685 CHECK_EQUAL(network_open_information.out.alloc_size);
1686 CHECK_EQUAL(network_open_information.out.size);
1687 CHECK_ATTRIB(network_open_information.out.attrib);
1688 break;
1690 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1691 CHECK_ATTRIB(attribute_tag_information.out.attrib);
1692 CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
1693 break;
1695 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
1696 CHECK_NTTIMES_EQUAL(all_info2.out.create_time);
1697 CHECK_NTTIMES_EQUAL(all_info2.out.access_time);
1698 CHECK_NTTIMES_EQUAL(all_info2.out.write_time);
1699 CHECK_NTTIMES_EQUAL(all_info2.out.change_time);
1700 CHECK_ATTRIB(all_info2.out.attrib);
1701 CHECK_EQUAL(all_info2.out.unknown1);
1702 CHECK_EQUAL(all_info2.out.alloc_size);
1703 CHECK_EQUAL(all_info2.out.size);
1704 CHECK_EQUAL(all_info2.out.nlink);
1705 CHECK_EQUAL(all_info2.out.delete_pending);
1706 CHECK_EQUAL(all_info2.out.directory);
1707 CHECK_EQUAL(all_info2.out.file_id);
1708 CHECK_EQUAL(all_info2.out.ea_size);
1709 CHECK_EQUAL(all_info2.out.access_mask);
1710 CHECK_EQUAL(all_info2.out.position);
1711 CHECK_EQUAL(all_info2.out.mode);
1712 CHECK_EQUAL(all_info2.out.alignment_requirement);
1713 CHECK_WSTR_EQUAL(all_info2.out.fname);
1714 break;
1716 case RAW_FILEINFO_SMB2_ALL_EAS:
1717 CHECK_EQUAL(all_eas.out.num_eas);
1718 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1719 CHECK_EQUAL(all_eas.out.eas[i].flags);
1720 CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1721 CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1723 break;
1725 case RAW_FILEINFO_SEC_DESC:
1726 CHECK_SECDESC(query_secdesc.out.sd);
1727 break;
1729 /* Unhandled levels */
1730 case RAW_FILEINFO_EA_LIST:
1731 case RAW_FILEINFO_UNIX_BASIC:
1732 case RAW_FILEINFO_UNIX_LINK:
1733 case RAW_FILEINFO_UNIX_INFO2:
1734 break;
1737 return true;
1743 generate openx operations
1745 static bool handler_smb_openx(int instance)
1747 union smb_open parm[NSERVERS];
1748 NTSTATUS status[NSERVERS];
1750 parm[0].openx.level = RAW_OPEN_OPENX;
1751 parm[0].openx.in.flags = gen_openx_flags();
1752 parm[0].openx.in.open_mode = gen_openx_mode();
1753 parm[0].openx.in.search_attrs = gen_attrib();
1754 parm[0].openx.in.file_attrs = gen_attrib();
1755 parm[0].openx.in.write_time = gen_timet();
1756 parm[0].openx.in.open_func = gen_openx_func();
1757 parm[0].openx.in.size = gen_io_count();
1758 parm[0].openx.in.timeout = gen_timeout();
1759 parm[0].openx.in.fname = gen_fname_open(instance);
1761 if (!options.use_oplocks) {
1762 /* mask out oplocks */
1763 parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1764 OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1767 GEN_COPY_PARM;
1768 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1770 CHECK_ATTRIB(openx.out.attrib);
1771 CHECK_EQUAL(openx.out.size);
1772 CHECK_EQUAL(openx.out.access);
1773 CHECK_EQUAL(openx.out.ftype);
1774 CHECK_EQUAL(openx.out.devstate);
1775 CHECK_EQUAL(openx.out.action);
1776 CHECK_EQUAL(openx.out.access_mask);
1777 CHECK_EQUAL(openx.out.unknown);
1778 CHECK_TIMES_EQUAL(openx.out.write_time);
1780 /* open creates a new file handle */
1781 ADD_HANDLE_SMB(parm[0].openx.in.fname, openx.out.file.fnum);
1783 return true;
1788 generate open operations
1790 static bool handler_smb_open(int instance)
1792 union smb_open parm[NSERVERS];
1793 NTSTATUS status[NSERVERS];
1795 parm[0].openold.level = RAW_OPEN_OPEN;
1796 parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF);
1797 parm[0].openold.in.search_attrs = gen_attrib();
1798 parm[0].openold.in.fname = gen_fname_open(instance);
1800 if (!options.use_oplocks) {
1801 /* mask out oplocks */
1802 parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1803 OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1806 GEN_COPY_PARM;
1807 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1809 CHECK_ATTRIB(openold.out.attrib);
1810 CHECK_TIMES_EQUAL(openold.out.write_time);
1811 CHECK_EQUAL(openold.out.size);
1812 CHECK_EQUAL(openold.out.rmode);
1814 /* open creates a new file handle */
1815 ADD_HANDLE_SMB(parm[0].openold.in.fname, openold.out.file.fnum);
1817 return true;
1822 generate ntcreatex operations
1824 static bool handler_smb_ntcreatex(int instance)
1826 union smb_open parm[NSERVERS];
1827 NTSTATUS status[NSERVERS];
1829 parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX;
1830 parm[0].ntcreatex.in.flags = gen_ntcreatex_flags();
1831 parm[0].ntcreatex.in.root_fid.fnum = gen_root_fid(instance);
1832 parm[0].ntcreatex.in.access_mask = gen_access_mask();
1833 parm[0].ntcreatex.in.alloc_size = gen_alloc_size();
1834 parm[0].ntcreatex.in.file_attr = gen_attrib();
1835 parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
1836 parm[0].ntcreatex.in.open_disposition = gen_open_disp();
1837 parm[0].ntcreatex.in.create_options = gen_create_options();
1838 parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF);
1839 parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF);
1840 parm[0].ntcreatex.in.fname = gen_fname_open(instance);
1842 if (!options.use_oplocks) {
1843 /* mask out oplocks */
1844 parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK|
1845 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK);
1848 GEN_COPY_PARM;
1849 if (parm[0].ntcreatex.in.root_fid.fnum != 0) {
1850 GEN_SET_FNUM_SMB(ntcreatex.in.root_fid.fnum);
1852 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1854 CHECK_EQUAL(ntcreatex.out.oplock_level);
1855 CHECK_EQUAL(ntcreatex.out.create_action);
1856 CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time);
1857 CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time);
1858 CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time);
1859 CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time);
1860 CHECK_ATTRIB(ntcreatex.out.attrib);
1861 CHECK_EQUAL(ntcreatex.out.alloc_size);
1862 CHECK_EQUAL(ntcreatex.out.size);
1863 CHECK_EQUAL(ntcreatex.out.file_type);
1864 CHECK_EQUAL(ntcreatex.out.ipc_state);
1865 CHECK_EQUAL(ntcreatex.out.is_directory);
1867 /* ntcreatex creates a new file handle */
1868 ADD_HANDLE_SMB(parm[0].ntcreatex.in.fname, ntcreatex.out.file.fnum);
1870 return true;
1874 generate close operations
1876 static bool handler_smb_close(int instance)
1878 union smb_close parm[NSERVERS];
1879 NTSTATUS status[NSERVERS];
1881 parm[0].close.level = RAW_CLOSE_CLOSE;
1882 parm[0].close.in.file.fnum = gen_fnum_close(instance);
1883 parm[0].close.in.write_time = gen_timet();
1885 GEN_COPY_PARM;
1886 GEN_SET_FNUM_SMB(close.in.file.fnum);
1887 GEN_CALL_SMB(smb_raw_close(tree, &parm[i]));
1889 REMOVE_HANDLE_SMB(close.in.file.fnum);
1891 return true;
1895 generate unlink operations
1897 static bool handler_smb_unlink(int instance)
1899 union smb_unlink parm[NSERVERS];
1900 NTSTATUS status[NSERVERS];
1902 parm[0].unlink.in.pattern = gen_pattern();
1903 parm[0].unlink.in.attrib = gen_attrib();
1905 GEN_COPY_PARM;
1906 GEN_CALL_SMB(smb_raw_unlink(tree, &parm[i]));
1908 return true;
1912 generate chkpath operations
1914 static bool handler_smb_chkpath(int instance)
1916 union smb_chkpath parm[NSERVERS];
1917 NTSTATUS status[NSERVERS];
1919 parm[0].chkpath.in.path = gen_fname_open(instance);
1921 GEN_COPY_PARM;
1922 GEN_CALL_SMB(smb_raw_chkpath(tree, &parm[i]));
1924 return true;
1928 generate mkdir operations
1930 static bool handler_smb_mkdir(int instance)
1932 union smb_mkdir parm[NSERVERS];
1933 NTSTATUS status[NSERVERS];
1935 parm[0].mkdir.level = RAW_MKDIR_MKDIR;
1936 parm[0].mkdir.in.path = gen_fname_open(instance);
1938 GEN_COPY_PARM;
1939 GEN_CALL_SMB(smb_raw_mkdir(tree, &parm[i]));
1941 return true;
1945 generate rmdir operations
1947 static bool handler_smb_rmdir(int instance)
1949 struct smb_rmdir parm[NSERVERS];
1950 NTSTATUS status[NSERVERS];
1952 parm[0].in.path = gen_fname_open(instance);
1954 GEN_COPY_PARM;
1955 GEN_CALL_SMB(smb_raw_rmdir(tree, &parm[i]));
1957 return true;
1961 generate rename operations
1963 static bool handler_smb_rename(int instance)
1965 union smb_rename parm[NSERVERS];
1966 NTSTATUS status[NSERVERS];
1968 parm[0].generic.level = RAW_RENAME_RENAME;
1969 parm[0].rename.in.pattern1 = gen_pattern();
1970 parm[0].rename.in.pattern2 = gen_pattern();
1971 parm[0].rename.in.attrib = gen_attrib();
1973 GEN_COPY_PARM;
1974 GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
1976 return true;
1980 generate ntrename operations
1982 static bool handler_smb_ntrename(int instance)
1984 union smb_rename parm[NSERVERS];
1985 NTSTATUS status[NSERVERS];
1987 parm[0].generic.level = RAW_RENAME_NTRENAME;
1988 parm[0].ntrename.in.old_name = gen_fname();
1989 parm[0].ntrename.in.new_name = gen_fname();
1990 parm[0].ntrename.in.attrib = gen_attrib();
1991 parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF);
1992 parm[0].ntrename.in.flags = gen_rename_flags();
1994 GEN_COPY_PARM;
1995 GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
1997 return true;
2002 generate seek operations
2004 static bool handler_smb_seek(int instance)
2006 union smb_seek parm[NSERVERS];
2007 NTSTATUS status[NSERVERS];
2009 parm[0].lseek.in.file.fnum = gen_fnum(instance);
2010 parm[0].lseek.in.mode = gen_bits_mask2(0x3, 0xFFFF);
2011 parm[0].lseek.in.offset = gen_offset();
2013 GEN_COPY_PARM;
2014 GEN_SET_FNUM_SMB(lseek.in.file.fnum);
2015 GEN_CALL_SMB(smb_raw_seek(tree, &parm[i]));
2017 CHECK_EQUAL(lseek.out.offset);
2019 return true;
2024 generate readx operations
2026 static bool handler_smb_readx(int instance)
2028 union smb_read parm[NSERVERS];
2029 NTSTATUS status[NSERVERS];
2031 parm[0].readx.level = RAW_READ_READX;
2032 parm[0].readx.in.file.fnum = gen_fnum(instance);
2033 parm[0].readx.in.offset = gen_offset();
2034 parm[0].readx.in.mincnt = gen_io_count();
2035 parm[0].readx.in.maxcnt = gen_io_count();
2036 parm[0].readx.in.remaining = gen_io_count();
2037 parm[0].readx.in.read_for_execute = gen_bool();
2038 parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t,
2039 MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt));
2041 GEN_COPY_PARM;
2042 GEN_SET_FNUM_SMB(readx.in.file.fnum);
2043 GEN_CALL_SMB(smb_raw_read(tree, &parm[i]));
2045 CHECK_EQUAL(readx.out.remaining);
2046 CHECK_EQUAL(readx.out.compaction_mode);
2047 CHECK_EQUAL(readx.out.nread);
2049 return true;
2053 generate writex operations
2055 static bool handler_smb_writex(int instance)
2057 union smb_write parm[NSERVERS];
2058 NTSTATUS status[NSERVERS];
2060 parm[0].writex.level = RAW_WRITE_WRITEX;
2061 parm[0].writex.in.file.fnum = gen_fnum(instance);
2062 parm[0].writex.in.offset = gen_offset();
2063 parm[0].writex.in.wmode = gen_bits_mask(0xFFFF);
2064 parm[0].writex.in.remaining = gen_io_count();
2065 parm[0].writex.in.count = gen_io_count();
2066 parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count);
2068 GEN_COPY_PARM;
2069 GEN_SET_FNUM_SMB(writex.in.file.fnum);
2070 GEN_CALL_SMB(smb_raw_write(tree, &parm[i]));
2072 CHECK_EQUAL(writex.out.nwritten);
2073 CHECK_EQUAL(writex.out.remaining);
2075 return true;
2079 generate lockingx operations
2081 static bool handler_smb_lockingx(int instance)
2083 union smb_lock parm[NSERVERS];
2084 NTSTATUS status[NSERVERS];
2085 int n, nlocks;
2087 parm[0].lockx.level = RAW_LOCK_LOCKX;
2088 parm[0].lockx.in.file.fnum = gen_fnum(instance);
2089 parm[0].lockx.in.mode = gen_lock_mode();
2090 parm[0].lockx.in.timeout = gen_timeout();
2091 do {
2092 /* make sure we don't accidentially generate an oplock
2093 break ack - otherwise the server can just block forever */
2094 parm[0].lockx.in.ulock_cnt = gen_lock_count();
2095 parm[0].lockx.in.lock_cnt = gen_lock_count();
2096 nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt;
2097 } while (nlocks == 0);
2099 if (nlocks > 0) {
2100 parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx,
2101 struct smb_lock_entry,
2102 nlocks);
2103 for (n=0;n<nlocks;n++) {
2104 parm[0].lockx.in.locks[n].pid = gen_pid();
2105 parm[0].lockx.in.locks[n].offset = gen_offset();
2106 parm[0].lockx.in.locks[n].count = gen_io_count();
2110 GEN_COPY_PARM;
2111 GEN_SET_FNUM_SMB(lockx.in.file.fnum);
2112 GEN_CALL_SMB(smb_raw_lock(tree, &parm[i]));
2114 return true;
2117 #if 0
2119 generate a fileinfo query structure
2121 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2123 int i;
2124 #undef LVL
2125 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2126 struct {
2127 enum smb_setfileinfo_level level;
2128 const char *name;
2129 } levels[] = {
2130 #if 0
2131 /* disabled until win2003 can handle them ... */
2132 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO),
2133 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO),
2134 #endif
2135 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2136 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
2137 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
2138 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
2139 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2141 do {
2142 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2143 } while (ignore_pattern(levels[i].name));
2145 info->generic.level = levels[i].level;
2147 switch (info->generic.level) {
2148 case RAW_SFILEINFO_SETATTR:
2149 info->setattr.in.attrib = gen_attrib();
2150 info->setattr.in.write_time = gen_timet();
2151 break;
2152 case RAW_SFILEINFO_SETATTRE:
2153 info->setattre.in.create_time = gen_timet();
2154 info->setattre.in.access_time = gen_timet();
2155 info->setattre.in.write_time = gen_timet();
2156 break;
2157 case RAW_SFILEINFO_STANDARD:
2158 info->standard.in.create_time = gen_timet();
2159 info->standard.in.access_time = gen_timet();
2160 info->standard.in.write_time = gen_timet();
2161 break;
2162 case RAW_SFILEINFO_EA_SET: {
2163 static struct ea_struct ea;
2164 info->ea_set.in.num_eas = 1;
2165 info->ea_set.in.eas = &ea;
2166 info->ea_set.in.eas[0] = gen_ea_struct();
2168 break;
2169 case RAW_SFILEINFO_BASIC_INFO:
2170 case RAW_SFILEINFO_BASIC_INFORMATION:
2171 info->basic_info.in.create_time = gen_nttime();
2172 info->basic_info.in.access_time = gen_nttime();
2173 info->basic_info.in.write_time = gen_nttime();
2174 info->basic_info.in.change_time = gen_nttime();
2175 info->basic_info.in.attrib = gen_attrib();
2176 break;
2177 case RAW_SFILEINFO_DISPOSITION_INFO:
2178 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2179 info->disposition_info.in.delete_on_close = gen_bool();
2180 break;
2181 case RAW_SFILEINFO_ALLOCATION_INFO:
2182 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2183 info->allocation_info.in.alloc_size = gen_alloc_size();
2184 break;
2185 case RAW_SFILEINFO_END_OF_FILE_INFO:
2186 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2187 info->end_of_file_info.in.size = gen_offset();
2188 break;
2189 case RAW_SFILEINFO_RENAME_INFORMATION:
2190 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2191 info->rename_information.in.overwrite = gen_bool();
2192 info->rename_information.in.root_fid = gen_root_fid(instance);
2193 info->rename_information.in.new_name = gen_fname_open(instance);
2194 break;
2195 case RAW_SFILEINFO_POSITION_INFORMATION:
2196 info->position_information.in.position = gen_offset();
2197 break;
2198 case RAW_SFILEINFO_MODE_INFORMATION:
2199 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2200 break;
2201 case RAW_SFILEINFO_FULL_EA_INFORMATION:
2202 info->full_ea_information.in.eas = gen_ea_list();
2203 break;
2204 case RAW_SFILEINFO_GENERIC:
2205 case RAW_SFILEINFO_SEC_DESC:
2206 case RAW_SFILEINFO_UNIX_BASIC:
2207 case RAW_SFILEINFO_UNIX_LINK:
2208 case RAW_SFILEINFO_UNIX_HLINK:
2209 case RAW_SFILEINFO_1023:
2210 case RAW_SFILEINFO_1025:
2211 case RAW_SFILEINFO_1029:
2212 case RAW_SFILEINFO_1032:
2213 case RAW_SFILEINFO_1039:
2214 case RAW_SFILEINFO_1040:
2215 case RAW_SFILEINFO_UNIX_INFO2:
2216 /* Untested */
2217 break;
2220 #endif
2223 generate a fileinfo query structure
2225 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2227 int i;
2228 #undef LVL
2229 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2230 struct levels {
2231 enum smb_setfileinfo_level level;
2232 const char *name;
2234 struct levels smb_levels[] = {
2235 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO),
2236 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO),
2237 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2238 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
2239 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
2240 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
2241 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION),
2242 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2243 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2245 struct levels smb2_levels[] = {
2246 LVL(BASIC_INFORMATION),
2247 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
2248 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
2249 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
2250 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION),
2251 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2252 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2254 struct levels *levels = options.smb2?smb2_levels:smb_levels;
2255 uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels);
2257 do {
2258 i = gen_int_range(0, num_levels-1);
2259 } while (ignore_pattern(levels[i].name));
2261 ZERO_STRUCTP(info);
2262 info->generic.level = levels[i].level;
2264 switch (info->generic.level) {
2265 case RAW_SFILEINFO_SETATTR:
2266 info->setattr.in.attrib = gen_attrib();
2267 info->setattr.in.write_time = gen_timet();
2268 break;
2269 case RAW_SFILEINFO_SETATTRE:
2270 info->setattre.in.create_time = gen_timet();
2271 info->setattre.in.access_time = gen_timet();
2272 info->setattre.in.write_time = gen_timet();
2273 break;
2274 case RAW_SFILEINFO_STANDARD:
2275 info->standard.in.create_time = gen_timet();
2276 info->standard.in.access_time = gen_timet();
2277 info->standard.in.write_time = gen_timet();
2278 break;
2279 case RAW_SFILEINFO_EA_SET: {
2280 static struct ea_struct ea;
2281 info->ea_set.in.num_eas = 1;
2282 info->ea_set.in.eas = &ea;
2283 info->ea_set.in.eas[0] = gen_ea_struct();
2284 break;
2286 case RAW_SFILEINFO_BASIC_INFO:
2287 case RAW_SFILEINFO_BASIC_INFORMATION:
2288 info->basic_info.in.create_time = gen_nttime();
2289 info->basic_info.in.access_time = gen_nttime();
2290 info->basic_info.in.write_time = gen_nttime();
2291 info->basic_info.in.change_time = gen_nttime();
2292 info->basic_info.in.attrib = gen_attrib();
2293 break;
2294 case RAW_SFILEINFO_DISPOSITION_INFO:
2295 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2296 info->disposition_info.in.delete_on_close = gen_bool();
2297 break;
2298 case RAW_SFILEINFO_ALLOCATION_INFO:
2299 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2300 info->allocation_info.in.alloc_size = gen_alloc_size();
2301 break;
2302 case RAW_SFILEINFO_END_OF_FILE_INFO:
2303 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2304 info->end_of_file_info.in.size = gen_offset();
2305 break;
2306 case RAW_SFILEINFO_RENAME_INFORMATION:
2307 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2308 info->rename_information.in.overwrite = gen_bool();
2309 info->rename_information.in.root_fid = gen_root_fid(instance);
2310 info->rename_information.in.new_name = gen_fname_open(instance);
2311 break;
2312 case RAW_SFILEINFO_POSITION_INFORMATION:
2313 info->position_information.in.position = gen_offset();
2314 break;
2315 case RAW_SFILEINFO_MODE_INFORMATION:
2316 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2317 break;
2318 case RAW_SFILEINFO_FULL_EA_INFORMATION:
2319 info->full_ea_information.in.eas = gen_ea_list();
2320 break;
2322 case RAW_SFILEINFO_GENERIC:
2323 case RAW_SFILEINFO_SEC_DESC:
2324 case RAW_SFILEINFO_1025:
2325 case RAW_SFILEINFO_1029:
2326 case RAW_SFILEINFO_1032:
2327 case RAW_SFILEINFO_UNIX_BASIC:
2328 case RAW_SFILEINFO_UNIX_INFO2:
2329 case RAW_SFILEINFO_UNIX_LINK:
2330 case RAW_SFILEINFO_UNIX_HLINK:
2331 case RAW_SFILEINFO_LINK_INFORMATION:
2332 case RAW_SFILEINFO_PIPE_INFORMATION:
2333 case RAW_SFILEINFO_VALID_DATA_INFORMATION:
2334 case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
2335 case RAW_SFILEINFO_1027:
2336 case RAW_SFILEINFO_1030:
2337 case RAW_SFILEINFO_1031:
2338 case RAW_SFILEINFO_1036:
2339 case RAW_SFILEINFO_1041:
2340 case RAW_SFILEINFO_1042:
2341 case RAW_SFILEINFO_1043:
2342 case RAW_SFILEINFO_1044:
2343 /* Untested */
2344 break;
2351 generate a fileinfo query structure
2353 static void gen_fileinfo_smb(int instance, union smb_fileinfo *info)
2355 int i;
2356 #undef LVL
2357 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2358 struct {
2359 enum smb_fileinfo_level level;
2360 const char *name;
2361 } levels[] = {
2362 LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD),
2363 LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID),
2364 LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO),
2365 LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO),
2366 LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION),
2367 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2368 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2369 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION),
2370 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2371 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION)
2373 do {
2374 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2375 } while (ignore_pattern(levels[i].name));
2377 info->generic.level = levels[i].level;
2381 generate qpathinfo operations
2383 static bool handler_smb_qpathinfo(int instance)
2385 union smb_fileinfo parm[NSERVERS];
2386 NTSTATUS status[NSERVERS];
2388 parm[0].generic.in.file.path = gen_fname_open(instance);
2390 gen_fileinfo_smb(instance, &parm[0]);
2392 GEN_COPY_PARM;
2393 GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i]));
2395 return cmp_fileinfo(instance, parm, status);
2399 generate qfileinfo operations
2401 static bool handler_smb_qfileinfo(int instance)
2403 union smb_fileinfo parm[NSERVERS];
2404 NTSTATUS status[NSERVERS];
2406 parm[0].generic.in.file.fnum = gen_fnum(instance);
2408 gen_fileinfo_smb(instance, &parm[0]);
2410 GEN_COPY_PARM;
2411 GEN_SET_FNUM_SMB(generic.in.file.fnum);
2412 GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i]));
2414 return cmp_fileinfo(instance, parm, status);
2419 generate setpathinfo operations
2421 static bool handler_smb_spathinfo(int instance)
2423 union smb_setfileinfo parm[NSERVERS];
2424 NTSTATUS status[NSERVERS];
2426 gen_setfileinfo(instance, &parm[0]);
2427 parm[0].generic.in.file.path = gen_fname_open(instance);
2429 GEN_COPY_PARM;
2431 /* a special case for the fid in a RENAME */
2432 if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION &&
2433 parm[0].rename_information.in.root_fid != 0) {
2434 GEN_SET_FNUM_SMB(rename_information.in.root_fid);
2437 GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i]));
2439 return true;
2444 generate setfileinfo operations
2446 static bool handler_smb_sfileinfo(int instance)
2448 union smb_setfileinfo parm[NSERVERS];
2449 NTSTATUS status[NSERVERS];
2451 parm[0].generic.in.file.fnum = gen_fnum(instance);
2453 gen_setfileinfo(instance, &parm[0]);
2455 GEN_COPY_PARM;
2456 GEN_SET_FNUM_SMB(generic.in.file.fnum);
2457 GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i]));
2459 return true;
2464 this is called when a change notify reply comes in
2466 static void async_notify_smb(struct smbcli_request *req)
2468 union smb_notify notify;
2469 NTSTATUS status;
2470 int i, j;
2471 uint16_t tid = 0;
2472 struct smbcli_transport *transport = req->transport;
2474 if (req->tree) {
2475 tid = req->tree->tid;
2478 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
2479 status = smb_raw_changenotify_recv(req, current_op.mem_ctx, &notify);
2480 if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) {
2481 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
2482 tid,
2483 notify.nttrans.out.num_changes,
2484 notify.nttrans.out.changes[0].action,
2485 notify.nttrans.out.changes[0].name.s);
2488 for (i=0;i<NSERVERS;i++) {
2489 for (j=0;j<NINSTANCES;j++) {
2490 if (transport == servers[i].smb_tree[j]->session->transport &&
2491 tid == servers[i].smb_tree[j]->tid) {
2492 notifies[i][j].notify_count++;
2493 notifies[i][j].status = status;
2494 notifies[i][j].notify = notify;
2501 generate change notify operations
2503 static bool handler_smb_notify(int instance)
2505 union smb_notify parm[NSERVERS];
2506 int n;
2508 ZERO_STRUCT(parm[0]);
2509 parm[0].nttrans.level = RAW_NOTIFY_NTTRANS;
2510 parm[0].nttrans.in.buffer_size = gen_io_count();
2511 parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF);
2512 parm[0].nttrans.in.file.fnum = gen_fnum(instance);
2513 parm[0].nttrans.in.recursive = gen_bool();
2515 GEN_COPY_PARM;
2516 GEN_SET_FNUM_SMB(nttrans.in.file.fnum);
2518 for (n=0;n<NSERVERS;n++) {
2519 struct smbcli_request *req;
2520 req = smb_raw_changenotify_send(servers[n].smb_tree[instance], &parm[n]);
2521 req->async.fn = async_notify_smb;
2524 return true;
2529 generate ntcreatex operations
2531 static bool handler_smb2_create(int instance)
2533 struct smb2_create parm[NSERVERS];
2534 NTSTATUS status[NSERVERS];
2536 ZERO_STRUCT(parm[0]);
2537 parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
2538 parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
2539 parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
2540 parm[0].in.create_flags = gen_reserved64();
2541 parm[0].in.reserved = gen_reserved64();
2542 parm[0].in.desired_access = gen_access_mask();
2543 parm[0].in.file_attributes = gen_attrib();
2544 parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
2545 parm[0].in.create_disposition = gen_open_disp();
2546 parm[0].in.create_options = gen_create_options();
2547 parm[0].in.fname = gen_fname_open(instance);
2548 parm[0].in.eas = gen_ea_list();
2549 parm[0].in.alloc_size = gen_alloc_size();
2550 parm[0].in.durable_open = gen_bool();
2551 parm[0].in.query_maximal_access = gen_bool();
2552 parm[0].in.timewarp = gen_timewarp();
2553 parm[0].in.query_on_disk_id = gen_bool();
2554 parm[0].in.sec_desc = gen_sec_desc();
2556 if (!options.use_oplocks) {
2557 /* mask out oplocks */
2558 parm[0].in.oplock_level = 0;
2561 if (options.valid) {
2562 parm[0].in.security_flags &= 3;
2563 parm[0].in.oplock_level &= 9;
2564 parm[0].in.impersonation_level &= 3;
2567 GEN_COPY_PARM;
2568 GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i]));
2570 CHECK_EQUAL(out.oplock_level);
2571 CHECK_EQUAL(out.reserved);
2572 CHECK_EQUAL(out.create_action);
2573 CHECK_NTTIMES_EQUAL(out.create_time);
2574 CHECK_NTTIMES_EQUAL(out.access_time);
2575 CHECK_NTTIMES_EQUAL(out.write_time);
2576 CHECK_NTTIMES_EQUAL(out.change_time);
2577 CHECK_EQUAL(out.alloc_size);
2578 CHECK_EQUAL(out.size);
2579 CHECK_ATTRIB(out.file_attr);
2580 CHECK_EQUAL(out.reserved2);
2581 CHECK_EQUAL(out.maximal_access);
2583 /* ntcreatex creates a new file handle */
2584 ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle);
2586 return true;
2590 generate close operations
2592 static bool handler_smb2_close(int instance)
2594 struct smb2_close parm[NSERVERS];
2595 NTSTATUS status[NSERVERS];
2597 ZERO_STRUCT(parm[0]);
2598 parm[0].in.file.handle.data[0] = gen_fnum_close(instance);
2599 parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF);
2601 GEN_COPY_PARM;
2602 GEN_SET_FNUM_SMB2(in.file.handle);
2603 GEN_CALL_SMB2(smb2_close(tree, &parm[i]));
2605 CHECK_EQUAL(out.flags);
2606 CHECK_EQUAL(out._pad);
2607 CHECK_NTTIMES_EQUAL(out.create_time);
2608 CHECK_NTTIMES_EQUAL(out.access_time);
2609 CHECK_NTTIMES_EQUAL(out.write_time);
2610 CHECK_NTTIMES_EQUAL(out.change_time);
2611 CHECK_EQUAL(out.alloc_size);
2612 CHECK_EQUAL(out.size);
2613 CHECK_ATTRIB(out.file_attr);
2615 REMOVE_HANDLE_SMB2(in.file.handle);
2617 return true;
2621 generate read operations
2623 static bool handler_smb2_read(int instance)
2625 struct smb2_read parm[NSERVERS];
2626 NTSTATUS status[NSERVERS];
2628 parm[0].in.file.handle.data[0] = gen_fnum(instance);
2629 parm[0].in.reserved = gen_reserved8();
2630 parm[0].in.length = gen_io_count();
2631 parm[0].in.offset = gen_offset();
2632 parm[0].in.min_count = gen_io_count();
2633 parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF);
2634 parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF);
2635 parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF);
2636 parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF);
2638 GEN_COPY_PARM;
2639 GEN_SET_FNUM_SMB2(in.file.handle);
2640 GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i]));
2642 CHECK_EQUAL(out.remaining);
2643 CHECK_EQUAL(out.reserved);
2644 CHECK_EQUAL(out.data.length);
2646 return true;
2650 generate write operations
2652 static bool handler_smb2_write(int instance)
2654 struct smb2_write parm[NSERVERS];
2655 NTSTATUS status[NSERVERS];
2657 parm[0].in.file.handle.data[0] = gen_fnum(instance);
2658 parm[0].in.offset = gen_offset();
2659 parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF);
2660 parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF);
2661 parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL,
2662 gen_io_count());
2664 GEN_COPY_PARM;
2665 GEN_SET_FNUM_SMB2(in.file.handle);
2666 GEN_CALL_SMB2(smb2_write(tree, &parm[i]));
2668 CHECK_EQUAL(out._pad);
2669 CHECK_EQUAL(out.nwritten);
2670 CHECK_EQUAL(out.unknown1);
2672 return true;
2676 generate lockingx operations
2678 static bool handler_smb2_lock(int instance)
2680 struct smb2_lock parm[NSERVERS];
2681 NTSTATUS status[NSERVERS];
2682 int n;
2684 parm[0].level = RAW_LOCK_LOCKX;
2685 parm[0].in.file.handle.data[0] = gen_fnum(instance);
2686 parm[0].in.lock_count = gen_lock_count();
2687 parm[0].in.lock_sequence = gen_reserved32();
2689 parm[0].in.locks = talloc_array(current_op.mem_ctx,
2690 struct smb2_lock_element,
2691 parm[0].in.lock_count);
2692 for (n=0;n<parm[0].in.lock_count;n++) {
2693 parm[0].in.locks[n].offset = gen_offset();
2694 parm[0].in.locks[n].length = gen_io_count();
2695 /* don't yet cope with async replies */
2696 parm[0].in.locks[n].flags = gen_lock_flags_smb2() |
2697 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2698 parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF);
2701 GEN_COPY_PARM;
2702 GEN_SET_FNUM_SMB2(in.file.handle);
2703 GEN_CALL_SMB2(smb2_lock(tree, &parm[i]));
2705 return true;
2709 generate flush operations
2711 static bool handler_smb2_flush(int instance)
2713 struct smb2_flush parm[NSERVERS];
2714 NTSTATUS status[NSERVERS];
2716 ZERO_STRUCT(parm[0]);
2717 parm[0].in.file.handle.data[0] = gen_fnum(instance);
2718 parm[0].in.reserved1 = gen_reserved16();
2719 parm[0].in.reserved2 = gen_reserved32();
2721 GEN_COPY_PARM;
2722 GEN_SET_FNUM_SMB2(in.file.handle);
2723 GEN_CALL_SMB2(smb2_flush(tree, &parm[i]));
2725 CHECK_EQUAL(out.reserved);
2727 return true;
2731 generate echo operations
2733 static bool handler_smb2_echo(int instance)
2735 NTSTATUS status[NSERVERS];
2737 GEN_CALL_SMB2(smb2_keepalive(tree->session->transport));
2739 return true;
2745 generate a fileinfo query structure
2747 static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info)
2749 int i;
2750 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2751 struct {
2752 enum smb_fileinfo_level level;
2753 const char *name;
2754 } levels[] = {
2755 LVL(BASIC_INFORMATION),
2756 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2757 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2758 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION),
2759 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2760 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION),
2761 LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC),
2763 do {
2764 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2765 } while (ignore_pattern(levels[i].name));
2767 info->generic.level = levels[i].level;
2771 generate qfileinfo operations
2773 static bool handler_smb2_qfileinfo(int instance)
2775 union smb_fileinfo parm[NSERVERS];
2776 NTSTATUS status[NSERVERS];
2778 parm[0].generic.in.file.handle.data[0] = gen_fnum(instance);
2780 gen_fileinfo_smb2(instance, &parm[0]);
2782 GEN_COPY_PARM;
2783 GEN_SET_FNUM_SMB2(generic.in.file.handle);
2784 GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i]));
2786 return cmp_fileinfo(instance, parm, status);
2791 generate setfileinfo operations
2793 static bool handler_smb2_sfileinfo(int instance)
2795 union smb_setfileinfo parm[NSERVERS];
2796 NTSTATUS status[NSERVERS];
2798 gen_setfileinfo(instance, &parm[0]);
2799 parm[0].generic.in.file.fnum = gen_fnum(instance);
2801 GEN_COPY_PARM;
2802 GEN_SET_FNUM_SMB2(generic.in.file.handle);
2803 GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i]));
2805 return true;
2809 wipe any relevant files
2811 static void wipe_files(void)
2813 int i;
2814 NTSTATUS status;
2816 if (options.skip_cleanup) {
2817 return;
2820 for (i=0;i<NSERVERS;i++) {
2821 int n;
2822 if (options.smb2) {
2823 n = smb2_deltree(servers[i].smb2_tree[0], "gentest");
2824 } else {
2825 n = smbcli_deltree(servers[i].smb_tree[0], "gentest");
2827 if (n == -1) {
2828 printf("Failed to wipe tree on server %d\n", i);
2829 exit(1);
2831 if (options.smb2) {
2832 status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest");
2833 } else {
2834 status = smbcli_mkdir(servers[i].smb_tree[0], "gentest");
2836 if (NT_STATUS_IS_ERR(status)) {
2837 printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status));
2838 exit(1);
2840 if (n > 0) {
2841 printf("Deleted %d files on server %d\n", n, i);
2847 dump the current seeds - useful for continuing a backtrack
2849 static void dump_seeds(void)
2851 int i;
2852 FILE *f;
2854 if (!options.seeds_file) {
2855 return;
2857 f = fopen("seeds.tmp", "w");
2858 if (!f) return;
2860 for (i=0;i<options.numops;i++) {
2861 fprintf(f, "%u\n", op_parms[i].seed);
2863 fclose(f);
2864 rename("seeds.tmp", options.seeds_file);
2870 the list of top-level operations that we will generate
2872 static struct {
2873 const char *name;
2874 bool (*handler)(int instance);
2875 bool smb2;
2876 int count, success_count;
2877 } gen_ops[] = {
2878 {"CREATE", handler_smb2_create, true},
2879 {"CLOSE", handler_smb2_close, true},
2880 {"READ", handler_smb2_read, true},
2881 {"WRITE", handler_smb2_write, true},
2882 {"LOCK", handler_smb2_lock, true},
2883 {"FLUSH", handler_smb2_flush, true},
2884 {"ECHO", handler_smb2_echo, true},
2885 {"QFILEINFO", handler_smb2_qfileinfo, true},
2886 {"SFILEINFO", handler_smb2_sfileinfo, true},
2888 {"OPEN", handler_smb_open, false},
2889 {"OPENX", handler_smb_openx, false},
2890 {"NTCREATEX", handler_smb_ntcreatex, false},
2891 {"CLOSE", handler_smb_close, false},
2892 {"UNLINK", handler_smb_unlink, false},
2893 {"MKDIR", handler_smb_mkdir, false},
2894 {"RMDIR", handler_smb_rmdir, false},
2895 {"RENAME", handler_smb_rename, false},
2896 {"NTRENAME", handler_smb_ntrename, false},
2897 {"READX", handler_smb_readx, false},
2898 {"WRITEX", handler_smb_writex, false},
2899 {"CHKPATH", handler_smb_chkpath, false},
2900 {"SEEK", handler_smb_seek, false},
2901 {"LOCKINGX", handler_smb_lockingx, false},
2902 {"QPATHINFO", handler_smb_qpathinfo, false},
2903 {"QFILEINFO", handler_smb_qfileinfo, false},
2904 {"SPATHINFO", handler_smb_spathinfo, false},
2905 {"SFILEINFO", handler_smb_sfileinfo, false},
2906 {"NOTIFY", handler_smb_notify, false},
2907 {"SEEK", handler_smb_seek, false},
2912 run the test with the current set of op_parms parameters
2913 return the number of operations that completed successfully
2915 static int run_test(struct tevent_context *ev, struct loadparm_context *lp_ctx)
2917 int op, i;
2919 if (!connect_servers(ev, lp_ctx)) {
2920 printf("Failed to connect to servers\n");
2921 exit(1);
2924 dump_seeds();
2926 /* wipe any leftover files from old runs */
2927 wipe_files();
2929 /* reset the open handles array */
2930 memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
2931 num_open_handles = 0;
2933 for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
2934 gen_ops[i].count = 0;
2935 gen_ops[i].success_count = 0;
2938 for (op=0; op<options.numops; op++) {
2939 int instance, which_op;
2940 bool ret;
2942 if (op_parms[op].disabled) continue;
2944 srandom(op_parms[op].seed);
2946 instance = gen_int_range(0, NINSTANCES-1);
2948 /* generate a non-ignored operation */
2949 do {
2950 which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
2951 } while (ignore_pattern(gen_ops[which_op].name) ||
2952 gen_ops[which_op].smb2 != options.smb2);
2954 DEBUG(3,("Generating op %s on instance %d\n",
2955 gen_ops[which_op].name, instance));
2957 current_op.seed = op_parms[op].seed;
2958 current_op.opnum = op;
2959 current_op.name = gen_ops[which_op].name;
2960 current_op.status = NT_STATUS_OK;
2961 talloc_free(current_op.mem_ctx);
2962 current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name);
2964 ret = gen_ops[which_op].handler(instance);
2966 gen_ops[which_op].count++;
2967 if (NT_STATUS_IS_OK(current_op.status)) {
2968 gen_ops[which_op].success_count++;
2971 if (!ret) {
2972 printf("Failed at operation %d - %s\n",
2973 op, gen_ops[which_op].name);
2974 return op;
2977 if (op % 100 == 0) {
2978 printf("%d\n", op);
2982 for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
2983 printf("Op %-10s got %d/%d success\n",
2984 gen_ops[i].name,
2985 gen_ops[i].success_count,
2986 gen_ops[i].count);
2989 return op;
2993 perform a backtracking analysis of the minimal set of operations
2994 to generate an error
2996 static void backtrack_analyze(struct tevent_context *ev,
2997 struct loadparm_context *lp_ctx)
2999 int chunk, ret;
3000 const char *mismatch = current_op.mismatch;
3002 chunk = options.numops / 2;
3004 do {
3005 int base;
3006 for (base=0;
3007 chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
3008 int i, max;
3010 chunk = MIN(chunk, options.numops / 2);
3012 /* mark this range as disabled */
3013 max = MIN(options.numops, base+chunk);
3014 for (i=base;i<max; i++) {
3015 op_parms[i].disabled = true;
3017 printf("Testing %d ops with %d-%d disabled\n",
3018 options.numops, base, max-1);
3019 ret = run_test(ev, lp_ctx);
3020 printf("Completed %d of %d ops\n", ret, options.numops);
3021 for (i=base;i<max; i++) {
3022 op_parms[i].disabled = false;
3024 if (ret == options.numops) {
3025 /* this chunk is needed */
3026 base += chunk;
3027 } else if (mismatch != current_op.mismatch &&
3028 strcmp(mismatch, current_op.mismatch)) {
3029 base += chunk;
3030 printf("Different error in backtracking\n");
3031 } else if (ret < base) {
3032 printf("damn - inconsistent errors! found early error\n");
3033 options.numops = ret+1;
3034 base = 0;
3035 } else {
3036 /* it failed - this chunk isn't needed for a failure */
3037 memmove(&op_parms[base], &op_parms[max],
3038 sizeof(op_parms[0]) * (options.numops - max));
3039 options.numops = (ret+1) - (max - base);
3043 if (chunk == 2) {
3044 chunk = 1;
3045 } else {
3046 chunk *= 0.4;
3049 if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
3050 chunk = 1;
3052 } while (chunk > 0);
3054 printf("Reduced to %d ops\n", options.numops);
3055 ret = run_test(ev, lp_ctx);
3056 if (ret != options.numops - 1) {
3057 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
3062 start the main gentest process
3064 static bool start_gentest(struct tevent_context *ev,
3065 struct loadparm_context *lp_ctx)
3067 int op;
3068 int ret;
3070 /* allocate the open_handles array */
3071 open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
3072 if (open_handles == NULL) {
3073 printf("Unable to allocate memory for open_handles array.\n");
3074 exit(1);
3077 srandom(options.seed);
3078 op_parms = calloc(options.numops, sizeof(op_parms[0]));
3079 if (op_parms == NULL) {
3080 printf("Unable to allocate memory for op_parms.\n");
3081 exit(1);
3084 /* generate the seeds - after this everything is deterministic */
3085 if (options.use_preset_seeds) {
3086 int numops;
3087 char **preset = file_lines_load(options.seeds_file, &numops, 0, NULL);
3088 if (!preset) {
3089 printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
3090 exit(1);
3092 if (numops < options.numops) {
3093 options.numops = numops;
3095 for (op=0;op<options.numops;op++) {
3096 if (!preset[op]) {
3097 printf("Not enough seeds in %s\n", options.seeds_file);
3098 exit(1);
3100 op_parms[op].seed = atoi(preset[op]);
3102 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
3103 } else {
3104 for (op=0; op<options.numops; op++) {
3105 op_parms[op].seed = random();
3109 ret = run_test(ev, lp_ctx);
3111 if (ret != options.numops && options.analyze) {
3112 options.numops = ret+1;
3113 backtrack_analyze(ev, lp_ctx);
3114 } else if (options.analyze_always) {
3115 backtrack_analyze(ev, lp_ctx);
3116 } else if (options.analyze_continuous) {
3117 while (run_test(ev, lp_ctx) == options.numops) ;
3120 return ret == options.numops;
3124 static void usage(poptContext pc)
3126 printf(
3127 "Usage:\n\
3128 gentest //server1/share1 //server2/share2 [options..]\n\
3130 poptPrintUsage(pc, stdout, 0);
3134 split a UNC name into server and share names
3136 static bool split_unc_name(const char *unc, char **server, char **share)
3138 char *p = strdup(unc);
3139 if (!p) return false;
3140 all_string_sub(p, "\\", "/", 0);
3141 if (strncmp(p, "//", 2) != 0) return false;
3143 (*server) = p+2;
3144 p = strchr(*server, '/');
3145 if (!p) return false;
3147 *p = 0;
3148 (*share) = p+1;
3150 return true;
3155 /****************************************************************************
3156 main program
3157 ****************************************************************************/
3158 int main(int argc, char *argv[])
3160 int opt;
3161 int i, username_count=0;
3162 bool ret;
3163 char *ignore_file=NULL;
3164 struct tevent_context *ev;
3165 struct loadparm_context *lp_ctx;
3166 poptContext pc;
3167 int argc_new;
3168 char **argv_new;
3169 enum {OPT_UNCLIST=1000};
3170 struct poptOption long_options[] = {
3171 POPT_AUTOHELP
3172 {"smb2", 0, POPT_ARG_NONE, &options.smb2, 0, "use SMB2 protocol", NULL},
3173 {"seed", 0, POPT_ARG_INT, &options.seed, 0, "Seed to use for randomizer", NULL},
3174 {"num-ops", 0, POPT_ARG_INT, &options.numops, 0, "num ops", NULL},
3175 {"oplocks", 0, POPT_ARG_NONE, &options.use_oplocks,0, "use oplocks", NULL},
3176 {"showall", 0, POPT_ARG_NONE, &options.showall, 0, "display all operations", NULL},
3177 {"analyse", 0, POPT_ARG_NONE, &options.analyze, 0, "do backtrack analysis", NULL},
3178 {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always, 0, "analysis always", NULL},
3179 {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous, 0, "analysis continuous", NULL},
3180 {"ignore", 0, POPT_ARG_STRING, &ignore_file, 0, "ignore from file", NULL},
3181 {"preset", 0, POPT_ARG_NONE, &options.use_preset_seeds, 0, "use preset seeds", NULL},
3182 {"fast", 0, POPT_ARG_NONE, &options.fast_reconnect, 0, "use fast reconnect", NULL},
3183 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
3184 {"seedsfile", 0, POPT_ARG_STRING, &options.seeds_file, 0, "seed file", NULL},
3185 { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3186 {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL},
3187 {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL},
3188 {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL},
3189 {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL},
3190 {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL},
3191 POPT_COMMON_SAMBA
3192 POPT_COMMON_CONNECTION
3193 POPT_COMMON_CREDENTIALS
3194 POPT_COMMON_VERSION
3195 { NULL }
3198 memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle));
3200 setlinebuf(stdout);
3201 options.seed = time(NULL);
3202 options.numops = 1000;
3203 options.max_open_handles = 20;
3204 options.seeds_file = "gentest_seeds.dat";
3206 pc = poptGetContext("gentest", argc, (const char **) argv, long_options,
3207 POPT_CONTEXT_KEEP_FIRST);
3209 poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
3211 lp_ctx = cmdline_lp_ctx;
3212 servers[0].credentials = cli_credentials_init(talloc_autofree_context());
3213 servers[1].credentials = cli_credentials_init(talloc_autofree_context());
3214 cli_credentials_guess(servers[0].credentials, lp_ctx);
3215 cli_credentials_guess(servers[1].credentials, lp_ctx);
3217 while((opt = poptGetNextOpt(pc)) != -1) {
3218 switch (opt) {
3219 case OPT_UNCLIST:
3220 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
3221 break;
3222 case 'U':
3223 if (username_count == 2) {
3224 usage(pc);
3225 exit(1);
3227 cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED);
3228 username_count++;
3229 break;
3233 if (ignore_file) {
3234 options.ignore_patterns = file_lines_load(ignore_file, NULL, 0, NULL);
3237 argv_new = discard_const_p(char *, poptGetArgs(pc));
3238 argc_new = argc;
3239 for (i=0; i<argc; i++) {
3240 if (argv_new[i] == NULL) {
3241 argc_new = i;
3242 break;
3246 if (!(argc_new >= 3)) {
3247 usage(pc);
3248 exit(1);
3251 setlinebuf(stdout);
3253 setup_logging("gentest", DEBUG_STDOUT);
3255 if (argc < 3 || argv[1][0] == '-') {
3256 usage(pc);
3257 exit(1);
3260 setup_logging(argv[0], DEBUG_STDOUT);
3262 for (i=0;i<NSERVERS;i++) {
3263 const char *share = argv[1+i];
3264 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
3265 printf("Invalid share name '%s'\n", share);
3266 return -1;
3270 if (username_count == 0) {
3271 usage(pc);
3272 return -1;
3274 if (username_count == 1) {
3275 servers[1].credentials = servers[0].credentials;
3278 printf("seed=%u\n", options.seed);
3280 ev = s4_event_context_init(talloc_autofree_context());
3282 gensec_init();
3284 ret = start_gentest(ev, lp_ctx);
3286 if (ret) {
3287 printf("gentest completed - no errors\n");
3288 } else {
3289 printf("gentest failed\n");
3292 return ret?0:-1;