📄 locking.c
字号:
/* Unix SMB/CIFS implementation. basic locking tests Copyright (C) Andrew Tridgell 2000-2004 Copyright (C) Jeremy Allison 2000-2004 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 "libcli/raw/libcliraw.h"#include "libcli/libcli.h"#include "torture/smbtorture.h"#include "torture/util.h"#include "system/time.h"#include "system/filesys.h"#define BASEDIR "\\locktest"/* This test checks for two things: 1) correct support for retaining locks over a close (ie. the server must not use posix semantics) 2) support for lock timeouts */static bool torture_locktest1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\lockt1.lck"; int fnum1, fnum2, fnum3; time_t t1, t2; uint_t lock_timeout; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree))); fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE); torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree))); fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE); torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree))); torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree))); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock2 succeeded! This is a locking bug\n"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock2 succeeded! This is a locking bug\n"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT)) return false; torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree))); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)), "lock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT)) return false; lock_timeout = (6 + (random() % 20)); torture_comment(tctx, "Testing lock timeout with timeout=%u\n", lock_timeout); t1 = time(NULL); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)), "lock3 succeeded! This is a locking bug\n"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT)) return false; t2 = time(NULL); if (t2 - t1 < 5) { torture_fail(tctx, "error: This server appears not to support timed lock requests"); } torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n", (uint_t)(t2-t1), lock_timeout); torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2), talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree))); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock4 succeeded! This is a locking bug"); if (!check_error(__location__, cli2, ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT)) return false; torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1), talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3), talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree))); torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname), talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree))); return true;}/* This test checks that 1) the server supports multiple locking contexts on the one SMB connection, distinguished by PID. 2) the server correctly fails overlapping locks made by the same PID (this goes against POSIX behaviour, which is why it is tricky to implement) 3) the server denies unlock requests by an incorrect client PID*/static bool torture_locktest2(struct torture_context *tctx, struct smbcli_state *cli){ const char *fname = BASEDIR "\\lockt2.lck"; int fnum1, fnum2, fnum3; if (!torture_setup_dir(cli, BASEDIR)) { return false; } torture_comment(tctx, "Testing pid context\n"); cli->session->pid = 1; fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)", fname, smbcli_errstr(cli->tree))); fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open2 of %s failed (%s)", fname, smbcli_errstr(cli->tree))); cli->session->pid = 2; fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree))); cli->session->pid = 1; torture_assert_ntstatus_ok(tctx, smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli->tree))); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)), "WRITE lock1 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)), "WRITE lock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)), "READ lock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT)) return false; torture_assert_ntstatus_ok(tctx, smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock at 100 failed (%s)", smbcli_errstr(cli->tree))); cli->session->pid = 2; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)), "unlock at 100 succeeded! This is a locking bug"); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)), "unlock1 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRnotlocked, NT_STATUS_RANGE_NOT_LOCKED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)), "unlock2 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRnotlocked, NT_STATUS_RANGE_NOT_LOCKED)) return false; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)), "lock3 succeeded! This is a locking bug"); if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false; cli->session->pid = 1; torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1), talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2), talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3), talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree))); return true;}/* This test checks that 1) the server supports the full offset range in lock requests*/static bool torture_locktest3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\lockt3.lck"; int fnum1, fnum2, i; uint32_t offset; extern int torture_numops;#define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops torture_comment(tctx, "Testing 32 bit offset ranges"); if (!torture_setup_dir(cli1, BASEDIR)) { return false; } fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree))); fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE); torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree))); torture_comment(tctx, "Establishing %d locks\n", torture_numops); for (offset=i=0;i<torture_numops;i++) { NEXT_OFFSET; torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK), talloc_asprintf(tctx, "lock2 %d failed (%s)", i, smbcli_errstr(cli1->tree))); } torture_comment(tctx, "Testing %d locks\n", torture_numops); for (offset=i=0;i<torture_numops;i++) { NEXT_OFFSET; torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)), talloc_asprintf(tctx, "error: lock1 %d succeeded!", i)); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)), talloc_asprintf(tctx, "error: lock2 %d succeeded!", i)); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)), talloc_asprintf(tctx, "error: lock3 %d succeeded!", i)); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)), talloc_asprintf(tctx, "error: lock4 %d succeeded!", i)); } torture_comment(tctx, "Removing %d locks\n", torture_numops); for (offset=i=0;i<torture_numops;i++) { NEXT_OFFSET; torture_assert_ntstatus_ok(tctx, smbcli_unlock(cli1->tree, fnum1, offset-1, 1), talloc_asprintf(tctx, "unlock1 %d failed (%s)", i, smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_unlock(cli2->tree, fnum2, offset-2, 1), talloc_asprintf(tctx, "unlock2 %d failed (%s)", i, smbcli_errstr(cli1->tree))); } torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1), talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2), talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree))); torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname), talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree))); return true;}#define EXPECTED(ret, v) if ((ret) != (v)) { \ torture_comment(tctx, "** "); correct = false; \ }/* looks at overlapping locks*/static bool torture_locktest4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2){ const char *fname = BASEDIR "\\lockt4.lck"; int fnum1, fnum2, f; bool ret; uint8_t buf[1000]; bool correct = true; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE); memset(buf, 0, sizeof(buf)); if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) { torture_comment(tctx, "Failed to create file\n"); correct = false; goto fail; } ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) && NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK)); EXPECTED(ret, false); torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot"); ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) && NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK)); EXPECTED(ret, true); torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot"); ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -