diff options
Diffstat (limited to 'source4/torture/raw/lock.c')
-rw-r--r-- | source4/torture/raw/lock.c | 1336 |
1 files changed, 1336 insertions, 0 deletions
diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c new file mode 100644 index 0000000000..cd8d606795 --- /dev/null +++ b/source4/torture/raw/lock.c @@ -0,0 +1,1336 @@ +/* + Unix SMB/CIFS implementation. + test suite for various lock operations + Copyright (C) Andrew Tridgell 2003 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "torture/torture.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "system/time.h" +#include "system/filesys.h" +#include "libcli/libcli.h" +#include "torture/util.h" +#include "libcli/composite/composite.h" +#include "libcli/smb_composite/smb_composite.h" +#include "lib/cmdline/popt_common.h" +#include "param/param.h" + +#define CHECK_STATUS(status, correct) do { \ + if (!NT_STATUS_EQUAL(status, correct)) { \ + printf("(%s) Incorrect status %s - should be %s\n", \ + __location__, nt_errstr(status), nt_errstr(correct)); \ + ret = false; \ + goto done; \ + }} while (0) + +#define BASEDIR "\\testlock" + + +/* + test SMBlock and SMBunlock ops +*/ +static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli) +{ + union smb_lock io; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\test.txt"; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing RAW_LOCK_LOCK\n"); + io.generic.level = RAW_LOCK_LOCK; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + printf("Trying 0/0 lock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 0; + io.lock.in.offset = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid--; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + printf("Trying 0/1 lock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 1; + io.lock.in.offset = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + cli->session->pid--; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying 0xEEFFFFFF lock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 4000; + io.lock.in.offset = 0xEEFFFFFF; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + cli->session->pid--; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying 0xEF000000 lock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 4000; + io.lock.in.offset = 0xEEFFFFFF; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + cli->session->pid--; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying max lock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 4000; + io.lock.in.offset = 0xEF000000; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + cli->session->pid--; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying wrong pid unlock\n"); + io.lock.level = RAW_LOCK_LOCK; + io.lock.in.file.fnum = fnum; + io.lock.in.count = 4002; + io.lock.in.offset = 10001; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + cli->session->pid++; + io.lock.level = RAW_LOCK_UNLOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + cli->session->pid--; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + +done: + smbcli_close(cli->tree, fnum); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + test locking&X ops +*/ +static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\test.txt"; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing RAW_LOCK_LOCKX\n"); + io.generic.level = RAW_LOCK_LOCKX; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 10; + lock[0].count = 1; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + + printf("Trying 0xEEFFFFFF lock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 4000; + lock[0].offset = 0xEEFFFFFF; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying 0xEF000000 lock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 4000; + lock[0].offset = 0xEF000000; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying zero lock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 0; + lock[0].offset = ~0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying max lock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 0; + lock[0].offset = ~0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying 2^63\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 1; + lock[0].offset = 1; + lock[0].offset <<= 63; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying 2^63 - 1\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 1; + lock[0].offset = 1; + lock[0].offset <<= 63; + lock[0].offset--; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + printf("Trying max lock 2\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].count = 1; + lock[0].offset = ~0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid++; + lock[0].count = 2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + lock[0].pid--; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + lock[0].count = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + +done: + smbcli_close(cli->tree, fnum); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + test high pid +*/ +static bool test_pidhigh(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\test.txt"; + uint8_t c = 1; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing high pid\n"); + io.generic.level = RAW_LOCK_LOCKX; + + cli->session->pid = 1; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) { + printf("Failed to write 1 byte - %s\n", smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 0; + lock[0].count = 0xFFFFFFFF; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) { + printf("Failed to read 1 byte - %s\n", smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + cli->session->pid |= 0x10000; + + cli->session->pid = 2; + + if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) { + printf("pid is incorrect handled for read with lock!\n"); + ret = false; + goto done; + } + + cli->session->pid = 0x10001; + + if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) { + printf("High pid is used on this server!\n"); + ret = false; + } else { + printf("High pid is not used on this server (correct)\n"); + } + +done: + smbcli_close(cli->tree, fnum); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + test locking&X async operation +*/ +static bool test_async(struct torture_context *tctx, + struct smbcli_state *cli) +{ + struct smbcli_session *session; + struct smb_composite_sesssetup setup; + struct smbcli_tree *tree; + union smb_tcon tcon; + const char *host, *share; + union smb_lock io; + struct smb_lock_entry lock[2]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\test.txt"; + time_t t; + struct smbcli_request *req; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing LOCKING_ANDX_CANCEL_LOCK\n"); + io.generic.level = RAW_LOCK_LOCKX; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + t = time(NULL); + + printf("testing cancel by CANCEL_LOCK\n"); + + /* setup a timed lock */ + io.lockx.in.timeout = 10000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + /* cancel the wrong range */ + lock[0].offset = 0; + io.lockx.in.timeout = 0; + io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation)); + + /* cancel with the wrong bits set */ + lock[0].offset = 100; + io.lockx.in.timeout = 0; + io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation)); + + /* cancel the right range */ + lock[0].offset = 100; + io.lockx.in.timeout = 0; + io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* receive the failed lock request */ + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + if (time(NULL) > t+2) { + printf("lock cancel was not immediate (%s)\n", __location__); + ret = false; + goto done; + } + + printf("testing cancel by unlock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.timeout = 5000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + t = time(NULL); + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + if (time(NULL) > t+2) { + printf("lock cancel by unlock was not immediate (%s) - took %d secs\n", + __location__, (int)(time(NULL)-t)); + ret = false; + goto done; + } + + printf("testing cancel by close\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + t = time(NULL); + io.lockx.in.timeout = 10000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + status = smbcli_close(cli->tree, fnum); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + if (time(NULL) > t+2) { + printf("lock cancel by close was not immediate (%s)\n", __location__); + ret = false; + goto done; + } + + printf("create a new sessions\n"); + session = smbcli_session_init(cli->transport, tctx, false); + setup.in.sesskey = cli->transport->negotiate.sesskey; + setup.in.capabilities = cli->transport->negotiate.capabilities; + setup.in.workgroup = lp_workgroup(tctx->lp_ctx); + setup.in.credentials = cmdline_credentials; + status = smb_composite_sesssetup(session, &setup); + CHECK_STATUS(status, NT_STATUS_OK); + session->vuid = setup.out.vuid; + + printf("create new tree context\n"); + share = torture_setting_string(tctx, "share", NULL); + host = torture_setting_string(tctx, "host", NULL); + tree = smbcli_tree_init(session, tctx, false); + tcon.generic.level = RAW_TCON_TCONX; + tcon.tconx.in.flags = 0; + tcon.tconx.in.password = data_blob(NULL, 0); + tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); + tcon.tconx.in.device = "A:"; + status = smb_raw_tcon(tree, tctx, &tcon); + CHECK_STATUS(status, NT_STATUS_OK); + tree->tid = tcon.tconx.out.tid; + + printf("testing cancel by exit\n"); + fname = BASEDIR "\\test_exit.txt"; + fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + io.lockx.in.timeout = 10000; + t = time(NULL); + req = smb_raw_lock_send(tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + status = smb_raw_exit(session); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + if (time(NULL) > t+2) { + printf("lock cancel by exit was not immediate (%s)\n", __location__); + ret = false; + goto done; + } + + printf("testing cancel by ulogoff\n"); + fname = BASEDIR "\\test_ulogoff.txt"; + fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + io.lockx.in.timeout = 10000; + t = time(NULL); + req = smb_raw_lock_send(tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + status = smb_raw_ulogoff(session); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smbcli_request_simple_recv(req); + if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) { + printf("lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n", + nt_errstr(status)); + smb_tree_disconnect(tree); + smb_raw_exit(session); + goto done; + } + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + if (time(NULL) > t+2) { + printf("lock cancel by ulogoff was not immediate (%s)\n", __location__); + ret = false; + goto done; + } + + printf("testing cancel by tdis\n"); + tree->session = cli->session; + + fname = BASEDIR "\\test_tdis.txt"; + fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb_raw_lock(tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + io.lockx.in.timeout = 10000; + t = time(NULL); + req = smb_raw_lock_send(tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + status = smb_tree_disconnect(tree); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + if (time(NULL) > t+2) { + printf("lock cancel by tdis was not immediate (%s)\n", __location__); + ret = false; + goto done; + } + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + +/* + test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT +*/ +static bool test_errorcode(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + union smb_open op; + struct smb_lock_entry lock[2]; + NTSTATUS status; + bool ret = true; + int fnum, fnum2; + const char *fname; + struct smbcli_request *req; + time_t start; + int t; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n"); + + printf("testing with timeout = 0\n"); + fname = BASEDIR "\\test0.txt"; + t = 0; + + /* + * the first run is with t = 0, + * the second with t > 0 (=1) + */ +next_run: + /* + * use the DENY_DOS mode, that creates two fnum's of one low-level file handle, + * this demonstrates that the cache is per fnum + */ + op.openx.level = RAW_OPEN_OPENX; + op.openx.in.fname = fname; + op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO; + op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS; + op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE; + op.openx.in.search_attrs = 0; + op.openx.in.file_attrs = 0; + op.openx.in.write_time = 0; + op.openx.in.size = 0; + op.openx.in.timeout = 0; + + status = smb_raw_open(cli->tree, tctx, &op); + CHECK_STATUS(status, NT_STATUS_OK); + fnum = op.openx.out.file.fnum; + + status = smb_raw_open(cli->tree, tctx, &op); + CHECK_STATUS(status, NT_STATUS_OK); + fnum2 = op.openx.out.file.fnum; + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = t; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED + * this also demonstrates that the error code cache is per file handle + * (LOCK_NOT_GRANTED is only be used when timeout is 0!) + */ + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + + /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */ + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* demonstrate that the smbpid doesn't matter */ + lock[0].pid++; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + lock[0].pid--; + + /* + * demonstrate the a successful lock with count = 0 and the same offset, + * doesn't reset the error cache + */ + lock[0].offset = 100; + lock[0].count = 0; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * demonstrate the a successful lock with count = 0 and outside the locked range, + * doesn't reset the error cache + */ + lock[0].offset = 110; + lock[0].count = 0; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 99; + lock[0].count = 0; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* demonstrate that a changing count doesn't reset the error cache */ + lock[0].offset = 100; + lock[0].count = 5; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 100; + lock[0].count = 15; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * demonstrate the a lock with count = 0 and inside the locked range, + * fails and resets the error cache + */ + lock[0].offset = 101; + lock[0].count = 0; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* demonstrate the a changing offset, resets the error cache */ + lock[0].offset = 105; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 95; + lock[0].count = 9; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * demonstrate the a successful lock in a different range, + * doesn't reset the cache, the failing lock on the 2nd handle + * resets the resets the cache + */ + lock[0].offset = 120; + lock[0].count = 15; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.file.fnum = fnum; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.file.fnum = fnum2; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED)); + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* end of the loop */ + if (t == 0) { + smb_raw_exit(cli->session); + printf("testing with timeout > 0 (=1)\n"); + fname = BASEDIR "\\test1.txt"; + t = 1; + goto next_run; + } + + /* + * the following 3 test sections demonstrate that + * the cache is only set when the error is reported + * to the client (after the timeout went by) + */ + smb_raw_exit(cli->session); + printf("testing a conflict while a lock is pending\n"); + fname = BASEDIR "\\test2.txt"; + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + start = time(NULL); + io.lockx.in.timeout = 1000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + io.lockx.in.timeout = 0; + lock[0].offset = 105; + lock[0].count = 10; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + if (time(NULL) < start+1) { + printf("lock comes back to early (%s)\n", __location__); + ret = false; + goto done; + } + + smbcli_close(cli->tree, fnum); + fname = BASEDIR "\\test3.txt"; + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + start = time(NULL); + io.lockx.in.timeout = 1000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + io.lockx.in.timeout = 0; + lock[0].offset = 105; + lock[0].count = 10; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + lock[0].offset = 100; + lock[0].count = 10; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + if (time(NULL) < start+1) { + printf("lock comes back to early (%s)\n", __location__); + ret = false; + goto done; + } + + smbcli_close(cli->tree, fnum); + fname = BASEDIR "\\test4.txt"; + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + start = time(NULL); + io.lockx.in.timeout = 1000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = false; + goto done; + } + + io.lockx.in.timeout = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + if (time(NULL) < start+1) { + printf("lock comes back to early (%s)\n", __location__); + ret = false; + goto done; + } + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + test LOCKING_ANDX_CHANGE_LOCKTYPE +*/ +static bool test_changetype(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + NTSTATUS status; + bool ret = true; + int fnum; + uint8_t c = 0; + const char *fname = BASEDIR "\\test.txt"; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + printf("Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n"); + io.generic.level = RAW_LOCK_LOCKX; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = false; + goto done; + } + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { + printf("allowed write on read locked region (%s)\n", __location__); + ret = false; + goto done; + } + + /* windows server don't seem to support this */ + io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks)); + + if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { + printf("allowed write after lock change (%s)\n", __location__); + ret = false; + goto done; + } + +done: + smbcli_close(cli->tree, fnum); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + basic testing of lock calls +*/ +struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK"); + + torture_suite_add_1smb_test(suite, "lockx", test_lockx); + torture_suite_add_1smb_test(suite, "lock", test_lock); + torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh); + torture_suite_add_1smb_test(suite, "async", test_async); + torture_suite_add_1smb_test(suite, "errorcode", test_errorcode); + torture_suite_add_1smb_test(suite, "changetype", test_changetype); + + return suite; +} |