/* Unix SMB/CIFS implementation. randomised byte range lock tester Copyright (C) Andrew Tridgell 1999 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" static fstring password[2]; static fstring username[2]; static int got_user; static int got_pass; static BOOL use_kerberos; static int numops = 1000; static BOOL showall; static BOOL analyze; static BOOL hide_unlock_fails; static BOOL use_oplocks; static uint_t lock_range = 100; static uint_t lock_base = 0; static uint_t min_length = 0; static BOOL exact_error_codes; static BOOL zero_zero; #define FILENAME "\\locktest.dat" #define READ_PCT 50 #define LOCK_PCT 45 #define UNLOCK_PCT 70 #define RANGE_MULTIPLE 1 #define NSERVERS 2 #define NCONNECTIONS 2 #define NFILES 2 #define LOCK_TIMEOUT 0 #define NASTY_POSIX_LOCK_HACK 0 enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN}; struct record { enum lock_op lock_op; enum brl_type lock_type; char conn, f; uint64_t start, len; char needed; }; #define PRESETS 0 #if PRESETS static struct record preset[] = { {OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1}, {OP_UNLOCK, 0 , 0, 0, 2, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1}, {OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1}, {OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1}, {OP_REOPEN, 0, 0, 0, 0, 0, 1}, }; #endif static struct record *recorded; /***************************************************** return a connection to a server *******************************************************/ static struct cli_state *connect_one(char *share, int snum) { struct cli_state *c; fstring server, myname; uint_t flags = 0; NTSTATUS status; fstrcpy(server,share+2); share = strchr_m(server,'\\'); if (!share) return NULL; *share = 0; share++; slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), snum); if (use_kerberos) flags |= CLI_FULL_CONNECTION_USE_KERBEROS; status = cli_full_connection(&c, myname, server, NULL, share, "?????", username[snum], lp_workgroup(), password[snum], flags, NULL); if (!NT_STATUS_IS_OK(status)) { return NULL; } return c; } static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES], char *share[NSERVERS]) { int server, conn, f; for (server=0;servertree, fnum[server][conn][f]); fnum[server][conn][f] = -1; } } cli_shutdown(cli[server][conn]); } cli[server][conn] = connect_one(share[server], server); if (!cli[server][conn]) { DEBUG(0,("Failed to connect to %s\n", share[server])); exit(1); } } } static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES], struct record *rec) { uint_t conn = rec->conn; uint_t f = rec->f; uint64_t start = rec->start; uint64_t len = rec->len; enum brl_type op = rec->lock_type; int server; BOOL ret[NSERVERS]; NTSTATUS status[NSERVERS]; switch (rec->lock_op) { case OP_LOCK: /* set a lock */ for (server=0;servertree, fnum[server][conn][f], start, len, LOCK_TIMEOUT, op)); status[server] = cli_nt_error(cli[server][conn]->tree); if (!exact_error_codes && NT_STATUS_EQUAL(status[server], NT_STATUS_FILE_LOCK_CONFLICT)) { status[server] = NT_STATUS_LOCK_NOT_GRANTED; } } if (showall || !NT_STATUS_EQUAL(status[0],status[1])) { printf("lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n", conn, f, (double)start, (double)len, op==READ_LOCK?"READ_LOCK":"WRITE_LOCK", nt_errstr(status[0]), nt_errstr(status[1])); } if (!NT_STATUS_EQUAL(status[0],status[1])) return False; break; case OP_UNLOCK: /* unset a lock */ for (server=0;servertree, fnum[server][conn][f], start, len)); status[server] = cli_nt_error(cli[server][conn]->tree); } if (showall || (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) { printf("unlock conn=%u f=%u range=%.0f(%.0f) -> %s:%s\n", conn, f, (double)start, (double)len, nt_errstr(status[0]), nt_errstr(status[1])); } if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1])) return False; break; case OP_REOPEN: /* reopen the file */ for (server=0;servertree, fnum[server][conn][f]); fnum[server][conn][f] = -1; } for (server=0;servertree, FILENAME, O_RDWR|O_CREAT, DENY_NONE); if (fnum[server][conn][f] == -1) { printf("failed to reopen on share%d\n", server); return False; } } if (showall) { printf("reopen conn=%u f=%u\n", conn, f); } break; } return True; } static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES]) { int server, conn, f; for (server=0;servertree, fnum[server][conn][f]); fnum[server][conn][f] = -1; } } for (server=0;servertree, FILENAME); } } static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES]) { int server, conn, f; for (server=0;servertree, FILENAME, O_RDWR|O_CREAT, DENY_NONE); if (fnum[server][conn][f] == -1) { fprintf(stderr,"Failed to open fnum[%u][%u][%u]\n", server, conn, f); exit(1); } } } static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES], int n) { int i; printf("testing %u ...\n", n); for (i=0; i 1) { skip = skip/2; printf("skip=%d\n", skip); continue; } if (n1 == n) break; } close_files(cli, fnum); reconnect(cli, fnum, share); open_files(cli, fnum); showall = True; n1 = retest(cli, fnum, n); if (n1 != n-1) { printf("ERROR - inconsistent result (%u %u)\n", n1, n); } close_files(cli, fnum); for (i=0;i