wmi-1.3.16 from opsview.com
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
chkpath individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\rawchkpath"
|
||||
|
||||
#define CHECK_STATUS(status, correct, dos_correct) do { \
|
||||
if (!NT_STATUS_EQUAL(status, correct) && !NT_STATUS_EQUAL(status, dos_correct)) { \
|
||||
printf("(%d) Incorrect status %s - should be %s\n", \
|
||||
__LINE__, nt_errstr(status), nt_errstr(correct)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
|
||||
static NTSTATUS single_search(struct smbcli_state *cli,
|
||||
TALLOC_CTX *mem_ctx, const char *pattern)
|
||||
{
|
||||
union smb_search_first io;
|
||||
NTSTATUS status;
|
||||
|
||||
io.t2ffirst.level = RAW_SEARCH_TRANS2;
|
||||
io.t2ffirst.data_level = RAW_SEARCH_DATA_STANDARD;
|
||||
io.t2ffirst.in.search_attrib = 0;
|
||||
io.t2ffirst.in.max_count = 1;
|
||||
io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
|
||||
io.t2ffirst.in.storage_type = 0;
|
||||
io.t2ffirst.in.pattern = pattern;
|
||||
|
||||
status = smb_raw_search_first(cli->tree, mem_ctx,
|
||||
&io, NULL, NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL test_path(struct smbcli_state *cli, const char *path, NTSTATUS expected, NTSTATUS dos_expected)
|
||||
{
|
||||
union smb_chkpath io;
|
||||
NTSTATUS status;
|
||||
io.chkpath.in.path = path;
|
||||
status = smb_raw_chkpath(cli->tree, &io);
|
||||
if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) {
|
||||
printf("%-40s FAILED %s should be %s or %s\n",
|
||||
path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected));
|
||||
return False;
|
||||
} else {
|
||||
printf("%-40s correct (%s)\n", path, nt_errstr(status));
|
||||
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_chkpath io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum = -1;
|
||||
int fnum1 = -1;
|
||||
|
||||
io.chkpath.in.path = BASEDIR;
|
||||
|
||||
status = smb_raw_chkpath(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK, NT_STATUS_OK);
|
||||
|
||||
ret &= test_path(cli, BASEDIR "\\nodir", NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\test.txt..");
|
||||
if (fnum == -1) {
|
||||
printf("failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret &= test_path(cli, BASEDIR "\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
if (!torture_set_file_attribute(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN)) {
|
||||
printf("failed to set basedir hidden\n");
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret &= test_path(cli, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
|
||||
ret &= test_path(cli, BASEDIR "\\foo\\..\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "", NT_STATUS_OK, NT_STATUS_OK);
|
||||
ret &= test_path(cli, ".", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\\\\\.\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "." BASEDIR, NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\.\\test.txt..", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.\\.aaaaa", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\.\\\\\\\\\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
/* Note that the two following paths are identical but
|
||||
give different NT status returns for chkpth and findfirst. */
|
||||
|
||||
printf("testing findfirst on %s\n", "\\.\\\\\\\\\\\\.");
|
||||
status = single_search(cli, mem_ctx, "\\.\\\\\\\\\\\\.");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRinvalidname));
|
||||
|
||||
ret &= test_path(cli, "\\.\\\\\\\\\\\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
/* We expect this open to fail with the same error code as the chkpath below. */
|
||||
printf("testing Open on %s\n", "\\.\\\\\\\\\\\\.");
|
||||
/* findfirst seems to fail with a different error. */
|
||||
fnum1 = smbcli_nt_create_full(cli->tree, "\\.\\\\\\\\\\\\.",
|
||||
0, SEC_RIGHTS_FILE_ALL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NTCREATEX_SHARE_ACCESS_DELETE|
|
||||
NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE,
|
||||
NTCREATEX_DISP_OVERWRITE_IF,
|
||||
0, 0);
|
||||
status = smbcli_nt_error(cli->tree);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
|
||||
ret &= test_path(cli, "\\.\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "..\\..\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
|
||||
ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
|
||||
ret &= test_path(cli, "\\.\\\\\\\\\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"\\.\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"\\nt", NT_STATUS_OK, NT_STATUS_OK);
|
||||
ret &= test_path(cli, BASEDIR".\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR"xx\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, ".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\..\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR".", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\", NT_STATUS_OK,NT_STATUS_OK);
|
||||
ret &= test_path(cli, "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, "\\..\\", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
|
||||
ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
|
||||
ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\..", NT_STATUS_OK,NT_STATUS_OK);
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb600", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe", NT_STATUS_NOT_A_DIRECTORY,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
/* We expect this open to fail with the same error code as the chkpath below. */
|
||||
printf("testing Open on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
|
||||
/* findfirst seems to fail with a different error. */
|
||||
fnum1 = smbcli_nt_create_full(cli->tree, BASEDIR".\\.\\.\\.\\foo\\..\\.\\",
|
||||
0, SEC_RIGHTS_FILE_ALL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NTCREATEX_SHARE_ACCESS_DELETE|
|
||||
NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE,
|
||||
NTCREATEX_DISP_OVERWRITE_IF,
|
||||
0, 0);
|
||||
status = smbcli_nt_error(cli->tree);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
printf("testing findfirst on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
|
||||
status = single_search(cli, mem_ctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
/* We expect this open to fail with the same error code as the chkpath below. */
|
||||
/* findfirst seems to fail with a different error. */
|
||||
printf("testing Open on %s\n", BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3");
|
||||
fnum1 = smbcli_nt_create_full(cli->tree, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3",
|
||||
0, SEC_RIGHTS_FILE_ALL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NTCREATEX_SHARE_ACCESS_DELETE|
|
||||
NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE,
|
||||
NTCREATEX_DISP_OVERWRITE_IF,
|
||||
0, 0);
|
||||
status = smbcli_nt_error(cli->tree);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
basic testing of chkpath calls
|
||||
*/
|
||||
BOOL torture_raw_chkpath(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_chkpath");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt"))) {
|
||||
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S"))) {
|
||||
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S\\VB98"))) {
|
||||
printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
|
||||
return False;
|
||||
}
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\nt\\V S\\VB98\\vb6.exe");
|
||||
if (fnum == -1) {
|
||||
printf("failed to open \\nt\\V S\\VB98\\vb6.exe - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!test_chkpath(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_CLOSE_* individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "system/time.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
|
||||
/* basic testing of all RAW_CLOSE_* calls
|
||||
*/
|
||||
BOOL torture_raw_close(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
union smb_close io;
|
||||
union smb_flush io_flush;
|
||||
int fnum;
|
||||
const char *fname = "\\torture_close.txt";
|
||||
time_t basetime = (time(NULL) + 3*86400) & ~1;
|
||||
union smb_fileinfo finfo, finfo2;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_close");
|
||||
|
||||
#define REOPEN do { \
|
||||
fnum = create_complex_file(cli, mem_ctx, fname); \
|
||||
if (fnum == -1) { \
|
||||
printf("(%d) Failed to create %s\n", __LINE__, fname); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_STATUS(status, correct) do { \
|
||||
if (!NT_STATUS_EQUAL(status, correct)) { \
|
||||
printf("(%d) Incorrect status %s - should be %s\n", \
|
||||
__LINE__, nt_errstr(status), nt_errstr(correct)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
REOPEN;
|
||||
|
||||
io.close.level = RAW_CLOSE_CLOSE;
|
||||
io.close.in.file.fnum = fnum;
|
||||
io.close.in.write_time = basetime;
|
||||
status = smb_raw_close(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_close(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("testing close.in.write_time\n");
|
||||
|
||||
/* the file should have the write time set */
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (basetime != nt_time_to_unix(finfo.all_info.out.write_time)) {
|
||||
printf("Incorrect write time on file - %s - %s\n",
|
||||
timestring(mem_ctx, basetime),
|
||||
nt_time_string(mem_ctx, finfo.all_info.out.write_time));
|
||||
dump_all_info(mem_ctx, &finfo);
|
||||
ret = False;
|
||||
}
|
||||
|
||||
printf("testing other times\n");
|
||||
|
||||
/* none of the other times should be set to that time */
|
||||
if (nt_time_equal(&finfo.all_info.out.write_time,
|
||||
&finfo.all_info.out.access_time) ||
|
||||
nt_time_equal(&finfo.all_info.out.write_time,
|
||||
&finfo.all_info.out.create_time) ||
|
||||
nt_time_equal(&finfo.all_info.out.write_time,
|
||||
&finfo.all_info.out.change_time)) {
|
||||
printf("Incorrect times after close - only write time should be set\n");
|
||||
dump_all_info(mem_ctx, &finfo);
|
||||
ret = False;
|
||||
}
|
||||
|
||||
|
||||
smbcli_unlink(cli->tree, fname);
|
||||
REOPEN;
|
||||
|
||||
finfo2.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo2.generic.in.file.path = fname;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.close.level = RAW_CLOSE_CLOSE;
|
||||
io.close.in.file.fnum = fnum;
|
||||
io.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
/* the file should have the write time set equal to access time */
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (!nt_time_equal(&finfo.all_info.out.write_time,
|
||||
&finfo2.all_info.out.write_time)) {
|
||||
printf("Incorrect write time on file - 0 time should be ignored\n");
|
||||
dump_all_info(mem_ctx, &finfo);
|
||||
ret = False;
|
||||
}
|
||||
|
||||
printf("testing splclose\n");
|
||||
|
||||
/* check splclose on a file */
|
||||
REOPEN;
|
||||
io.splclose.level = RAW_CLOSE_SPLCLOSE;
|
||||
io.splclose.in.file.fnum = fnum;
|
||||
status = smb_raw_close(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
|
||||
|
||||
printf("testing flush\n");
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
io_flush.flush.level = RAW_FLUSH_FLUSH;
|
||||
io_flush.flush.in.file.fnum = fnum;
|
||||
status = smb_raw_flush(cli->tree, &io_flush);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
io_flush.flush_all.level = RAW_FLUSH_ALL;
|
||||
status = smb_raw_flush(cli->tree, &io_flush);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
REOPEN;
|
||||
|
||||
io_flush.flush.level = RAW_FLUSH_FLUSH;
|
||||
io_flush.flush.in.file.fnum = fnum;
|
||||
status = smb_raw_flush(cli->tree, &io_flush);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Testing SMBexit\n");
|
||||
smb_raw_exit(cli->session);
|
||||
|
||||
io_flush.flush.level = RAW_FLUSH_FLUSH;
|
||||
io_flush.flush.in.file.fnum = fnum;
|
||||
status = smb_raw_flush(cli->tree, &io_flush);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_unlink(cli->tree, fname);
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
libcli composite function testing
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
#include "librpc/gen_ndr/ndr_misc.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\composite"
|
||||
|
||||
static void loadfile_complete(struct composite_context *c)
|
||||
{
|
||||
int *count = talloc_get_type(c->async.private_data, int);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
test a simple savefile/loadfile combination
|
||||
*/
|
||||
static BOOL test_loadfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
NTSTATUS status;
|
||||
struct smb_composite_savefile io1;
|
||||
struct smb_composite_loadfile io2;
|
||||
struct composite_context **c;
|
||||
uint8_t *data;
|
||||
size_t len = random() % 100000;
|
||||
const int num_ops = 50;
|
||||
int i;
|
||||
int *count = talloc_zero(mem_ctx, int);
|
||||
|
||||
data = talloc_array(mem_ctx, uint8_t, len);
|
||||
|
||||
generate_random_buffer(data, len);
|
||||
|
||||
io1.in.fname = fname;
|
||||
io1.in.data = data;
|
||||
io1.in.size = len;
|
||||
|
||||
printf("testing savefile\n");
|
||||
|
||||
status = smb_composite_savefile(cli->tree, &io1);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("savefile failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
io2.in.fname = fname;
|
||||
|
||||
printf("testing parallel loadfile with %d ops\n", num_ops);
|
||||
|
||||
c = talloc_array(mem_ctx, struct composite_context *, num_ops);
|
||||
|
||||
for (i=0;i<num_ops;i++) {
|
||||
c[i] = smb_composite_loadfile_send(cli->tree, &io2);
|
||||
c[i]->async.fn = loadfile_complete;
|
||||
c[i]->async.private_data = count;
|
||||
}
|
||||
|
||||
printf("waiting for completion\n");
|
||||
while (*count != num_ops) {
|
||||
event_loop_once(cli->transport->socket->event.ctx);
|
||||
printf("count=%d\r", *count);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("count=%d\n", *count);
|
||||
|
||||
for (i=0;i<num_ops;i++) {
|
||||
status = smb_composite_loadfile_recv(c[i], mem_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("loadfile[%d] failed - %s\n", i, nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (io2.out.size != len) {
|
||||
printf("wrong length in returned data - %d should be %d\n",
|
||||
io2.out.size, (int)len);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (memcmp(io2.out.data, data, len) != 0) {
|
||||
printf("wrong data in loadfile!\n");
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(data);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test a simple savefile/loadfile combination
|
||||
*/
|
||||
static BOOL test_fetchfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
NTSTATUS status;
|
||||
struct smb_composite_savefile io1;
|
||||
struct smb_composite_fetchfile io2;
|
||||
struct composite_context **c;
|
||||
uint8_t *data;
|
||||
int i;
|
||||
size_t len = random() % 10000;
|
||||
extern int torture_numops;
|
||||
struct event_context *event_ctx;
|
||||
int *count = talloc_zero(mem_ctx, int);
|
||||
BOOL ret = True;
|
||||
|
||||
data = talloc_array(mem_ctx, uint8_t, len);
|
||||
|
||||
generate_random_buffer(data, len);
|
||||
|
||||
io1.in.fname = fname;
|
||||
io1.in.data = data;
|
||||
io1.in.size = len;
|
||||
|
||||
printf("testing savefile\n");
|
||||
|
||||
status = smb_composite_savefile(cli->tree, &io1);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("savefile failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
io2.in.dest_host = lp_parm_string(-1, "torture", "host");
|
||||
io2.in.port = 0;
|
||||
io2.in.called_name = lp_parm_string(-1, "torture", "host");
|
||||
io2.in.service = lp_parm_string(-1, "torture", "share");
|
||||
io2.in.service_type = "A:";
|
||||
|
||||
io2.in.credentials = cmdline_credentials;
|
||||
io2.in.workgroup = lp_workgroup();
|
||||
io2.in.filename = fname;
|
||||
|
||||
printf("testing parallel fetchfile with %d ops\n", torture_numops);
|
||||
|
||||
event_ctx = event_context_init(mem_ctx);
|
||||
c = talloc_array(mem_ctx, struct composite_context *, torture_numops);
|
||||
|
||||
for (i=0; i<torture_numops; i++) {
|
||||
c[i] = smb_composite_fetchfile_send(&io2, event_ctx);
|
||||
c[i]->async.fn = loadfile_complete;
|
||||
c[i]->async.private_data = count;
|
||||
}
|
||||
|
||||
printf("waiting for completion\n");
|
||||
|
||||
while (*count != torture_numops) {
|
||||
event_loop_once(event_ctx);
|
||||
printf("count=%d\r", *count);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("count=%d\n", *count);
|
||||
|
||||
for (i=0;i<torture_numops;i++) {
|
||||
status = smb_composite_fetchfile_recv(c[i], mem_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("loadfile[%d] failed - %s\n", i,
|
||||
nt_errstr(status));
|
||||
ret = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (io2.out.size != len) {
|
||||
printf("wrong length in returned data - %d "
|
||||
"should be %d\n",
|
||||
io2.out.size, (int)len);
|
||||
ret = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(io2.out.data, data, len) != 0) {
|
||||
printf("wrong data in loadfile!\n");
|
||||
ret = False;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test setfileacl
|
||||
*/
|
||||
static BOOL test_appendacl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
struct smb_composite_appendacl **io;
|
||||
struct smb_composite_appendacl **io_orig;
|
||||
struct composite_context **c;
|
||||
struct event_context *event_ctx;
|
||||
|
||||
struct security_descriptor *test_sd;
|
||||
struct security_ace *ace;
|
||||
struct dom_sid *test_sid;
|
||||
|
||||
const int num_ops = 50;
|
||||
int *count = talloc_zero(mem_ctx, int);
|
||||
struct smb_composite_savefile io1;
|
||||
|
||||
NTSTATUS status;
|
||||
int i;
|
||||
|
||||
io_orig = talloc_array(mem_ctx, struct smb_composite_appendacl *, num_ops);
|
||||
|
||||
printf ("creating %d empty files and getting their acls with appendacl\n", num_ops);
|
||||
|
||||
for (i = 0; i < num_ops; i++) {
|
||||
io1.in.fname = talloc_asprintf(io_orig, BASEDIR "\\test%d.txt", i);
|
||||
io1.in.data = NULL;
|
||||
io1.in.size = 0;
|
||||
|
||||
status = smb_composite_savefile(cli->tree, &io1);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("savefile failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
io_orig[i] = talloc (io_orig, struct smb_composite_appendacl);
|
||||
io_orig[i]->in.fname = talloc_steal(io_orig[i], io1.in.fname);
|
||||
io_orig[i]->in.sd = security_descriptor_initialise(io_orig[i]);
|
||||
status = smb_composite_appendacl(cli->tree, io_orig[i], io_orig[i]);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("appendacl failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* fill Security Descriptor with aces to be added */
|
||||
|
||||
test_sd = security_descriptor_initialise(mem_ctx);
|
||||
test_sid = dom_sid_parse_talloc (mem_ctx, "S-1-5-32-1234-5432");
|
||||
|
||||
ace = talloc_zero(mem_ctx, struct security_ace);
|
||||
|
||||
ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
|
||||
ace->flags = 0;
|
||||
ace->access_mask = SEC_STD_ALL;
|
||||
ace->trustee = *test_sid;
|
||||
|
||||
status = security_descriptor_dacl_add(test_sd, ace);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("appendacl failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* set parameters for appendacl async call */
|
||||
|
||||
printf("testing parallel appendacl with %d ops\n", num_ops);
|
||||
|
||||
c = talloc_array(mem_ctx, struct composite_context *, num_ops);
|
||||
io = talloc_array(mem_ctx, struct smb_composite_appendacl *, num_ops);
|
||||
|
||||
for (i=0; i < num_ops; i++) {
|
||||
io[i] = talloc (io, struct smb_composite_appendacl);
|
||||
io[i]->in.sd = test_sd;
|
||||
io[i]->in.fname = talloc_asprintf(io[i], BASEDIR "\\test%d.txt", i);
|
||||
|
||||
c[i] = smb_composite_appendacl_send(cli->tree, io[i]);
|
||||
c[i]->async.fn = loadfile_complete;
|
||||
c[i]->async.private_data = count;
|
||||
}
|
||||
|
||||
event_ctx = talloc_reference(mem_ctx, cli->tree->session->transport->socket->event.ctx);
|
||||
printf("waiting for completion\n");
|
||||
while (*count != num_ops) {
|
||||
event_loop_once(event_ctx);
|
||||
printf("count=%d\r", *count);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("count=%d\n", *count);
|
||||
|
||||
for (i=0; i < num_ops; i++) {
|
||||
status = smb_composite_appendacl_recv(c[i], io[i]);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("appendacl[%d] failed - %s\n", i, nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
security_descriptor_dacl_add(io_orig[i]->out.sd, ace);
|
||||
if (!security_acl_equal(io_orig[i]->out.sd->dacl, io[i]->out.sd->dacl)) {
|
||||
printf("appendacl[%d] failed - needed acl isn't set\n", i);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
talloc_free (ace);
|
||||
talloc_free (test_sid);
|
||||
talloc_free (test_sd);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* test a query FS info by asking for share's GUID */
|
||||
static BOOL test_fsinfo(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
char *guid = NULL;
|
||||
NTSTATUS status;
|
||||
struct smb_composite_fsinfo io1;
|
||||
struct composite_context **c;
|
||||
|
||||
int i;
|
||||
extern int torture_numops;
|
||||
struct event_context *event_ctx;
|
||||
int *count = talloc_zero(mem_ctx, int);
|
||||
BOOL ret = True;
|
||||
|
||||
io1.in.dest_host = lp_parm_string(-1, "torture", "host");
|
||||
io1.in.port = 0;
|
||||
io1.in.called_name = lp_parm_string(-1, "torture", "host");
|
||||
io1.in.service = lp_parm_string(-1, "torture", "share");
|
||||
io1.in.service_type = "A:";
|
||||
io1.in.credentials = cmdline_credentials;
|
||||
io1.in.workgroup = lp_workgroup();
|
||||
io1.in.level = RAW_QFS_OBJECTID_INFORMATION;
|
||||
|
||||
printf("testing parallel queryfsinfo [Object ID] with %d ops\n", torture_numops);
|
||||
|
||||
event_ctx = talloc_reference(mem_ctx, cli->tree->session->transport->socket->event.ctx);
|
||||
c = talloc_array(mem_ctx, struct composite_context *, torture_numops);
|
||||
|
||||
for (i=0; i<torture_numops; i++) {
|
||||
c[i] = smb_composite_fsinfo_send(cli->tree,&io1);
|
||||
c[i]->async.fn = loadfile_complete;
|
||||
c[i]->async.private_data = count;
|
||||
}
|
||||
|
||||
printf("waiting for completion\n");
|
||||
|
||||
while (*count < torture_numops) {
|
||||
event_loop_once(event_ctx);
|
||||
printf("count=%d\r", *count);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("count=%d\n", *count);
|
||||
|
||||
for (i=0;i<torture_numops;i++) {
|
||||
status = smb_composite_fsinfo_recv(c[i], mem_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("fsinfo[%d] failed - %s\n", i, nt_errstr(status));
|
||||
ret = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (io1.out.fsinfo->generic.level != RAW_QFS_OBJECTID_INFORMATION) {
|
||||
printf("wrong level in returned info - %d "
|
||||
"should be %d\n",
|
||||
io1.out.fsinfo->generic.level, RAW_QFS_OBJECTID_INFORMATION);
|
||||
ret = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
guid=GUID_string(mem_ctx, &io1.out.fsinfo->objectid_information.out.guid);
|
||||
printf("[%d] GUID: %s\n", i, guid);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of libcli composite calls
|
||||
*/
|
||||
BOOL torture_raw_composite(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_composite");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ret &= test_fetchfile(cli, mem_ctx);
|
||||
ret &= test_loadfile(cli, mem_ctx);
|
||||
ret &= test_appendacl(cli, mem_ctx);
|
||||
ret &= test_fsinfo(cli, mem_ctx);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,915 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
test suite for session setup 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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
#define BASEDIR "\\rawcontext"
|
||||
|
||||
#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 CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%s) Incorrect value %s=%d - should be %d\n", \
|
||||
__location__, #v, v, correct); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_NOT_VALUE(v, correct) do { \
|
||||
if ((v) == (correct)) { \
|
||||
printf("(%s) Incorrect value %s=%d - should not be %d\n", \
|
||||
__location__, #v, v, correct); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
|
||||
/*
|
||||
test session ops
|
||||
*/
|
||||
static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
struct smbcli_session *session;
|
||||
struct smbcli_session *session2;
|
||||
struct smbcli_session *session3;
|
||||
struct smbcli_session *session4;
|
||||
struct cli_credentials *anon_creds;
|
||||
struct smbcli_session *sessions[15];
|
||||
struct composite_context *composite_contexts[15];
|
||||
struct smbcli_tree *tree;
|
||||
struct smb_composite_sesssetup setup;
|
||||
struct smb_composite_sesssetup setups[15];
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
union smb_close cl;
|
||||
int fnum;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint8_t c = 1;
|
||||
int i;
|
||||
|
||||
printf("TESTING SESSION HANDLING\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("create a second security context on the same transport\n");
|
||||
session = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
|
||||
status = smb_composite_sesssetup(session, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
session->vuid = setup.out.vuid;
|
||||
|
||||
printf("create a third security context on the same transport, with vuid set\n");
|
||||
session2 = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
|
||||
session2->vuid = session->vuid;
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
|
||||
status = smb_composite_sesssetup(session2, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
session2->vuid = setup.out.vuid;
|
||||
printf("vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid);
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
|
||||
/* Samba4 currently fails this - we need to determine if this insane behaviour is important */
|
||||
if (session2->vuid == session->vuid) {
|
||||
printf("server allows the user to re-use an existing vuid in session setup \n");
|
||||
}
|
||||
} else {
|
||||
CHECK_NOT_VALUE(session2->vuid, session->vuid);
|
||||
}
|
||||
talloc_free(session2);
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
|
||||
printf("create a fourth security context on the same transport, without extended security\n");
|
||||
session3 = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
|
||||
session3->vuid = session->vuid;
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
|
||||
|
||||
status = smb_composite_sesssetup(session3, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
|
||||
|
||||
printf("create a fouth anonymous security context on the same transport, without extended security\n");
|
||||
session4 = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
|
||||
session4->vuid = session->vuid;
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
|
||||
anon_creds = cli_credentials_init(mem_ctx);
|
||||
cli_credentials_set_conf(anon_creds);
|
||||
cli_credentials_set_anonymous(anon_creds);
|
||||
|
||||
setup.in.credentials = anon_creds;
|
||||
|
||||
status = smb_composite_sesssetup(session3, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
talloc_free(session4);
|
||||
}
|
||||
|
||||
printf("use the same tree as the existing connection\n");
|
||||
tree = smbcli_tree_init(session, mem_ctx, False);
|
||||
tree->tid = cli->tree->tid;
|
||||
|
||||
printf("create a file using the new vuid\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using the old vuid\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("write with the new vuid\n");
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("logoff the new vuid\n");
|
||||
status = smb_raw_ulogoff(session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the new vuid should not now be accessible\n");
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("second logoff for the new vuid should fail\n");
|
||||
status = smb_raw_ulogoff(session);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
|
||||
talloc_free(session);
|
||||
|
||||
printf("the fnum should have been auto-closed\n");
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("create %d secondary security contexts on the same transport\n",
|
||||
(int)ARRAY_SIZE(sessions));
|
||||
for (i=0; i <ARRAY_SIZE(sessions); i++) {
|
||||
setups[i].in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
|
||||
setups[i].in.workgroup = lp_workgroup();
|
||||
|
||||
setups[i].in.credentials = cmdline_credentials;
|
||||
|
||||
sessions[i] = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* flush the queue */
|
||||
for (i=0; i < ARRAY_SIZE(sessions); i++) {
|
||||
event_loop_once(composite_contexts[0]->event_ctx);
|
||||
}
|
||||
|
||||
printf("finishing %d secondary security contexts on the same transport\n",
|
||||
(int)ARRAY_SIZE(sessions));
|
||||
for (i=0; i< ARRAY_SIZE(sessions); i++) {
|
||||
status = smb_composite_sesssetup_recv(composite_contexts[i]);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
sessions[i]->vuid = setups[i].out.vuid;
|
||||
printf("VUID: %d\n", sessions[i]->vuid);
|
||||
status = smb_raw_ulogoff(sessions[i]);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
}
|
||||
|
||||
|
||||
talloc_free(tree);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test tree ops
|
||||
*/
|
||||
static BOOL test_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *share, *host;
|
||||
struct smbcli_tree *tree;
|
||||
union smb_tcon tcon;
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
union smb_close cl;
|
||||
int fnum;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint8_t c = 1;
|
||||
|
||||
printf("TESTING TREE HANDLING\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
share = lp_parm_string(-1, "torture", "share");
|
||||
host = lp_parm_string(-1, "torture", "host");
|
||||
|
||||
printf("create a second tree context on the same session\n");
|
||||
tree = smbcli_tree_init(cli->session, mem_ctx, 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(mem_ctx, "\\\\%s\\%s", host, share);
|
||||
tcon.tconx.in.device = "A:";
|
||||
status = smb_raw_tcon(tree, mem_ctx, &tcon);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
|
||||
tree->tid = tcon.tconx.out.tid;
|
||||
printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
|
||||
|
||||
printf("try a tconx with a bad device type\n");
|
||||
tcon.tconx.in.device = "FOO";
|
||||
status = smb_raw_tcon(tree, mem_ctx, &tcon);
|
||||
CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
|
||||
|
||||
|
||||
printf("create a file using the new tid\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using the old tid\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("write with the new tid\n");
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("disconnect the new tid\n");
|
||||
status = smb_tree_disconnect(tree);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the new tid should not now be accessible\n");
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum should have been auto-closed\n");
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
/* close down the new tree */
|
||||
talloc_free(tree);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test tree with ulogoff
|
||||
this demonstrates that a tcon isn't autoclosed by a ulogoff
|
||||
the tcon can be reused using any other valid session later
|
||||
*/
|
||||
static BOOL test_tree_ulogoff(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *share, *host;
|
||||
struct smbcli_session *session1;
|
||||
struct smbcli_session *session2;
|
||||
struct smb_composite_sesssetup setup;
|
||||
struct smbcli_tree *tree;
|
||||
union smb_tcon tcon;
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
int fnum1, fnum2;
|
||||
const char *fname1 = BASEDIR "\\test1.txt";
|
||||
const char *fname2 = BASEDIR "\\test2.txt";
|
||||
uint8_t c = 1;
|
||||
|
||||
printf("TESTING TREE with ulogoff\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
share = lp_parm_string(-1, "torture", "share");
|
||||
host = lp_parm_string(-1, "torture", "host");
|
||||
|
||||
printf("create the first new sessions\n");
|
||||
session1 = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities = cli->transport->negotiate.capabilities;
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
status = smb_composite_sesssetup(session1, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
session1->vuid = setup.out.vuid;
|
||||
printf("vuid1=%d\n", session1->vuid);
|
||||
|
||||
printf("create a tree context on the with vuid1\n");
|
||||
tree = smbcli_tree_init(session1, mem_ctx, 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(mem_ctx, "\\\\%s\\%s", host, share);
|
||||
tcon.tconx.in.device = "A:";
|
||||
status = smb_raw_tcon(tree, mem_ctx, &tcon);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
tree->tid = tcon.tconx.out.tid;
|
||||
printf("tid=%d\n", tree->tid);
|
||||
|
||||
printf("create a file using vuid1\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname1;
|
||||
status = smb_raw_open(tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum1 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using vuid1\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum1;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("ulogoff the vuid1\n");
|
||||
status = smb_raw_ulogoff(session1);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("create the second new sessions\n");
|
||||
session2 = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities = cli->transport->negotiate.capabilities;
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
status = smb_composite_sesssetup(session2, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
session2->vuid = setup.out.vuid;
|
||||
printf("vuid2=%d\n", session2->vuid);
|
||||
|
||||
printf("use the existing tree with vuid2\n");
|
||||
tree->session = session2;
|
||||
|
||||
printf("create a file using vuid2\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname2;
|
||||
status = smb_raw_open(tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using vuid2\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum2;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
status = smb_raw_write(tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("ulogoff the vuid2\n");
|
||||
status = smb_raw_ulogoff(session2);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
/* this also demonstrates that SMBtdis doesn't need a valid vuid */
|
||||
printf("disconnect the existing tree connection\n");
|
||||
status = smb_tree_disconnect(tree);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("disconnect the existing tree connection\n");
|
||||
status = smb_tree_disconnect(tree);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));
|
||||
|
||||
/* close down the new tree */
|
||||
talloc_free(tree);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test pid ops
|
||||
this test demonstrates that exit() only sees the PID
|
||||
used for the open() calls
|
||||
*/
|
||||
static BOOL test_pid_exit_only_sees_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
union smb_close cl;
|
||||
int fnum;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint8_t c = 1;
|
||||
uint16_t pid1, pid2;
|
||||
|
||||
printf("TESTING PID HANDLING exit() only cares about open() PID\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
pid1 = cli->session->pid;
|
||||
pid2 = pid1 + 1;
|
||||
|
||||
printf("pid1=%d pid2=%d\n", pid1, pid2);
|
||||
|
||||
printf("create a file using pid1\n");
|
||||
cli->session->pid = pid1;
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using pid2\n");
|
||||
cli->session->pid = pid2;
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit pid2\n");
|
||||
cli->session->pid = pid2;
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum should still be accessible via pid2\n");
|
||||
cli->session->pid = pid2;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit pid2\n");
|
||||
cli->session->pid = pid2;
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum should still be accessible via pid1 and pid2\n");
|
||||
cli->session->pid = pid1;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
cli->session->pid = pid2;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit pid1\n");
|
||||
cli->session->pid = pid1;
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum should not now be accessible via pid1 or pid2\n");
|
||||
cli->session->pid = pid1;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
cli->session->pid = pid2;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum should have been auto-closed\n");
|
||||
cli->session->pid = pid1;
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test pid ops with 2 sessions
|
||||
*/
|
||||
static BOOL test_pid_2sess(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
struct smbcli_session *session;
|
||||
struct smb_composite_sesssetup setup;
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
union smb_close cl;
|
||||
int fnum;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint8_t c = 1;
|
||||
uint16_t vuid1, vuid2;
|
||||
|
||||
printf("TESTING PID HANDLING WITH 2 SESSIONS\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("create a second security context on the same transport\n");
|
||||
session = smbcli_session_init(cli->transport, mem_ctx, False);
|
||||
|
||||
setup.in.sesskey = cli->transport->negotiate.sesskey;
|
||||
setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
|
||||
setup.in.workgroup = lp_workgroup();
|
||||
|
||||
setup.in.credentials = cmdline_credentials;
|
||||
|
||||
status = smb_composite_sesssetup(session, &setup);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
session->vuid = setup.out.vuid;
|
||||
|
||||
vuid1 = cli->session->vuid;
|
||||
vuid2 = session->vuid;
|
||||
|
||||
printf("vuid1=%d vuid2=%d\n", vuid1, vuid2);
|
||||
|
||||
printf("create a file using the vuid1\n");
|
||||
cli->session->vuid = vuid1;
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using the vuid1 (fnum=%d)\n", fnum);
|
||||
cli->session->vuid = vuid1;
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit the pid with vuid2\n");
|
||||
cli->session->vuid = vuid2;
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum should still be accessible\n");
|
||||
cli->session->vuid = vuid1;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit the pid with vuid1\n");
|
||||
cli->session->vuid = vuid1;
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum should not now be accessible\n");
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum should have been auto-closed\n");
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test pid ops with 2 tcons
|
||||
*/
|
||||
static BOOL test_pid_2tcon(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *share, *host;
|
||||
struct smbcli_tree *tree;
|
||||
union smb_tcon tcon;
|
||||
union smb_open io;
|
||||
union smb_write wr;
|
||||
union smb_close cl;
|
||||
int fnum1, fnum2;
|
||||
const char *fname1 = BASEDIR "\\test1.txt";
|
||||
const char *fname2 = BASEDIR "\\test2.txt";
|
||||
uint8_t c = 1;
|
||||
uint16_t tid1, tid2;
|
||||
|
||||
printf("TESTING PID HANDLING WITH 2 TCONS\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
share = lp_parm_string(-1, "torture", "share");
|
||||
host = lp_parm_string(-1, "torture", "host");
|
||||
|
||||
printf("create a second tree context on the same session\n");
|
||||
tree = smbcli_tree_init(cli->session, mem_ctx, 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(mem_ctx, "\\\\%s\\%s", host, share);
|
||||
tcon.tconx.in.device = "A:";
|
||||
status = smb_raw_tcon(tree, mem_ctx, &tcon);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
tree->tid = tcon.tconx.out.tid;
|
||||
|
||||
tid1 = cli->tree->tid;
|
||||
tid2 = tree->tid;
|
||||
printf("tid1=%d tid2=%d\n", tid1, tid2);
|
||||
|
||||
printf("create a file using the tid1\n");
|
||||
cli->tree->tid = tid1;
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname1;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum1 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using the tid1\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum1;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("create a file using the tid2\n");
|
||||
cli->tree->tid = tid2;
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname2;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("write using the tid2\n");
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum2;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = 1;
|
||||
wr.writex.in.data = &c;
|
||||
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, 1);
|
||||
|
||||
printf("exit the pid\n");
|
||||
status = smb_raw_exit(cli->session);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the fnum1 on tid1 should not be accessible\n");
|
||||
cli->tree->tid = tid1;
|
||||
wr.writex.in.file.fnum = fnum1;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum1 on tid1 should have been auto-closed\n");
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum1;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum2 on tid2 should not be accessible\n");
|
||||
cli->tree->tid = tid2;
|
||||
wr.writex.in.file.fnum = fnum2;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("the fnum2 on tid2 should have been auto-closed\n");
|
||||
cl.close.level = RAW_CLOSE_CLOSE;
|
||||
cl.close.in.file.fnum = fnum2;
|
||||
cl.close.in.write_time = 0;
|
||||
status = smb_raw_close(cli->tree, &cl);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of session/tree context calls
|
||||
*/
|
||||
static BOOL torture_raw_context_int(void)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_context");
|
||||
|
||||
ret &= test_session(cli, mem_ctx);
|
||||
ret &= test_tree(cli, mem_ctx);
|
||||
ret &= test_tree_ulogoff(cli, mem_ctx);
|
||||
ret &= test_pid_exit_only_sees_open(cli, mem_ctx);
|
||||
ret &= test_pid_2sess(cli, mem_ctx);
|
||||
ret &= test_pid_2tcon(cli, mem_ctx);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
basic testing of session/tree context calls
|
||||
*/
|
||||
BOOL torture_raw_context(struct torture_context *torture)
|
||||
{
|
||||
BOOL ret = True;
|
||||
if (lp_use_spnego()) {
|
||||
ret &= torture_raw_context_int();
|
||||
lp_set_cmdline("use spnego", "False");
|
||||
}
|
||||
|
||||
ret &= torture_raw_context_int();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
test DOS extended attributes
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
Copyright (C) Guenter Kukkukk 2005
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\testeas"
|
||||
|
||||
#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)
|
||||
|
||||
static BOOL maxeadebug; /* need that here, to allow no file delete in debug case */
|
||||
|
||||
static BOOL check_ea(struct smbcli_state *cli,
|
||||
const char *fname, const char *eaname, const char *value)
|
||||
{
|
||||
NTSTATUS status = torture_check_ea(cli, fname, eaname, value);
|
||||
return NT_STATUS_IS_OK(status);
|
||||
}
|
||||
|
||||
static BOOL test_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
union smb_setfileinfo setfile;
|
||||
union smb_open io;
|
||||
const char *fname = BASEDIR "\\ea.txt";
|
||||
BOOL ret = True;
|
||||
int fnum = -1;
|
||||
|
||||
printf("TESTING SETFILEINFO EA_SET\n");
|
||||
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", NULL);
|
||||
|
||||
printf("Adding first two EAs\n");
|
||||
setfile.generic.level = RAW_SFILEINFO_EA_SET;
|
||||
setfile.generic.in.file.fnum = fnum;
|
||||
setfile.ea_set.in.num_eas = 2;
|
||||
setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
|
||||
setfile.ea_set.in.eas[0].flags = 0;
|
||||
setfile.ea_set.in.eas[0].name.s = "EAONE";
|
||||
setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
|
||||
setfile.ea_set.in.eas[1].flags = 0;
|
||||
setfile.ea_set.in.eas[1].name.s = "SECONDEA";
|
||||
setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
|
||||
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
|
||||
ret &= check_ea(cli, fname, "SECONDEA", "ValueTwo");
|
||||
|
||||
printf("Modifying 2nd EA\n");
|
||||
setfile.ea_set.in.num_eas = 1;
|
||||
setfile.ea_set.in.eas[0].name.s = "SECONDEA";
|
||||
setfile.ea_set.in.eas[0].value = data_blob_string_const(" Changed Value");
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
|
||||
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
|
||||
|
||||
printf("Setting a NULL EA\n");
|
||||
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
|
||||
setfile.ea_set.in.eas[0].name.s = "NULLEA";
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", "VALUE1");
|
||||
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
|
||||
ret &= check_ea(cli, fname, "NULLEA", NULL);
|
||||
|
||||
printf("Deleting first EA\n");
|
||||
setfile.ea_set.in.eas[0].flags = 0;
|
||||
setfile.ea_set.in.eas[0].name.s = "EAONE";
|
||||
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", NULL);
|
||||
ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
|
||||
|
||||
printf("Deleting second EA\n");
|
||||
setfile.ea_set.in.eas[0].flags = 0;
|
||||
setfile.ea_set.in.eas[0].name.s = "SECONDEA";
|
||||
setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", NULL);
|
||||
ret &= check_ea(cli, fname, "SECONDEA", NULL);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to retrieve the max. ea size for one ea name
|
||||
*/
|
||||
static int test_one_eamax(struct smbcli_state *cli, const int fnum,
|
||||
const char *eaname, DATA_BLOB eablob,
|
||||
const int eastart, const int eadebug)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct ea_struct eastruct;
|
||||
union smb_setfileinfo setfile;
|
||||
int i, high, low, maxeasize;
|
||||
|
||||
setfile.generic.level = RAW_SFILEINFO_EA_SET;
|
||||
setfile.generic.in.file.fnum = fnum;
|
||||
setfile.ea_set.in.num_eas = 1;
|
||||
setfile.ea_set.in.eas = &eastruct;
|
||||
setfile.ea_set.in.eas->flags = 0;
|
||||
setfile.ea_set.in.eas->name.s = eaname;
|
||||
setfile.ea_set.in.eas->value = eablob;
|
||||
|
||||
maxeasize = eablob.length;
|
||||
i = eastart;
|
||||
low = 0;
|
||||
high = maxeasize;
|
||||
|
||||
do {
|
||||
if (eadebug) {
|
||||
printf ("Testing EA size: %d\n", i);
|
||||
}
|
||||
setfile.ea_set.in.eas->value.length = i;
|
||||
|
||||
status = smb_raw_setfileinfo(cli->tree, &setfile);
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
|
||||
if (eadebug) {
|
||||
printf ("[%s] EA size %d succeeded! "
|
||||
"(high=%d low=%d)\n",
|
||||
eaname, i, high, low);
|
||||
}
|
||||
low = i;
|
||||
if (low == maxeasize) {
|
||||
printf ("Max. EA size for \"%s\"=%d "
|
||||
"[but could be possibly larger]\n",
|
||||
eaname, low);
|
||||
break;
|
||||
}
|
||||
if (high - low == 1 && high != maxeasize) {
|
||||
printf ("Max. EA size for \"%s\"=%d\n",
|
||||
eaname, low);
|
||||
break;
|
||||
}
|
||||
i += (high - low + 1) / 2;
|
||||
} else {
|
||||
if (eadebug) {
|
||||
printf ("[%s] EA size %d failed! "
|
||||
"(high=%d low=%d) [%s]\n",
|
||||
eaname, i, high, low,
|
||||
nt_errstr(status));
|
||||
}
|
||||
high = i;
|
||||
if (high - low <= 1) {
|
||||
printf ("Max. EA size for \"%s\"=%d\n",
|
||||
eaname, low);
|
||||
break;
|
||||
}
|
||||
i -= (high - low + 1) / 2;
|
||||
}
|
||||
} while (True);
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for maximum ea size - more than one ea name is checked.
|
||||
*
|
||||
* Additional parameters can be passed, to allow further testing:
|
||||
*
|
||||
* default
|
||||
* maxeasize 65536 limit the max. size for a single EA name
|
||||
* maxeanames 101 limit of the number of tested names
|
||||
* maxeastart 1 this EA size is used to test for the 1st EA (atm)
|
||||
* maxeadebug 0 if set True, further debug output is done - in addition
|
||||
* the testfile is not deleted for further inspection!
|
||||
*
|
||||
* Set some/all of these options on the cmdline with:
|
||||
* --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
|
||||
*
|
||||
*/
|
||||
static BOOL test_max_eas(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
union smb_open io;
|
||||
const char *fname = BASEDIR "\\ea_max.txt";
|
||||
int fnum = -1;
|
||||
BOOL ret = True;
|
||||
BOOL err = False;
|
||||
|
||||
int i, j, k, last, total;
|
||||
DATA_BLOB eablob;
|
||||
char *eaname = NULL;
|
||||
int maxeasize;
|
||||
int maxeanames;
|
||||
int maxeastart;
|
||||
|
||||
printf("TESTING SETFILEINFO MAX. EA_SET\n");
|
||||
|
||||
maxeasize = lp_parm_int(-1, "torture", "maxeasize", 65536);
|
||||
maxeanames = lp_parm_int(-1, "torture", "maxeanames", 101);
|
||||
maxeastart = lp_parm_int(-1, "torture", "maxeastart", 1);
|
||||
maxeadebug = lp_parm_int(-1, "torture", "maxeadebug", 0);
|
||||
|
||||
/* Do some sanity check on possibly passed parms */
|
||||
if (maxeasize <= 0) {
|
||||
printf("Invalid parameter 'maxeasize=%d'",maxeasize);
|
||||
err = True;
|
||||
}
|
||||
if (maxeanames <= 0) {
|
||||
printf("Invalid parameter 'maxeanames=%d'",maxeanames);
|
||||
err = True;
|
||||
}
|
||||
if (maxeastart <= 0) {
|
||||
printf("Invalid parameter 'maxeastart=%d'",maxeastart);
|
||||
err = True;
|
||||
}
|
||||
if (maxeadebug < 0) {
|
||||
printf("Invalid parameter 'maxeadebug=%d'",maxeadebug);
|
||||
err = True;
|
||||
}
|
||||
if (err) {
|
||||
printf("\n\n");
|
||||
goto done;
|
||||
}
|
||||
if (maxeastart > maxeasize) {
|
||||
maxeastart = maxeasize;
|
||||
printf ("'maxeastart' outside range - corrected to %d\n",
|
||||
maxeastart);
|
||||
}
|
||||
printf("MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
|
||||
" maxeadebug=%d\n", maxeasize, maxeanames, maxeastart,
|
||||
maxeadebug);
|
||||
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
eablob = data_blob_talloc(mem_ctx, NULL, maxeasize);
|
||||
if (eablob.data == NULL) {
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Fill in some EA data - the offset could be easily checked
|
||||
* during a hexdump.
|
||||
*/
|
||||
for (i = 0, k = 0; i < eablob.length / 4; i++, k+=4) {
|
||||
eablob.data[k] = k & 0xff;
|
||||
eablob.data[k+1] = (k >> 8) & 0xff;
|
||||
eablob.data[k+2] = (k >> 16) & 0xff;
|
||||
eablob.data[k+3] = (k >> 24) & 0xff;
|
||||
}
|
||||
|
||||
i = eablob.length % 4;
|
||||
if (i-- > 0) {
|
||||
eablob.data[k] = k & 0xff;
|
||||
if (i-- > 0) {
|
||||
eablob.data[k+1] = (k >> 8) & 0xff;
|
||||
if (i-- > 0) {
|
||||
eablob.data[k+2] = (k >> 16) & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Filesystems might allow max. EAs data for different EA names.
|
||||
* So more than one EA name should be checked.
|
||||
*/
|
||||
total = 0;
|
||||
last = maxeastart;
|
||||
|
||||
for (i = 0; i < maxeanames; i++) {
|
||||
if (eaname != NULL) {
|
||||
talloc_free(eaname);
|
||||
}
|
||||
eaname = talloc_asprintf(mem_ctx, "MAX%d", i);
|
||||
if(eaname == NULL) {
|
||||
goto done;
|
||||
}
|
||||
j = test_one_eamax(cli, fnum, eaname, eablob, last, maxeadebug);
|
||||
if (j <= 0) {
|
||||
break;
|
||||
}
|
||||
total += j;
|
||||
last = j;
|
||||
}
|
||||
|
||||
printf("Total EA size:%d\n", total);
|
||||
if (i == maxeanames) {
|
||||
printf ("NOTE: More EAs could be available!\n");
|
||||
}
|
||||
if (total == 0) {
|
||||
ret = False;
|
||||
}
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test using NTTRANS CREATE to create a file with an initial EA set
|
||||
*/
|
||||
static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
union smb_open io;
|
||||
const char *fname = BASEDIR "\\ea2.txt";
|
||||
BOOL ret = True;
|
||||
int fnum = -1;
|
||||
struct ea_struct eas[3];
|
||||
struct smb_ea_list ea_list;
|
||||
|
||||
printf("TESTING NTTRANS CREATE WITH EAS\n");
|
||||
|
||||
io.generic.level = RAW_OPEN_NTTRANS_CREATE;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
|
||||
ea_list.num_eas = 3;
|
||||
ea_list.eas = eas;
|
||||
|
||||
eas[0].flags = 0;
|
||||
eas[0].name.s = "1st EA";
|
||||
eas[0].value = data_blob_string_const("Value One");
|
||||
|
||||
eas[1].flags = 0;
|
||||
eas[1].name.s = "2nd EA";
|
||||
eas[1].value = data_blob_string_const("Second Value");
|
||||
|
||||
eas[2].flags = 0;
|
||||
eas[2].name.s = "and 3rd";
|
||||
eas[2].value = data_blob_string_const("final value");
|
||||
|
||||
io.ntcreatex.in.ea_list = &ea_list;
|
||||
io.ntcreatex.in.sec_desc = NULL;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
ret &= check_ea(cli, fname, "EAONE", NULL);
|
||||
ret &= check_ea(cli, fname, "1st EA", "Value One");
|
||||
ret &= check_ea(cli, fname, "2nd EA", "Second Value");
|
||||
ret &= check_ea(cli, fname, "and 3rd", "final value");
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
printf("Trying to add EAs on non-create\n");
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
|
||||
ea_list.num_eas = 1;
|
||||
eas[0].flags = 0;
|
||||
eas[0].name.s = "Fourth EA";
|
||||
eas[0].value = data_blob_string_const("Value Four");
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
ret &= check_ea(cli, fname, "1st EA", "Value One");
|
||||
ret &= check_ea(cli, fname, "2nd EA", "Second Value");
|
||||
ret &= check_ea(cli, fname, "and 3rd", "final value");
|
||||
ret &= check_ea(cli, fname, "Fourth EA", NULL);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
basic testing of EA calls
|
||||
*/
|
||||
BOOL torture_raw_eas(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_eas");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ret &= test_eas(cli, mem_ctx);
|
||||
ret &= test_nttrans_create(cli, mem_ctx);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test max EA size
|
||||
*/
|
||||
BOOL torture_max_eas(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_eas");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ret &= test_max_eas(cli, mem_ctx);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
if (!maxeadebug) {
|
||||
/* in no ea debug case, all files are gone now */
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
}
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ioctl individual test suite
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/ioctl.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\rawioctl"
|
||||
|
||||
#define CHECK_STATUS(status, correct) do { \
|
||||
if (!NT_STATUS_EQUAL(status, correct)) { \
|
||||
printf("(%d) Incorrect status %s - should be %s\n", \
|
||||
__LINE__, nt_errstr(status), nt_errstr(correct)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
|
||||
/* test some ioctls */
|
||||
static BOOL test_ioctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_ioctl ctl;
|
||||
int fnum;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *fname = BASEDIR "\\test.dat";
|
||||
|
||||
printf("TESTING IOCTL FUNCTIONS\n");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
if (fnum == -1) {
|
||||
printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying 0xFFFF\n");
|
||||
ctl.ioctl.level = RAW_IOCTL_IOCTL;
|
||||
ctl.ioctl.in.file.fnum = fnum;
|
||||
ctl.ioctl.in.request = 0xFFFF;
|
||||
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
|
||||
|
||||
printf("Trying QUERY_JOB_INFO\n");
|
||||
ctl.ioctl.level = RAW_IOCTL_IOCTL;
|
||||
ctl.ioctl.in.file.fnum = fnum;
|
||||
ctl.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
|
||||
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
|
||||
|
||||
printf("Trying bad handle\n");
|
||||
ctl.ioctl.in.file.fnum = fnum+1;
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* test some filesystem control functions */
|
||||
static BOOL test_fsctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
int fnum;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *fname = BASEDIR "\\test.dat";
|
||||
union smb_ioctl nt;
|
||||
|
||||
printf("\nTESTING FSCTL FUNCTIONS\n");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
if (fnum == -1) {
|
||||
printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("trying sparse file\n");
|
||||
nt.ioctl.level = RAW_IOCTL_NTIOCTL;
|
||||
nt.ntioctl.in.function = FSCTL_SET_SPARSE;
|
||||
nt.ntioctl.in.file.fnum = fnum;
|
||||
nt.ntioctl.in.fsctl = True;
|
||||
nt.ntioctl.in.filter = 0;
|
||||
nt.ntioctl.in.max_data = 0;
|
||||
nt.ntioctl.in.blob = data_blob(NULL, 0);
|
||||
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("trying batch oplock\n");
|
||||
nt.ioctl.level = RAW_IOCTL_NTIOCTL;
|
||||
nt.ntioctl.in.function = FSCTL_REQUEST_BATCH_OPLOCK;
|
||||
nt.ntioctl.in.file.fnum = fnum;
|
||||
nt.ntioctl.in.fsctl = True;
|
||||
nt.ntioctl.in.filter = 0;
|
||||
nt.ntioctl.in.max_data = 0;
|
||||
nt.ntioctl.in.blob = data_blob(NULL, 0);
|
||||
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
printf("Server supports batch oplock upgrades on open files\n");
|
||||
} else {
|
||||
printf("Server does not support batch oplock upgrades on open files\n");
|
||||
}
|
||||
|
||||
printf("Trying bad handle\n");
|
||||
nt.ntioctl.in.file.fnum = fnum+1;
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
#if 0
|
||||
nt.ntioctl.in.file.fnum = fnum;
|
||||
for (i=0;i<100;i++) {
|
||||
nt.ntioctl.in.function = FSCTL_FILESYSTEM + (i<<2);
|
||||
status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
|
||||
printf("filesystem fsctl 0x%x - %s\n",
|
||||
i, nt_errstr(status));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
basic testing of some ioctl calls
|
||||
*/
|
||||
BOOL torture_raw_ioctl(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_ioctl");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!test_ioctl(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_fsctl(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
locking benchmark
|
||||
|
||||
Copyright (C) Andrew Tridgell 2006
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/cmdline/popt_common.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)); \
|
||||
goto failed; \
|
||||
}} while (0)
|
||||
|
||||
#define BASEDIR "\\benchlock"
|
||||
#define FNAME BASEDIR "\\lock.dat"
|
||||
|
||||
static int nprocs;
|
||||
static int lock_failed;
|
||||
|
||||
struct benchlock_state {
|
||||
struct smbcli_state *cli;
|
||||
int fnum;
|
||||
int offset;
|
||||
int count;
|
||||
union smb_lock io;
|
||||
struct smb_lock_entry lock[2];
|
||||
struct smbcli_request *req;
|
||||
};
|
||||
|
||||
static void lock_completion(struct smbcli_request *);
|
||||
|
||||
/*
|
||||
send the next lock request
|
||||
*/
|
||||
static void lock_send(struct benchlock_state *state)
|
||||
{
|
||||
state->io.lockx.in.file.fnum = state->fnum;
|
||||
state->io.lockx.in.ulock_cnt = 1;
|
||||
state->lock[0].pid = state->cli->session->pid;
|
||||
state->lock[1].pid = state->cli->session->pid;
|
||||
state->lock[0].offset = state->offset;
|
||||
state->lock[1].offset = (state->offset+1)%nprocs;
|
||||
state->req = smb_raw_lock_send(state->cli->tree, &state->io);
|
||||
if (state->req == NULL) {
|
||||
DEBUG(0,("Failed to setup lock\n"));
|
||||
lock_failed++;
|
||||
}
|
||||
state->req->async.private = state;
|
||||
state->req->async.fn = lock_completion;
|
||||
state->offset = (state->offset+1)%nprocs;
|
||||
}
|
||||
|
||||
/*
|
||||
called when a lock completes
|
||||
*/
|
||||
static void lock_completion(struct smbcli_request *req)
|
||||
{
|
||||
struct benchlock_state *state = (struct benchlock_state *)req->async.private;
|
||||
NTSTATUS status = smbcli_request_simple_recv(req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
lock_failed++;
|
||||
DEBUG(0,("Lock failed - %s\n", nt_errstr(status)));
|
||||
} else {
|
||||
state->count++;
|
||||
lock_send(state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
benchmark locking calls
|
||||
*/
|
||||
BOOL torture_bench_lock(struct torture_context *torture)
|
||||
{
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx = talloc_new(torture);
|
||||
int i;
|
||||
int timelimit = torture_setting_int(torture, "timelimit", 10);
|
||||
struct timeval tv;
|
||||
struct event_context *ev = event_context_find(mem_ctx);
|
||||
struct benchlock_state *state;
|
||||
int total = 0, loops=0;
|
||||
NTSTATUS status;
|
||||
|
||||
nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
|
||||
|
||||
state = talloc_zero_array(mem_ctx, struct benchlock_state, nprocs);
|
||||
|
||||
printf("Opening %d connections\n", nprocs);
|
||||
for (i=0;i<nprocs;i++) {
|
||||
if (!torture_open_connection_ev(&state[i].cli, i, ev)) {
|
||||
return False;
|
||||
}
|
||||
talloc_steal(mem_ctx, state);
|
||||
}
|
||||
|
||||
if (!torture_setup_dir(state[0].cli, BASEDIR)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i=0;i<nprocs;i++) {
|
||||
state[i].fnum = smbcli_open(state[i].cli->tree,
|
||||
FNAME,
|
||||
O_RDWR|O_CREAT, DENY_NONE);
|
||||
if (state[i].fnum == -1) {
|
||||
printf("Failed to open %s on connection %d\n", FNAME, i);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
state[i].io.lockx.level = RAW_LOCK_LOCKX;
|
||||
state[i].io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
|
||||
state[i].io.lockx.in.timeout = 100000;
|
||||
state[i].io.lockx.in.ulock_cnt = 0;
|
||||
state[i].io.lockx.in.lock_cnt = 1;
|
||||
state[i].lock[0].count = 1;
|
||||
state[i].lock[1].count = 1;
|
||||
state[i].io.lockx.in.locks = &state[i].lock[0];
|
||||
|
||||
state[i].offset = i;
|
||||
state[i].io.lockx.in.file.fnum = state[i].fnum;
|
||||
state[i].lock[0].offset = state[i].offset;
|
||||
state[i].lock[0].pid = state[i].cli->session->pid;
|
||||
status = smb_raw_lock(state[i].cli->tree, &state[i].io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
}
|
||||
|
||||
for (i=0;i<nprocs;i++) {
|
||||
lock_send(&state[i]);
|
||||
}
|
||||
|
||||
tv = timeval_current();
|
||||
|
||||
printf("Running for %d seconds\n", timelimit);
|
||||
while (timeval_elapsed(&tv) < timelimit) {
|
||||
event_loop_once(ev);
|
||||
|
||||
if (lock_failed) {
|
||||
DEBUG(0,("locking failed\n"));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (loops++ % 10 != 0) continue;
|
||||
|
||||
total = 0;
|
||||
for (i=0;i<nprocs;i++) {
|
||||
total += state[i].count;
|
||||
}
|
||||
printf("%.2f ops/second\r", total/timeval_elapsed(&tv));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
printf("%.2f ops/second\n", total/timeval_elapsed(&tv));
|
||||
|
||||
for (i=0;i<nprocs;i++) {
|
||||
talloc_free(state[i].req);
|
||||
smb_raw_exit(state[i].cli->session);
|
||||
}
|
||||
|
||||
smbcli_deltree(state[0].cli->tree, BASEDIR);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
|
||||
failed:
|
||||
for (i=0;i<nprocs;i++) {
|
||||
talloc_free(state[i].req);
|
||||
smb_raw_exit(state[i].cli->session);
|
||||
}
|
||||
smbcli_deltree(state[0].cli->tree, BASEDIR);
|
||||
talloc_free(mem_ctx);
|
||||
return False;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
- RAW-CONTEXT passes on nt4 but TCON doesn't !!??
|
||||
|
||||
- all messaging commands
|
||||
|
||||
- writebraw
|
||||
|
||||
- writebmpx
|
||||
|
||||
- acl ops
|
||||
|
||||
- readbmpx
|
||||
|
||||
- rap commands
|
||||
|
||||
- rpc commands
|
||||
|
||||
- SMBcopy
|
||||
|
||||
- SMBtcon
|
||||
|
||||
- SMBecho
|
||||
|
||||
- SMBfunique
|
||||
|
||||
- SMBsearch vs SMBffirst?
|
||||
|
||||
- SMBfclose
|
||||
|
||||
- SMBkeepalive
|
||||
|
||||
- secondary trans2 and nttrans
|
||||
|
||||
- trans2 ioctl
|
||||
|
||||
- trans2 session setup
|
||||
|
||||
- trans2 DFS ops
|
||||
|
||||
- unix ops
|
||||
|
||||
--------------
|
||||
done:
|
||||
|
||||
mkdir
|
||||
rmdir
|
||||
open
|
||||
create
|
||||
close
|
||||
flush
|
||||
unlink
|
||||
mv
|
||||
getatr
|
||||
setatr
|
||||
read
|
||||
write
|
||||
lock
|
||||
unlock
|
||||
ctemp
|
||||
mknew
|
||||
chkpath
|
||||
exit
|
||||
lseek
|
||||
tconX
|
||||
tdis
|
||||
negprot
|
||||
dskattr
|
||||
search
|
||||
lockread
|
||||
writeunlock
|
||||
readbraw
|
||||
setattrE
|
||||
getattrE
|
||||
lockingX
|
||||
ioctl
|
||||
openX
|
||||
readX
|
||||
writeX
|
||||
sesssetupX
|
||||
trans2
|
||||
findclose
|
||||
ulogoffX
|
||||
nttrans
|
||||
ntcreateX
|
||||
ntcancel
|
||||
trans2_open
|
||||
trans2_findfirst
|
||||
trans2_findnext?
|
||||
trans2_qfsinfo
|
||||
trans2_setfsinfo
|
||||
trans2_qpathinfo
|
||||
trans2_setpathinfo
|
||||
trans2_qfileinfo
|
||||
trans2_setfileinfo
|
||||
trans2_fsctl
|
||||
trans2_mkdir
|
||||
trans2_findnext
|
||||
NTrename
|
||||
SMB_QFS_ALLOCATION
|
||||
SMB_QFS_VOLUME
|
||||
SMB_QFS_VOLUME_INFO
|
||||
SMB_QFS_SIZE_INFO
|
||||
SMB_QFS_DEVICE_INFO
|
||||
SMB_QFS_ATTRIBUTE_INFO
|
||||
SMB_QFS_VOLUME_INFORMATION
|
||||
SMB_QFS_SIZE_INFORMATION
|
||||
SMB_QFS_DEVICE_INFORMATION
|
||||
SMB_QFS_ATTRIBUTE_INFORMATION
|
||||
SMB_QFS_QUOTA_INFORMATION
|
||||
SMB_QFS_FULL_SIZE_INFORMATION
|
||||
SMB_QFS_OBJECTID_INFORMATION
|
||||
SMB_QFILEINFO_STANDARD
|
||||
SMB_QFILEINFO_EA_SIZE
|
||||
SMB_QFILEINFO_ALL_EAS
|
||||
SMB_QFILEINFO_IS_NAME_VALID
|
||||
SMB_QFILEINFO_BASIC_INFO
|
||||
SMB_QFILEINFO_STANDARD_INFO
|
||||
SMB_QFILEINFO_EA_INFO
|
||||
SMB_QFILEINFO_NAME_INFO
|
||||
SMB_QFILEINFO_ALL_INFO
|
||||
SMB_QFILEINFO_ALT_NAME_INFO
|
||||
SMB_QFILEINFO_STREAM_INFO
|
||||
SMB_QFILEINFO_COMPRESSION_INFO
|
||||
SMB_QFILEINFO_BASIC_INFORMATION
|
||||
SMB_QFILEINFO_STANDARD_INFORMATION
|
||||
SMB_QFILEINFO_INTERNAL_INFORMATION
|
||||
SMB_QFILEINFO_EA_INFORMATION
|
||||
SMB_QFILEINFO_ACCESS_INFORMATION
|
||||
SMB_QFILEINFO_NAME_INFORMATION
|
||||
SMB_QFILEINFO_POSITION_INFORMATION
|
||||
SMB_QFILEINFO_MODE_INFORMATION
|
||||
SMB_QFILEINFO_ALIGNMENT_INFORMATION
|
||||
SMB_QFILEINFO_ALL_INFORMATION
|
||||
SMB_QFILEINFO_ALT_NAME_INFORMATION
|
||||
SMB_QFILEINFO_STREAM_INFORMATION
|
||||
SMB_QFILEINFO_COMPRESSION_INFORMATION
|
||||
SMB_QFILEINFO_NETWORK_OPEN_INFORMATION
|
||||
SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION
|
||||
SMB_SFILEINFO_STANDARD
|
||||
SMB_SFILEINFO_EA_SET
|
||||
SMB_SFILEINFO_BASIC_INFO
|
||||
SMB_SFILEINFO_DISPOSITION_INFO
|
||||
SMB_SFILEINFO_ALLOCATION_INFO
|
||||
SMB_SFILEINFO_END_OF_FILE_INFO
|
||||
SMB_SFILEINFO_UNIX_BASIC
|
||||
SMB_SFILEINFO_UNIX_LINK
|
||||
SMB_SFILEINFO_BASIC_INFORMATION
|
||||
SMB_SFILEINFO_RENAME_INFORMATION
|
||||
SMB_SFILEINFO_DISPOSITION_INFORMATION
|
||||
SMB_SFILEINFO_POSITION_INFORMATION
|
||||
SMB_SFILEINFO_MODE_INFORMATION
|
||||
SMB_SFILEINFO_ALLOCATION_INFORMATION
|
||||
SMB_SFILEINFO_END_OF_FILE_INFORMATION
|
||||
SMB_FIND_STANDARD
|
||||
SMB_FIND_EA_SIZE
|
||||
SMB_FIND_DIRECTORY_INFO
|
||||
SMB_FIND_FULL_DIRECTORY_INFO
|
||||
SMB_FIND_NAME_INFO
|
||||
SMB_FIND_BOTH_DIRECTORY_INFO
|
||||
SMB_FIND_261
|
||||
SMB_FIND_262
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_MKDIR_* and RAW_RMDIR_* individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\mkdirtest"
|
||||
|
||||
#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)
|
||||
|
||||
/*
|
||||
test mkdir ops
|
||||
*/
|
||||
static BOOL test_mkdir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_mkdir md;
|
||||
struct smb_rmdir rd;
|
||||
const char *path = BASEDIR "\\mkdir.dir";
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
basic mkdir
|
||||
*/
|
||||
md.mkdir.level = RAW_MKDIR_MKDIR;
|
||||
md.mkdir.in.path = path;
|
||||
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("testing mkdir collision\n");
|
||||
|
||||
/* 2nd create */
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
|
||||
|
||||
/* basic rmdir */
|
||||
rd.in.path = path;
|
||||
status = smb_raw_rmdir(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
printf("testing mkdir collision with file\n");
|
||||
|
||||
/* name collision with a file */
|
||||
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, path));
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
|
||||
|
||||
printf("testing rmdir with file\n");
|
||||
|
||||
/* delete a file with rmdir */
|
||||
status = smb_raw_rmdir(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
|
||||
|
||||
smbcli_unlink(cli->tree, path);
|
||||
|
||||
printf("testing invalid dir\n");
|
||||
|
||||
/* create an invalid dir */
|
||||
md.mkdir.in.path = "..\\..\\..";
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
|
||||
printf("testing t2mkdir\n");
|
||||
|
||||
/* try a t2mkdir - need to work out why this fails! */
|
||||
md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
|
||||
md.t2mkdir.in.path = path;
|
||||
md.t2mkdir.in.num_eas = 0;
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("testing t2mkdir with EAs\n");
|
||||
|
||||
/* with EAs */
|
||||
md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
|
||||
md.t2mkdir.in.path = path;
|
||||
md.t2mkdir.in.num_eas = 3;
|
||||
md.t2mkdir.in.eas = talloc_array(mem_ctx, struct ea_struct, md.t2mkdir.in.num_eas);
|
||||
md.t2mkdir.in.eas[0].flags = 0;
|
||||
md.t2mkdir.in.eas[0].name.s = "EAONE";
|
||||
md.t2mkdir.in.eas[0].value = data_blob_talloc(mem_ctx, "blah", 4);
|
||||
md.t2mkdir.in.eas[1].flags = 0;
|
||||
md.t2mkdir.in.eas[1].name.s = "EA TWO";
|
||||
md.t2mkdir.in.eas[1].value = data_blob_talloc(mem_ctx, "foo bar", 7);
|
||||
md.t2mkdir.in.eas[2].flags = 0;
|
||||
md.t2mkdir.in.eas[2].name.s = "EATHREE";
|
||||
md.t2mkdir.in.eas[2].value = data_blob_talloc(mem_ctx, "xx1", 3);
|
||||
status = smb_raw_mkdir(cli->tree, &md);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = torture_check_ea(cli, path, "EAONE", "blah");
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
status = torture_check_ea(cli, path, "EA TWO", "foo bar");
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
status = torture_check_ea(cli, path, "EATHREE", "xx1");
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of all RAW_MKDIR_* calls
|
||||
*/
|
||||
BOOL torture_raw_mkdir(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_mkdir");
|
||||
|
||||
if (!test_mkdir(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
basic raw test suite for multiplexing
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\test_mux"
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
/*
|
||||
test the delayed reply to a open that leads to a sharing violation
|
||||
*/
|
||||
static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_open io;
|
||||
NTSTATUS status;
|
||||
int fnum1, fnum2;
|
||||
BOOL ret = True;
|
||||
struct smbcli_request *req1, *req2;
|
||||
struct timeval tv;
|
||||
double d;
|
||||
|
||||
printf("testing multiplexed open/open/close\n");
|
||||
|
||||
printf("send first open\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = BASEDIR "\\open.dat";
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum1 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("send 2nd open, non-conflicting\n");
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
|
||||
tv = timeval_current();
|
||||
|
||||
printf("send 3rd open, conflicting\n");
|
||||
io.ntcreatex.in.share_access = 0;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
d = timeval_elapsed(&tv);
|
||||
if (d < 0.5 || d > 1.5) {
|
||||
printf("bad timeout for conflict - %.2f should be 1.0\n", d);
|
||||
} else {
|
||||
printf("open delay %.2f\n", d);
|
||||
}
|
||||
|
||||
printf("send async open, conflicting\n");
|
||||
tv = timeval_current();
|
||||
req1 = smb_raw_open_send(cli->tree, &io);
|
||||
|
||||
printf("send 2nd async open, conflicting\n");
|
||||
tv = timeval_current();
|
||||
req2 = smb_raw_open_send(cli->tree, &io);
|
||||
|
||||
printf("close first sync open\n");
|
||||
smbcli_close(cli->tree, fnum1);
|
||||
|
||||
printf("cancel 2nd async open (should be ignored)\n");
|
||||
smb_raw_ntcancel(req2);
|
||||
|
||||
d = timeval_elapsed(&tv);
|
||||
if (d > 0.25) {
|
||||
printf("bad timeout after cancel - %.2f should be <0.25\n", d);
|
||||
ret = False;
|
||||
}
|
||||
|
||||
printf("close the 2nd sync open\n");
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
printf("see if the 1st async open now succeeded\n");
|
||||
status = smb_raw_open_recv(req1, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
d = timeval_elapsed(&tv);
|
||||
if (d > 0.25) {
|
||||
printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
|
||||
ret = False;
|
||||
} else {
|
||||
printf("async open delay %.2f\n", d);
|
||||
}
|
||||
|
||||
printf("2nd async open should have timed out\n");
|
||||
status = smb_raw_open_recv(req2, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
d = timeval_elapsed(&tv);
|
||||
if (d < 0.8) {
|
||||
printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
|
||||
}
|
||||
|
||||
printf("close the 1st async open\n");
|
||||
smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test a write that hits a byte range lock and send the close after the write
|
||||
*/
|
||||
static BOOL test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_write io;
|
||||
NTSTATUS status;
|
||||
int fnum;
|
||||
BOOL ret = True;
|
||||
struct smbcli_request *req;
|
||||
|
||||
printf("testing multiplexed lock/write/close\n");
|
||||
|
||||
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cli->session->pid = 1;
|
||||
|
||||
/* lock a range */
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK))) {
|
||||
printf("lock failed in mux_write - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cli->session->pid = 2;
|
||||
|
||||
/* send an async write */
|
||||
io.generic.level = RAW_WRITE_WRITEX;
|
||||
io.writex.in.file.fnum = fnum;
|
||||
io.writex.in.offset = 0;
|
||||
io.writex.in.wmode = 0;
|
||||
io.writex.in.remaining = 0;
|
||||
io.writex.in.count = 4;
|
||||
io.writex.in.data = (void *)&fnum;
|
||||
req = smb_raw_write_send(cli->tree, &io);
|
||||
|
||||
/* unlock the range */
|
||||
cli->session->pid = 1;
|
||||
smbcli_unlock(cli->tree, fnum, 0, 4);
|
||||
|
||||
/* and recv the async write reply */
|
||||
status = smb_raw_write_recv(req, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test a lock that conflicts with an existing lock
|
||||
*/
|
||||
static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_lock io;
|
||||
NTSTATUS status;
|
||||
int fnum;
|
||||
BOOL ret = True;
|
||||
struct smbcli_request *req;
|
||||
struct smb_lock_entry lock[1];
|
||||
|
||||
printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
|
||||
|
||||
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("establishing a lock\n");
|
||||
io.lockx.level = RAW_LOCK_LOCKX;
|
||||
io.lockx.in.file.fnum = fnum;
|
||||
io.lockx.in.mode = 0;
|
||||
io.lockx.in.timeout = 0;
|
||||
io.lockx.in.lock_cnt = 1;
|
||||
io.lockx.in.ulock_cnt = 0;
|
||||
lock[0].pid = 1;
|
||||
lock[0].offset = 0;
|
||||
lock[0].count = 4;
|
||||
io.lockx.in.locks = &lock[0];
|
||||
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("the second lock will conflict with the first\n");
|
||||
lock[0].pid = 2;
|
||||
io.lockx.in.timeout = 1000;
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
printf("this will too, but we'll unlock while waiting\n");
|
||||
req = smb_raw_lock_send(cli->tree, &io);
|
||||
|
||||
printf("unlock the first range\n");
|
||||
lock[0].pid = 1;
|
||||
io.lockx.in.ulock_cnt = 1;
|
||||
io.lockx.in.lock_cnt = 0;
|
||||
io.lockx.in.timeout = 0;
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("recv the async reply\n");
|
||||
status = smbcli_request_simple_recv(req);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("reopening with an exit\n");
|
||||
smb_raw_exit(cli->session);
|
||||
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
|
||||
|
||||
printf("Now trying with a cancel\n");
|
||||
|
||||
io.lockx.level = RAW_LOCK_LOCKX;
|
||||
io.lockx.in.file.fnum = fnum;
|
||||
io.lockx.in.mode = 0;
|
||||
io.lockx.in.timeout = 0;
|
||||
io.lockx.in.lock_cnt = 1;
|
||||
io.lockx.in.ulock_cnt = 0;
|
||||
lock[0].pid = 1;
|
||||
lock[0].offset = 0;
|
||||
lock[0].count = 4;
|
||||
io.lockx.in.locks = &lock[0];
|
||||
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
lock[0].pid = 2;
|
||||
io.lockx.in.timeout = 1000;
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
req = smb_raw_lock_send(cli->tree, &io);
|
||||
|
||||
/* cancel the blocking lock */
|
||||
smb_raw_ntcancel(req);
|
||||
|
||||
/* the 2nd cancel is totally harmless, but tests the server trying to
|
||||
cancel an already cancelled request */
|
||||
smb_raw_ntcancel(req);
|
||||
|
||||
lock[0].pid = 1;
|
||||
io.lockx.in.ulock_cnt = 1;
|
||||
io.lockx.in.lock_cnt = 0;
|
||||
io.lockx.in.timeout = 0;
|
||||
status = smb_raw_lock(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smbcli_request_simple_recv(req);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
basic testing of multiplexing notify
|
||||
*/
|
||||
BOOL torture_raw_mux(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_mux");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!test_mux_open(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_mux_write(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_mux_lock(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
basic raw test suite for oplocks
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "librpc/gen_ndr/security.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
#include "lib/events/events.h"
|
||||
|
||||
#define CHECK_VAL(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%d) wrong value for %s got 0x%x - should be 0x%x\n", \
|
||||
__LINE__, #v, (int)v, (int)correct); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_STATUS(status, correct) do { \
|
||||
if (!NT_STATUS_EQUAL(status, correct)) { \
|
||||
printf("(%d) Incorrect status %s - should be %s\n", \
|
||||
__LINE__, nt_errstr(status), nt_errstr(correct)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
|
||||
static struct {
|
||||
int fnum;
|
||||
uint8_t level;
|
||||
int count;
|
||||
int failures;
|
||||
} break_info;
|
||||
|
||||
#define BASEDIR "\\test_notify"
|
||||
|
||||
/*
|
||||
a handler function for oplock break requests. Ack it as a break to level II if possible
|
||||
*/
|
||||
static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid,
|
||||
uint16_t fnum, uint8_t level, void *private)
|
||||
{
|
||||
struct smbcli_tree *tree = private;
|
||||
break_info.fnum = fnum;
|
||||
break_info.level = level;
|
||||
break_info.count++;
|
||||
|
||||
printf("Acking to level II in oplock handler\n");
|
||||
|
||||
return smbcli_oplock_ack(tree, fnum, level);
|
||||
}
|
||||
|
||||
/*
|
||||
a handler function for oplock break requests. Ack it as a break to none
|
||||
*/
|
||||
static BOOL oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid,
|
||||
uint16_t fnum, uint8_t level,
|
||||
void *private)
|
||||
{
|
||||
struct smbcli_tree *tree = private;
|
||||
break_info.fnum = fnum;
|
||||
break_info.level = level;
|
||||
break_info.count++;
|
||||
|
||||
printf("Acking to none in oplock handler\n");
|
||||
|
||||
return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
|
||||
}
|
||||
|
||||
static void oplock_handler_close_recv(struct smbcli_request *req)
|
||||
{
|
||||
NTSTATUS status;
|
||||
status = smbcli_request_simple_recv(req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("close failed in oplock_handler_close\n");
|
||||
break_info.failures++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
a handler function for oplock break requests - close the file
|
||||
*/
|
||||
static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid,
|
||||
uint16_t fnum, uint8_t level, void *private)
|
||||
{
|
||||
union smb_close io;
|
||||
struct smbcli_tree *tree = private;
|
||||
struct smbcli_request *req;
|
||||
|
||||
break_info.fnum = fnum;
|
||||
break_info.level = level;
|
||||
break_info.count++;
|
||||
|
||||
io.close.level = RAW_CLOSE_CLOSE;
|
||||
io.close.in.file.fnum = fnum;
|
||||
io.close.in.write_time = 0;
|
||||
req = smb_raw_close_send(tree, &io);
|
||||
if (req == NULL) {
|
||||
printf("failed to send close in oplock_handler_close\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
req->async.fn = oplock_handler_close_recv;
|
||||
req->async.private = NULL;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test oplock ops
|
||||
*/
|
||||
static BOOL test_oplock(struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
const char *fname = BASEDIR "\\test_oplock.dat";
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
union smb_open io;
|
||||
union smb_unlink unl;
|
||||
union smb_read rd;
|
||||
union smb_setfileinfo sfi;
|
||||
uint16_t fnum=0, fnum2=0;
|
||||
char c = 0;
|
||||
|
||||
/* cleanup */
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
/*
|
||||
base ntcreatex parms
|
||||
*/
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
|
||||
printf("open a file with a normal oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
|
||||
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
|
||||
|
||||
printf("a 2nd open should not cause a break\n");
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
printf("unlink it - should also be no break\n");
|
||||
unl.unlink.in.pattern = fname;
|
||||
unl.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
|
||||
/*
|
||||
with a batch oplock we get a break
|
||||
*/
|
||||
printf("open with batch oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
printf("unlink should generate a break\n");
|
||||
unl.unlink.in.pattern = fname;
|
||||
unl.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
printf("2nd unlink should not generate a break\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
|
||||
printf("writing should generate a self break to none\n");
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
|
||||
msleep(100);
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
|
||||
|
||||
printf("open with batch oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
printf("unlink should generate a break, which we ack as break to none\n");
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
|
||||
unl.unlink.in.pattern = fname;
|
||||
unl.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
printf("2nd unlink should not generate a break\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
|
||||
printf("writing should not generate a break\n");
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
|
||||
msleep(100);
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
|
||||
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
|
||||
printf("if we close on break then the unlink can succeed\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
unl.unlink.in.pattern = fname;
|
||||
unl.unlink.in.attrib = 0;
|
||||
ZERO_STRUCT(break_info);
|
||||
status = smb_raw_unlink(cli2->tree, &unl);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
printf("a self read should not cause a break\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
rd.read.level = RAW_READ_READ;
|
||||
rd.read.in.file.fnum = fnum;
|
||||
rd.read.in.count = 1;
|
||||
rd.read.in.offset = 0;
|
||||
rd.read.in.remaining = 0;
|
||||
status = smb_raw_read(cli1->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
printf("a 2nd open should give a break\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
|
||||
printf("a 2nd open should give a break to level II if the first open allowed shared read\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
|
||||
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.level, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
printf("write should trigger a break to none on both\n");
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
|
||||
msleep(100);
|
||||
smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
|
||||
|
||||
CHECK_VAL(break_info.count, 2);
|
||||
CHECK_VAL(break_info.level, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
|
||||
printf("a 2nd open should get an oplock when we close instead of ack\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum2);
|
||||
CHECK_VAL(break_info.level, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli2->tree, fnum);
|
||||
|
||||
printf("open with batch oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
printf("second open with attributes only shouldn't cause oplock break\n");
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
printf("open with attributes only can create file\n");
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
printf("Subsequent normal open should break oplock on attribute only open to level II\n");
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
|
||||
printf("third oplocked open should grant level2 without break\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
printf("write should trigger a break to none on both\n");
|
||||
smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
|
||||
|
||||
/* Now the oplock break request comes in. But right now we can't
|
||||
* answer it. Do another write */
|
||||
|
||||
msleep(100);
|
||||
smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
|
||||
|
||||
CHECK_VAL(break_info.count, 2);
|
||||
CHECK_VAL(break_info.level, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
printf("Open with oplock after a on-oplock open should grant level2\n");
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE|
|
||||
NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE|
|
||||
NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
|
||||
printf("write should trigger a break to none\n");
|
||||
{
|
||||
union smb_write wr;
|
||||
wr.write.level = RAW_WRITE_WRITE;
|
||||
wr.write.in.file.fnum = fnum;
|
||||
wr.write.in.count = 1;
|
||||
wr.write.in.offset = 0;
|
||||
wr.write.in.remaining = 0;
|
||||
wr.write.in.data = (const uint8_t *)"x";
|
||||
status = smb_raw_write(cli1->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
}
|
||||
|
||||
/* Now the oplock break request comes in. But right now we can't
|
||||
* answer it. Do another write */
|
||||
|
||||
msleep(100);
|
||||
|
||||
{
|
||||
union smb_write wr;
|
||||
wr.write.level = RAW_WRITE_WRITE;
|
||||
wr.write.in.file.fnum = fnum;
|
||||
wr.write.in.count = 1;
|
||||
wr.write.in.offset = 0;
|
||||
wr.write.in.remaining = 0;
|
||||
wr.write.in.data = (const uint8_t *)"x";
|
||||
status = smb_raw_write(cli1->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
}
|
||||
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.fnum, fnum2);
|
||||
CHECK_VAL(break_info.level, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
/* Test if a set-eof on pathname breaks an exclusive oplock. */
|
||||
printf("Test if setpathinfo set EOF breaks oplocks.\n");
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE|
|
||||
NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(sfi);
|
||||
sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
|
||||
sfi.generic.in.file.path = fname;
|
||||
sfi.end_of_file_info.in.size = 100;
|
||||
|
||||
status = smb_raw_setpathinfo(cli2->tree, &sfi);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(break_info.level, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
/* Test if a set-allocation size on pathname breaks an exclusive oplock. */
|
||||
printf("Test if setpathinfo allocation size breaks oplocks.\n");
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE|
|
||||
NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(break_info.count, 0);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(sfi);
|
||||
sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
|
||||
sfi.generic.in.file.path = fname;
|
||||
sfi.allocation_info.in.alloc_size = 65536 * 8;
|
||||
|
||||
status = smb_raw_setpathinfo(cli2->tree, &sfi);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
CHECK_VAL(break_info.level, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
printf("open with batch oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
printf("second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
printf("open with batch oplock\n");
|
||||
ZERO_STRUCT(break_info);
|
||||
smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
status = smb_raw_open(cli1->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
|
||||
|
||||
ZERO_STRUCT(break_info);
|
||||
|
||||
printf("second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
|
||||
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
|
||||
status = smb_raw_open(cli2->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = io.ntcreatex.out.file.fnum;
|
||||
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
|
||||
CHECK_VAL(break_info.count, 1);
|
||||
CHECK_VAL(break_info.failures, 0);
|
||||
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
|
||||
|
||||
done:
|
||||
smbcli_close(cli1->tree, fnum);
|
||||
smbcli_close(cli2->tree, fnum2);
|
||||
smbcli_unlink(cli1->tree, fname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of oplocks
|
||||
*/
|
||||
BOOL torture_raw_oplock(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli1, *cli2;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli1, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!torture_open_connection_ev(
|
||||
&cli2, 1, cli1->transport->socket->event.ctx)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!torture_setup_dir(cli1, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_oplock");
|
||||
|
||||
if (!test_oplock(cli1, cli2, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
smb_raw_exit(cli1->session);
|
||||
smbcli_deltree(cli1->tree, BASEDIR);
|
||||
torture_close_connection(cli1);
|
||||
torture_close_connection(cli2);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
stress testing of oplocks
|
||||
*/
|
||||
BOOL torture_bench_oplock(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state **cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx = talloc_new(torture);
|
||||
int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
|
||||
int i, count=0;
|
||||
int timelimit = torture_setting_int(torture, "timelimit", 10);
|
||||
union smb_open io;
|
||||
struct timeval tv;
|
||||
struct event_context *ev = event_context_find(mem_ctx);
|
||||
|
||||
cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
|
||||
|
||||
printf("Opening %d connections\n", torture_nprocs);
|
||||
for (i=0;i<torture_nprocs;i++) {
|
||||
if (!torture_open_connection_ev(&cli[i], i, ev)) {
|
||||
return False;
|
||||
}
|
||||
talloc_steal(mem_ctx, cli[i]);
|
||||
smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
|
||||
cli[i]->tree);
|
||||
}
|
||||
|
||||
if (!torture_setup_dir(cli[0], BASEDIR)) {
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
io.ntcreatex.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = BASEDIR "\\test.dat";
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
|
||||
NTCREATEX_FLAGS_REQUEST_OPLOCK |
|
||||
NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
|
||||
|
||||
tv = timeval_current();
|
||||
|
||||
/*
|
||||
we open the same file with SHARE_ACCESS_NONE from all the
|
||||
connections in a round robin fashion. Each open causes an
|
||||
oplock break on the previous connection, which is answered
|
||||
by the oplock_handler_close() to close the file.
|
||||
|
||||
This measures how fast we can pass on oplocks, and stresses
|
||||
the oplock handling code
|
||||
*/
|
||||
printf("Running for %d seconds\n", timelimit);
|
||||
while (timeval_elapsed(&tv) < timelimit) {
|
||||
for (i=0;i<torture_nprocs;i++) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
count++;
|
||||
}
|
||||
printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
|
||||
}
|
||||
|
||||
printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
|
||||
|
||||
smb_raw_exit(cli[torture_nprocs-1]->session);
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli[0]->session);
|
||||
smbcli_deltree(cli[0]->tree, BASEDIR);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_FILEINFO_* individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
enum smb_fileinfo_level level;
|
||||
uint_t only_paths:1;
|
||||
uint_t only_handles:1;
|
||||
uint32_t capability_mask;
|
||||
NTSTATUS fnum_status, fname_status;
|
||||
union smb_fileinfo fnum_finfo, fname_finfo;
|
||||
} levels[] = {
|
||||
{ "GETATTR", RAW_FILEINFO_GETATTR, 1, 0, },
|
||||
{ "GETATTRE", RAW_FILEINFO_GETATTRE, 0, 1, },
|
||||
{ "STANDARD", RAW_FILEINFO_STANDARD, },
|
||||
{ "EA_SIZE", RAW_FILEINFO_EA_SIZE, },
|
||||
{ "ALL_EAS", RAW_FILEINFO_ALL_EAS, },
|
||||
{ "IS_NAME_VALID", RAW_FILEINFO_IS_NAME_VALID, 1, 0, },
|
||||
{ "BASIC_INFO", RAW_FILEINFO_BASIC_INFO, },
|
||||
{ "STANDARD_INFO", RAW_FILEINFO_STANDARD_INFO, },
|
||||
{ "EA_INFO", RAW_FILEINFO_EA_INFO, },
|
||||
{ "NAME_INFO", RAW_FILEINFO_NAME_INFO, },
|
||||
{ "ALL_INFO", RAW_FILEINFO_ALL_INFO, },
|
||||
{ "ALT_NAME_INFO", RAW_FILEINFO_ALT_NAME_INFO, },
|
||||
{ "STREAM_INFO", RAW_FILEINFO_STREAM_INFO, },
|
||||
{ "COMPRESSION_INFO", RAW_FILEINFO_COMPRESSION_INFO, },
|
||||
{ "UNIX_BASIC_INFO", RAW_FILEINFO_UNIX_BASIC, 0, 0, CAP_UNIX},
|
||||
{ "UNIX_LINK_INFO", RAW_FILEINFO_UNIX_LINK, 0, 0, CAP_UNIX},
|
||||
{ "BASIC_INFORMATION", RAW_FILEINFO_BASIC_INFORMATION, },
|
||||
{ "STANDARD_INFORMATION", RAW_FILEINFO_STANDARD_INFORMATION, },
|
||||
{ "INTERNAL_INFORMATION", RAW_FILEINFO_INTERNAL_INFORMATION, },
|
||||
{ "EA_INFORMATION", RAW_FILEINFO_EA_INFORMATION, },
|
||||
{ "ACCESS_INFORMATION", RAW_FILEINFO_ACCESS_INFORMATION, },
|
||||
{ "NAME_INFORMATION", RAW_FILEINFO_NAME_INFORMATION, },
|
||||
{ "POSITION_INFORMATION", RAW_FILEINFO_POSITION_INFORMATION, },
|
||||
{ "MODE_INFORMATION", RAW_FILEINFO_MODE_INFORMATION, },
|
||||
{ "ALIGNMENT_INFORMATION", RAW_FILEINFO_ALIGNMENT_INFORMATION, },
|
||||
{ "ALL_INFORMATION", RAW_FILEINFO_ALL_INFORMATION, },
|
||||
{ "ALT_NAME_INFORMATION", RAW_FILEINFO_ALT_NAME_INFORMATION, },
|
||||
{ "STREAM_INFORMATION", RAW_FILEINFO_STREAM_INFORMATION, },
|
||||
{ "COMPRESSION_INFORMATION", RAW_FILEINFO_COMPRESSION_INFORMATION, },
|
||||
{ "NETWORK_OPEN_INFORMATION", RAW_FILEINFO_NETWORK_OPEN_INFORMATION, },
|
||||
{ "ATTRIBUTE_TAG_INFORMATION", RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, },
|
||||
{ NULL, }
|
||||
};
|
||||
|
||||
/*
|
||||
compare a dos time (2 second resolution) to a nt time
|
||||
*/
|
||||
static int dos_nt_time_cmp(time_t t, NTTIME nt)
|
||||
{
|
||||
time_t t2 = nt_time_to_unix(nt);
|
||||
if (abs(t2 - t) <= 2) return 0;
|
||||
return t2 - t;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
find a level in the levels[] table
|
||||
*/
|
||||
static union smb_fileinfo *fnum_find(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; levels[i].name; i++) {
|
||||
if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
|
||||
strcmp(name, levels[i].name) == 0 &&
|
||||
!levels[i].only_paths) {
|
||||
return &levels[i].fnum_finfo;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
find a level in the levels[] table
|
||||
*/
|
||||
static union smb_fileinfo *fname_find(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; levels[i].name; i++) {
|
||||
if (NT_STATUS_IS_OK(levels[i].fname_status) &&
|
||||
strcmp(name, levels[i].name) == 0 &&
|
||||
!levels[i].only_handles) {
|
||||
return &levels[i].fname_finfo;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* local macros to make the code below more readable */
|
||||
#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
|
||||
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
|
||||
#n1, #v1, (uint_t)s1->n1.out.v1, \
|
||||
#n2, #v2, (uint_t)s2->n2.out.v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
#define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
|
||||
s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
|
||||
printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
|
||||
#n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
|
||||
#n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
|
||||
printf("%s/%s != %s/%s at %s(%d)\n", \
|
||||
#n1, #v1, \
|
||||
#n2, #v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
/* used to find hints on unknown values - and to make sure
|
||||
we zero-fill */
|
||||
#if 0 /* unused */
|
||||
#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
|
||||
printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
|
||||
#n1, #v1, \
|
||||
(uint_t)s1->n1.out.v1, \
|
||||
(uint_t)s1->n1.out.v1, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
#endif
|
||||
|
||||
/* basic testing of all RAW_FILEINFO_* calls
|
||||
for each call we test that it succeeds, and where possible test
|
||||
for consistency between the calls.
|
||||
*/
|
||||
BOOL torture_raw_qfileinfo(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
int i;
|
||||
BOOL ret = True;
|
||||
int count;
|
||||
union smb_fileinfo *s1, *s2;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
int fnum;
|
||||
const char *fname = "\\torture_qfileinfo.txt";
|
||||
NTTIME correct_time;
|
||||
uint64_t correct_size;
|
||||
uint32_t correct_attrib;
|
||||
const char *correct_name;
|
||||
BOOL skip_streams = False;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_qfileinfo");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
if (fnum == -1) {
|
||||
printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* scan all the fileinfo and pathinfo levels */
|
||||
for (i=0; levels[i].name; i++) {
|
||||
if (!levels[i].only_paths) {
|
||||
levels[i].fnum_finfo.generic.level = levels[i].level;
|
||||
levels[i].fnum_finfo.generic.in.file.fnum = fnum;
|
||||
levels[i].fnum_status = smb_raw_fileinfo(cli->tree, mem_ctx,
|
||||
&levels[i].fnum_finfo);
|
||||
}
|
||||
|
||||
if (!levels[i].only_handles) {
|
||||
levels[i].fname_finfo.generic.level = levels[i].level;
|
||||
levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
|
||||
levels[i].fname_status = smb_raw_pathinfo(cli->tree, mem_ctx,
|
||||
&levels[i].fname_finfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for completely broken levels */
|
||||
for (count=i=0; levels[i].name; i++) {
|
||||
uint32_t cap = cli->transport->negotiate.capabilities;
|
||||
/* see if this server claims to support this level */
|
||||
if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
|
||||
printf("ERROR: level %s failed - %s\n",
|
||||
levels[i].name, nt_errstr(levels[i].fnum_status));
|
||||
count++;
|
||||
}
|
||||
if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
|
||||
printf("ERROR: level %s failed - %s\n",
|
||||
levels[i].name, nt_errstr(levels[i].fname_status));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
ret = False;
|
||||
printf("%d levels failed\n", count);
|
||||
if (count > 35) {
|
||||
printf("too many level failures - giving up\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if we can do streams */
|
||||
s1 = fnum_find("STREAM_INFO");
|
||||
if (!s1 || s1->stream_info.out.num_streams == 0) {
|
||||
printf("STREAM_INFO broken (%d) - skipping streams checks\n",
|
||||
s1 ? s1->stream_info.out.num_streams : -1);
|
||||
skip_streams = True;
|
||||
}
|
||||
|
||||
|
||||
/* this code is incredibly repititive but doesn't lend itself to loops, so
|
||||
we use lots of macros to make it less painful */
|
||||
|
||||
/* first off we check the levels that are supposed to be aliases. It will be quite rare for
|
||||
this code to fail, but we need to check it for completeness */
|
||||
|
||||
|
||||
|
||||
#define ALIAS_CHECK(sname1, sname2) \
|
||||
do { \
|
||||
s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
|
||||
if (s1 && s2) { INFO_CHECK } \
|
||||
s1 = fname_find(sname1); s2 = fname_find(sname2); \
|
||||
if (s1 && s2) { INFO_CHECK } \
|
||||
s1 = fnum_find(sname1); s2 = fname_find(sname2); \
|
||||
if (s1 && s2) { INFO_CHECK } \
|
||||
} while (0)
|
||||
|
||||
#define INFO_CHECK \
|
||||
STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
|
||||
STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
|
||||
STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
|
||||
STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
|
||||
VAL_EQUAL (basic_info, attrib, basic_info, attrib);
|
||||
|
||||
ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
|
||||
VAL_EQUAL(standard_info, size, standard_info, size); \
|
||||
VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
|
||||
VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
|
||||
VAL_EQUAL(standard_info, directory, standard_info, directory);
|
||||
|
||||
ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
|
||||
|
||||
ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
STR_EQUAL(name_info, fname, name_info, fname);
|
||||
|
||||
ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
|
||||
STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
|
||||
STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
|
||||
STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
|
||||
VAL_EQUAL(all_info, attrib, all_info, attrib); \
|
||||
VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
|
||||
VAL_EQUAL(all_info, size, all_info, size); \
|
||||
VAL_EQUAL(all_info, nlink, all_info, nlink); \
|
||||
VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
|
||||
VAL_EQUAL(all_info, directory, all_info, directory); \
|
||||
VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
|
||||
STR_EQUAL(all_info, fname, all_info, fname);
|
||||
|
||||
ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
|
||||
VAL_EQUAL(compression_info, format, compression_info, format); \
|
||||
VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
|
||||
VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
|
||||
VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
|
||||
|
||||
ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
|
||||
|
||||
|
||||
#undef INFO_CHECK
|
||||
#define INFO_CHECK \
|
||||
STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
|
||||
|
||||
ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
|
||||
|
||||
|
||||
#define TIME_CHECK_NT(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
|
||||
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
nt_time_string(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
|
||||
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
nt_time_string(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define TIME_CHECK_DOS(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
|
||||
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
timestring(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
|
||||
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
timestring(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#if 0 /* unused */
|
||||
#define TIME_CHECK_UNX(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
|
||||
printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
timestring(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
|
||||
printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
|
||||
timestring(mem_ctx, s1->stype.out.tfield), \
|
||||
nt_time_string(mem_ctx, correct_time)); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
#endif
|
||||
|
||||
/* now check that all the times that are supposed to be equal are correct */
|
||||
s1 = fnum_find("BASIC_INFO");
|
||||
correct_time = s1->basic_info.out.create_time;
|
||||
printf("create_time: %s\n", nt_time_string(mem_ctx, correct_time));
|
||||
|
||||
TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
|
||||
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
|
||||
TIME_CHECK_DOS("GETATTRE", getattre, create_time);
|
||||
TIME_CHECK_DOS("STANDARD", standard, create_time);
|
||||
TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
|
||||
TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
|
||||
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
|
||||
|
||||
s1 = fnum_find("BASIC_INFO");
|
||||
correct_time = s1->basic_info.out.access_time;
|
||||
printf("access_time: %s\n", nt_time_string(mem_ctx, correct_time));
|
||||
|
||||
TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
|
||||
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
|
||||
TIME_CHECK_DOS("GETATTRE", getattre, access_time);
|
||||
TIME_CHECK_DOS("STANDARD", standard, access_time);
|
||||
TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
|
||||
TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
|
||||
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
|
||||
|
||||
s1 = fnum_find("BASIC_INFO");
|
||||
correct_time = s1->basic_info.out.write_time;
|
||||
printf("write_time : %s\n", nt_time_string(mem_ctx, correct_time));
|
||||
|
||||
TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
|
||||
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
|
||||
TIME_CHECK_DOS("GETATTR", getattr, write_time);
|
||||
TIME_CHECK_DOS("GETATTRE", getattre, write_time);
|
||||
TIME_CHECK_DOS("STANDARD", standard, write_time);
|
||||
TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
|
||||
TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
|
||||
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
|
||||
|
||||
s1 = fnum_find("BASIC_INFO");
|
||||
correct_time = s1->basic_info.out.change_time;
|
||||
printf("change_time: %s\n", nt_time_string(mem_ctx, correct_time));
|
||||
|
||||
TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
|
||||
TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
|
||||
TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
|
||||
TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
|
||||
|
||||
|
||||
#define SIZE_CHECK(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != correct_size) { \
|
||||
printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield, \
|
||||
(uint_t)correct_size); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != correct_size) { \
|
||||
printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield, \
|
||||
(uint_t)correct_size); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
s1 = fnum_find("STANDARD_INFO");
|
||||
correct_size = s1->standard_info.out.size;
|
||||
printf("size: %u\n", (uint_t)correct_size);
|
||||
|
||||
SIZE_CHECK("GETATTR", getattr, size);
|
||||
SIZE_CHECK("GETATTRE", getattre, size);
|
||||
SIZE_CHECK("STANDARD", standard, size);
|
||||
SIZE_CHECK("EA_SIZE", ea_size, size);
|
||||
SIZE_CHECK("STANDARD_INFO", standard_info, size);
|
||||
SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
|
||||
SIZE_CHECK("ALL_INFO", all_info, size);
|
||||
SIZE_CHECK("ALL_INFORMATION", all_info, size);
|
||||
SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
|
||||
SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
|
||||
SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
|
||||
if (!skip_streams) {
|
||||
SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
|
||||
SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
|
||||
}
|
||||
|
||||
|
||||
s1 = fnum_find("STANDARD_INFO");
|
||||
correct_size = s1->standard_info.out.alloc_size;
|
||||
printf("alloc_size: %u\n", (uint_t)correct_size);
|
||||
|
||||
SIZE_CHECK("GETATTRE", getattre, alloc_size);
|
||||
SIZE_CHECK("STANDARD", standard, alloc_size);
|
||||
SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
|
||||
SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
|
||||
SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
|
||||
SIZE_CHECK("ALL_INFO", all_info, alloc_size);
|
||||
SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
|
||||
SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
|
||||
if (!skip_streams) {
|
||||
SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
|
||||
SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
|
||||
}
|
||||
|
||||
#define ATTRIB_CHECK(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != correct_attrib) { \
|
||||
printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield, \
|
||||
(uint_t)correct_attrib); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != correct_attrib) { \
|
||||
printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield, \
|
||||
(uint_t)correct_attrib); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
s1 = fnum_find("BASIC_INFO");
|
||||
correct_attrib = s1->basic_info.out.attrib;
|
||||
printf("attrib: 0x%x\n", (uint_t)correct_attrib);
|
||||
|
||||
ATTRIB_CHECK("GETATTR", getattr, attrib);
|
||||
ATTRIB_CHECK("GETATTRE", getattre, attrib);
|
||||
ATTRIB_CHECK("STANDARD", standard, attrib);
|
||||
ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
|
||||
ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
|
||||
ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
|
||||
ATTRIB_CHECK("ALL_INFO", all_info, attrib);
|
||||
ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
|
||||
ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
|
||||
ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
|
||||
|
||||
correct_name = fname;
|
||||
printf("name: %s\n", correct_name);
|
||||
|
||||
#define NAME_CHECK(sname, stype, tfield, flags) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
|
||||
wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
|
||||
printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
|
||||
s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
|
||||
wire_bad_flags(&s1->stype.out.tfield, flags, cli))) { \
|
||||
printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
|
||||
s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
|
||||
NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
|
||||
|
||||
/* the ALL_INFO file name is the full path on the filesystem */
|
||||
s1 = fnum_find("ALL_INFO");
|
||||
if (s1 && !s1->all_info.out.fname.s) {
|
||||
printf("ALL_INFO didn't give a filename\n");
|
||||
ret = False;
|
||||
}
|
||||
if (s1 && s1->all_info.out.fname.s) {
|
||||
char *p = strrchr(s1->all_info.out.fname.s, '\\');
|
||||
if (!p) {
|
||||
printf("Not a full path in all_info/fname? - '%s'\n",
|
||||
s1->all_info.out.fname.s);
|
||||
ret = False;
|
||||
} else {
|
||||
if (strcmp_safe(correct_name, p) != 0) {
|
||||
printf("incorrect basename in all_info/fname - '%s'\n",
|
||||
s1->all_info.out.fname.s);
|
||||
ret = False;
|
||||
}
|
||||
}
|
||||
if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, cli)) {
|
||||
printf("Should not null terminate all_info/fname\n");
|
||||
ret = False;
|
||||
}
|
||||
}
|
||||
|
||||
s1 = fnum_find("ALT_NAME_INFO");
|
||||
correct_name = s1->alt_name_info.out.fname.s;
|
||||
printf("alt_name: %s\n", correct_name);
|
||||
|
||||
NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
|
||||
NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
|
||||
|
||||
/* and make sure we can open by alternate name */
|
||||
smbcli_close(cli->tree, fnum);
|
||||
fnum = smbcli_nt_create_full(cli->tree, correct_name, 0,
|
||||
SEC_RIGHTS_FILE_ALL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NTCREATEX_SHARE_ACCESS_DELETE|
|
||||
NTCREATEX_SHARE_ACCESS_READ|
|
||||
NTCREATEX_SHARE_ACCESS_WRITE,
|
||||
NTCREATEX_DISP_OVERWRITE_IF,
|
||||
0, 0);
|
||||
if (fnum == -1) {
|
||||
printf("Unable to open by alt_name - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!skip_streams) {
|
||||
correct_name = "::$DATA";
|
||||
printf("stream_name: %s\n", correct_name);
|
||||
|
||||
NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
|
||||
NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
|
||||
}
|
||||
|
||||
/* make sure the EAs look right */
|
||||
s1 = fnum_find("ALL_EAS");
|
||||
s2 = fnum_find("ALL_INFO");
|
||||
if (s1) {
|
||||
for (i=0;i<s1->all_eas.out.num_eas;i++) {
|
||||
printf(" flags=%d %s=%*.*s\n",
|
||||
s1->all_eas.out.eas[i].flags,
|
||||
s1->all_eas.out.eas[i].name.s,
|
||||
(int)s1->all_eas.out.eas[i].value.length,
|
||||
(int)s1->all_eas.out.eas[i].value.length,
|
||||
s1->all_eas.out.eas[i].value.data);
|
||||
}
|
||||
}
|
||||
if (s1 && s2) {
|
||||
if (s1->all_eas.out.num_eas == 0) {
|
||||
if (s2->all_info.out.ea_size != 0) {
|
||||
printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
|
||||
s2->all_info.out.ea_size);
|
||||
}
|
||||
} else {
|
||||
if (s2->all_info.out.ea_size !=
|
||||
ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
|
||||
printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
|
||||
(int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
|
||||
(int)s2->all_info.out.ea_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
s2 = fname_find("ALL_EAS");
|
||||
if (s2) {
|
||||
VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
|
||||
for (i=0;i<s1->all_eas.out.num_eas;i++) {
|
||||
VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
|
||||
STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
|
||||
VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
|
||||
}
|
||||
}
|
||||
|
||||
#define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
|
||||
s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
|
||||
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
|
||||
printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
|
||||
#stype1, #tfield1, #stype2, #tfield2, \
|
||||
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname1); s2 = fname_find(sname2); \
|
||||
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
|
||||
printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
|
||||
#stype1, #tfield1, #stype2, #tfield2, \
|
||||
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fnum_find(sname1); s2 = fname_find(sname2); \
|
||||
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
|
||||
printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
|
||||
#stype1, #tfield1, #stype2, #tfield2, \
|
||||
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
|
||||
ret = False; \
|
||||
} \
|
||||
s1 = fname_find(sname1); s2 = fnum_find(sname2); \
|
||||
if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
|
||||
printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
|
||||
#stype1, #tfield1, #stype2, #tfield2, \
|
||||
s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
|
||||
"ALL_INFO", all_info, delete_pending);
|
||||
VAL_CHECK("STANDARD_INFO", standard_info, directory,
|
||||
"ALL_INFO", all_info, directory);
|
||||
VAL_CHECK("STANDARD_INFO", standard_info, nlink,
|
||||
"ALL_INFO", all_info, nlink);
|
||||
VAL_CHECK("EA_INFO", ea_info, ea_size,
|
||||
"ALL_INFO", all_info, ea_size);
|
||||
VAL_CHECK("EA_SIZE", ea_size, ea_size,
|
||||
"ALL_INFO", all_info, ea_size);
|
||||
|
||||
|
||||
#define NAME_PATH_CHECK(sname, stype, field) do { \
|
||||
s1 = fname_find(sname); s2 = fnum_find(sname); \
|
||||
if (s1 && s2) { \
|
||||
VAL_EQUAL(stype, field, stype, field); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
s1 = fnum_find("INTERNAL_INFORMATION");
|
||||
if (s1) {
|
||||
printf("file_id=%.0f\n", (double)s1->internal_information.out.file_id);
|
||||
}
|
||||
|
||||
NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
|
||||
NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
|
||||
if (s1 && s2) {
|
||||
printf("fnum pos = %.0f, fname pos = %.0f\n",
|
||||
(double)s2->position_information.out.position,
|
||||
(double)s1->position_information.out.position );
|
||||
}
|
||||
NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
|
||||
NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
|
||||
NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
|
||||
NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
|
||||
|
||||
#if 0
|
||||
/* these are expected to differ */
|
||||
NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
|
||||
#endif
|
||||
|
||||
#if 0 /* unused */
|
||||
#define UNKNOWN_CHECK(sname, stype, tfield) do { \
|
||||
s1 = fnum_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != 0) { \
|
||||
printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
|
||||
#stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield); \
|
||||
} \
|
||||
s1 = fname_find(sname); \
|
||||
if (s1 && s1->stype.out.tfield != 0) { \
|
||||
printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
|
||||
#stype, #tfield, \
|
||||
(uint_t)s1->stype.out.tfield); \
|
||||
}} while (0)
|
||||
#endif
|
||||
/* now get a bit fancier .... */
|
||||
|
||||
/* when we set the delete disposition then the link count should drop
|
||||
to 0 and delete_pending should be 1 */
|
||||
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_unlink(cli->tree, fname);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_QFS_* individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
enum smb_fsinfo_level level;
|
||||
uint32_t capability_mask;
|
||||
NTSTATUS status;
|
||||
union smb_fsinfo fsinfo;
|
||||
} levels[] = {
|
||||
{"DSKATTR", RAW_QFS_DSKATTR, },
|
||||
{"ALLOCATION", RAW_QFS_ALLOCATION, },
|
||||
{"VOLUME", RAW_QFS_VOLUME, },
|
||||
{"VOLUME_INFO", RAW_QFS_VOLUME_INFO, },
|
||||
{"SIZE_INFO", RAW_QFS_SIZE_INFO, },
|
||||
{"DEVICE_INFO", RAW_QFS_DEVICE_INFO, },
|
||||
{"ATTRIBUTE_INFO", RAW_QFS_ATTRIBUTE_INFO, },
|
||||
{"UNIX_INFO", RAW_QFS_UNIX_INFO, CAP_UNIX},
|
||||
{"VOLUME_INFORMATION", RAW_QFS_VOLUME_INFORMATION, },
|
||||
{"SIZE_INFORMATION", RAW_QFS_SIZE_INFORMATION, },
|
||||
{"DEVICE_INFORMATION", RAW_QFS_DEVICE_INFORMATION, },
|
||||
{"ATTRIBUTE_INFORMATION", RAW_QFS_ATTRIBUTE_INFORMATION, },
|
||||
{"QUOTA_INFORMATION", RAW_QFS_QUOTA_INFORMATION, },
|
||||
{"FULL_SIZE_INFORMATION", RAW_QFS_FULL_SIZE_INFORMATION, },
|
||||
#if 0
|
||||
/* w2k3 seems to no longer support this */
|
||||
{"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
|
||||
#endif
|
||||
{ NULL, }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
find a level in the levels[] table
|
||||
*/
|
||||
static union smb_fsinfo *find(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; levels[i].name; i++) {
|
||||
if (strcmp(name, levels[i].name) == 0 &&
|
||||
NT_STATUS_IS_OK(levels[i].status)) {
|
||||
return &levels[i].fsinfo;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* local macros to make the code below more readable */
|
||||
#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
|
||||
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
|
||||
#n1, #v1, (uint_t)s1->n1.out.v1, \
|
||||
#n2, #v2, (uint_t)s2->n2.out.v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
#define VAL_APPROX_EQUAL(n1, v1, n2, v2) do {if (abs((int)(s1->n1.out.v1) - (int)(s2->n2.out.v2)) > 0.1*s1->n1.out.v1) { \
|
||||
printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
|
||||
#n1, #v1, (uint_t)s1->n1.out.v1, \
|
||||
#n2, #v2, (uint_t)s2->n2.out.v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
#define STR_EQUAL(n1, v1, n2, v2) do { \
|
||||
if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
|
||||
printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
|
||||
#n1, #v1, s1->n1.out.v1, \
|
||||
#n2, #v2, s2->n2.out.v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
|
||||
printf("%s/%s != %s/%s at %s(%d)\n", \
|
||||
#n1, #v1, \
|
||||
#n2, #v2, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
/* used to find hints on unknown values - and to make sure
|
||||
we zero-fill */
|
||||
#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
|
||||
printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
|
||||
#n1, #v1, \
|
||||
(uint_t)s1->n1.out.v1, \
|
||||
(uint_t)s1->n1.out.v1, \
|
||||
__FILE__, __LINE__); \
|
||||
ret = False; \
|
||||
}} while(0)
|
||||
|
||||
/* basic testing of all RAW_QFS_* calls
|
||||
for each call we test that it succeeds, and where possible test
|
||||
for consistency between the calls.
|
||||
|
||||
Some of the consistency tests assume that the target filesystem is
|
||||
quiescent, which is sometimes hard to achieve
|
||||
*/
|
||||
BOOL torture_raw_qfsinfo(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
int i;
|
||||
BOOL ret = True;
|
||||
int count;
|
||||
union smb_fsinfo *s1, *s2;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_qfsinfo");
|
||||
|
||||
/* scan all the levels, pulling the results */
|
||||
for (i=0; levels[i].name; i++) {
|
||||
printf("Running level %s\n", levels[i].name);
|
||||
levels[i].fsinfo.generic.level = levels[i].level;
|
||||
levels[i].status = smb_raw_fsinfo(cli->tree, mem_ctx, &levels[i].fsinfo);
|
||||
}
|
||||
|
||||
/* check for completely broken levels */
|
||||
for (count=i=0; levels[i].name; i++) {
|
||||
uint32_t cap = cli->transport->negotiate.capabilities;
|
||||
/* see if this server claims to support this level */
|
||||
if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(levels[i].status)) {
|
||||
printf("ERROR: level %s failed - %s\n",
|
||||
levels[i].name, nt_errstr(levels[i].status));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
ret = False;
|
||||
printf("%d levels failed\n", count);
|
||||
if (count > 13) {
|
||||
printf("too many level failures - giving up\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
printf("check for correct aliases\n");
|
||||
s1 = find("SIZE_INFO");
|
||||
s2 = find("SIZE_INFORMATION");
|
||||
if (s1 && s2) {
|
||||
VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
|
||||
VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
|
||||
VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
|
||||
VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
|
||||
}
|
||||
|
||||
s1 = find("DEVICE_INFO");
|
||||
s2 = find("DEVICE_INFORMATION");
|
||||
if (s1 && s2) {
|
||||
VAL_EQUAL(device_info, device_type, device_info, device_type);
|
||||
VAL_EQUAL(device_info, characteristics, device_info, characteristics);
|
||||
}
|
||||
|
||||
s1 = find("VOLUME_INFO");
|
||||
s2 = find("VOLUME_INFORMATION");
|
||||
if (s1 && s2) {
|
||||
STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
|
||||
VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
|
||||
STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
|
||||
printf("volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
|
||||
}
|
||||
|
||||
s1 = find("ATTRIBUTE_INFO");
|
||||
s2 = find("ATTRIBUTE_INFORMATION");
|
||||
if (s1 && s2) {
|
||||
VAL_EQUAL(attribute_info, fs_attr,
|
||||
attribute_info, fs_attr);
|
||||
VAL_EQUAL(attribute_info, max_file_component_length,
|
||||
attribute_info, max_file_component_length);
|
||||
STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
|
||||
printf("attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
|
||||
}
|
||||
|
||||
printf("check for consistent disk sizes\n");
|
||||
s1 = find("DSKATTR");
|
||||
s2 = find("ALLOCATION");
|
||||
if (s1 && s2) {
|
||||
double size1, size2;
|
||||
double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
|
||||
size1 = 1.0 *
|
||||
s1->dskattr.out.units_total *
|
||||
s1->dskattr.out.blocks_per_unit *
|
||||
s1->dskattr.out.block_size / scale;
|
||||
size2 = 1.0 *
|
||||
s2->allocation.out.sectors_per_unit *
|
||||
s2->allocation.out.total_alloc_units *
|
||||
s2->allocation.out.bytes_per_sector / scale;
|
||||
if (abs(size1 - size2) > 1) {
|
||||
printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
|
||||
size1, size2);
|
||||
ret = False;
|
||||
}
|
||||
printf("total disk = %.0f MB\n", size1*scale/1.0e6);
|
||||
}
|
||||
|
||||
printf("check consistent free disk space\n");
|
||||
s1 = find("DSKATTR");
|
||||
s2 = find("ALLOCATION");
|
||||
if (s1 && s2) {
|
||||
double size1, size2;
|
||||
double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
|
||||
size1 = 1.0 *
|
||||
s1->dskattr.out.units_free *
|
||||
s1->dskattr.out.blocks_per_unit *
|
||||
s1->dskattr.out.block_size / scale;
|
||||
size2 = 1.0 *
|
||||
s2->allocation.out.sectors_per_unit *
|
||||
s2->allocation.out.avail_alloc_units *
|
||||
s2->allocation.out.bytes_per_sector / scale;
|
||||
if (abs(size1 - size2) > 1) {
|
||||
printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
|
||||
size1, size2);
|
||||
ret = False;
|
||||
}
|
||||
printf("free disk = %.0f MB\n", size1*scale/1.0e6);
|
||||
}
|
||||
|
||||
printf("volume info consistency\n");
|
||||
s1 = find("VOLUME");
|
||||
s2 = find("VOLUME_INFO");
|
||||
if (s1 && s2) {
|
||||
VAL_EQUAL(volume, serial_number, volume_info, serial_number);
|
||||
STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
|
||||
}
|
||||
|
||||
/* disk size consistency - notice that 'avail_alloc_units' maps to the caller
|
||||
available allocation units, not the total */
|
||||
s1 = find("SIZE_INFO");
|
||||
s2 = find("FULL_SIZE_INFORMATION");
|
||||
if (s1 && s2) {
|
||||
VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
|
||||
VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
|
||||
VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
|
||||
VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
|
||||
}
|
||||
|
||||
printf("check for non-zero unknown fields\n");
|
||||
s1 = find("QUOTA_INFORMATION");
|
||||
if (s1) {
|
||||
VAL_UNKNOWN(quota_information, unknown[0]);
|
||||
VAL_UNKNOWN(quota_information, unknown[1]);
|
||||
VAL_UNKNOWN(quota_information, unknown[2]);
|
||||
}
|
||||
|
||||
s1 = find("OBJECTID_INFORMATION");
|
||||
if (s1) {
|
||||
VAL_UNKNOWN(objectid_information, unknown[0]);
|
||||
VAL_UNKNOWN(objectid_information, unknown[1]);
|
||||
VAL_UNKNOWN(objectid_information, unknown[2]);
|
||||
VAL_UNKNOWN(objectid_information, unknown[3]);
|
||||
VAL_UNKNOWN(objectid_information, unknown[4]);
|
||||
VAL_UNKNOWN(objectid_information, unknown[5]);
|
||||
}
|
||||
|
||||
|
||||
#define STR_CHECK(sname, stype, field, flags) do { \
|
||||
s1 = find(sname); \
|
||||
if (s1) { \
|
||||
if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli)) { \
|
||||
printf("(%d) incorrect string termination in %s/%s\n", \
|
||||
__LINE__, #stype, #field); \
|
||||
ret = False; \
|
||||
} \
|
||||
}} while (0)
|
||||
|
||||
printf("check for correct termination\n");
|
||||
|
||||
STR_CHECK("VOLUME", volume, volume_name, 0);
|
||||
STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
|
||||
STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
|
||||
STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
|
||||
STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
|
||||
|
||||
done:
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB torture tester
|
||||
Copyright (C) Jelmer Vernooij 2006
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "torture/raw/proto.h"
|
||||
|
||||
NTSTATUS torture_raw_init(void)
|
||||
{
|
||||
struct torture_suite *suite = torture_suite_create(
|
||||
talloc_autofree_context(),
|
||||
"RAW");
|
||||
/* RAW smb tests */
|
||||
torture_suite_add_simple_test(suite, "BENCH-OPLOCK", torture_bench_oplock);
|
||||
torture_suite_add_simple_test(suite, "BENCH-LOCK", torture_bench_lock);
|
||||
torture_suite_add_simple_test(suite, "QFSINFO", torture_raw_qfsinfo);
|
||||
torture_suite_add_simple_test(suite, "QFILEINFO", torture_raw_qfileinfo);
|
||||
torture_suite_add_simple_test(suite, "SFILEINFO", torture_raw_sfileinfo);
|
||||
torture_suite_add_simple_test(suite, "SFILEINFO-BUG", torture_raw_sfileinfo_bug);
|
||||
torture_suite_add_simple_test(suite, "SEARCH", torture_raw_search);
|
||||
torture_suite_add_simple_test(suite, "CLOSE", torture_raw_close);
|
||||
torture_suite_add_simple_test(suite, "OPEN", torture_raw_open);
|
||||
torture_suite_add_simple_test(suite, "MKDIR", torture_raw_mkdir);
|
||||
torture_suite_add_simple_test(suite, "OPLOCK", torture_raw_oplock);
|
||||
torture_suite_add_simple_test(suite, "NOTIFY", torture_raw_notify);
|
||||
torture_suite_add_simple_test(suite, "MUX", torture_raw_mux);
|
||||
torture_suite_add_simple_test(suite, "IOCTL", torture_raw_ioctl);
|
||||
torture_suite_add_simple_test(suite, "CHKPATH", torture_raw_chkpath);
|
||||
torture_suite_add_simple_test(suite, "UNLINK", torture_raw_unlink);
|
||||
torture_suite_add_simple_test(suite, "READ", torture_raw_read);
|
||||
torture_suite_add_simple_test(suite, "WRITE", torture_raw_write);
|
||||
torture_suite_add_simple_test(suite, "LOCK", torture_raw_lock);
|
||||
torture_suite_add_simple_test(suite, "CONTEXT", torture_raw_context);
|
||||
torture_suite_add_simple_test(suite, "RENAME", torture_raw_rename);
|
||||
torture_suite_add_simple_test(suite, "SEEK", torture_raw_seek);
|
||||
torture_suite_add_simple_test(suite, "EAS", torture_raw_eas);
|
||||
torture_suite_add_simple_test(suite, "STREAMS", torture_raw_streams);
|
||||
torture_suite_add_simple_test(suite, "ACLS", torture_raw_acls);
|
||||
torture_suite_add_simple_test(suite, "COMPOSITE", torture_raw_composite);
|
||||
torture_suite_add_simple_test(suite, "SAMBA3HIDE", torture_samba3_hide);
|
||||
torture_suite_add_simple_test(suite, "SAMBA3CHECKFSP", torture_samba3_checkfsp);
|
||||
torture_suite_add_simple_test(suite, "SAMBA3BADPATH", torture_samba3_badpath);
|
||||
torture_suite_add_simple_test(suite, "SCAN-EAMAX", torture_max_eas);
|
||||
|
||||
suite->description = talloc_strdup(suite,
|
||||
"Tests for the raw SMB interface");
|
||||
|
||||
torture_register_suite(suite);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
test suite for various read 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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.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 CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%s) Incorrect value %s=%ld - should be %ld\n", \
|
||||
__location__, #v, (long)v, (long)correct); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_BUFFER(buf, seed, len) do { \
|
||||
if (!check_buffer(buf, seed, len, __LINE__)) { \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define BASEDIR "\\testread"
|
||||
|
||||
|
||||
/*
|
||||
setup a random buffer based on a seed
|
||||
*/
|
||||
static void setup_buffer(uint8_t *buf, uint_t seed, int len)
|
||||
{
|
||||
int i;
|
||||
srandom(seed);
|
||||
for (i=0;i<len;i++) buf[i] = random();
|
||||
}
|
||||
|
||||
/*
|
||||
check a random buffer based on a seed
|
||||
*/
|
||||
static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, int line)
|
||||
{
|
||||
int i;
|
||||
srandom(seed);
|
||||
for (i=0;i<len;i++) {
|
||||
uint8_t v = random();
|
||||
if (buf[i] != v) {
|
||||
printf("Buffer incorrect at line %d! ofs=%d v1=0x%x v2=0x%x\n",
|
||||
line, i, buf[i], v);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test read ops
|
||||
*/
|
||||
static BOOL test_read(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_read io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const char *test_data = "TEST DATA";
|
||||
uint_t seed = time(NULL);
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_READ_READ\n");
|
||||
io.generic.level = RAW_READ_READ;
|
||||
|
||||
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 empty file read\n");
|
||||
io.read.in.file.fnum = fnum;
|
||||
io.read.in.count = 1;
|
||||
io.read.in.offset = 0;
|
||||
io.read.in.remaining = 0;
|
||||
io.read.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.read.out.nread, 0);
|
||||
|
||||
printf("Trying zero file read\n");
|
||||
io.read.in.count = 0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.read.out.nread, 0);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.read.in.file.fnum = fnum+1;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
io.read.in.file.fnum = fnum;
|
||||
|
||||
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
|
||||
|
||||
printf("Trying small read\n");
|
||||
io.read.in.file.fnum = fnum;
|
||||
io.read.in.offset = 0;
|
||||
io.read.in.remaining = 0;
|
||||
io.read.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.read.out.nread, strlen(test_data));
|
||||
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying short read\n");
|
||||
io.read.in.offset = 1;
|
||||
io.read.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.read.out.nread, strlen(test_data)-1);
|
||||
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
||||
printf("Trying max offset\n");
|
||||
io.read.in.offset = ~0;
|
||||
io.read.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.read.out.nread, 0);
|
||||
}
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
|
||||
memset(buf, 0, maxsize);
|
||||
|
||||
printf("Trying large read\n");
|
||||
io.read.in.offset = 0;
|
||||
io.read.in.count = ~0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_BUFFER(buf, seed, io.read.out.nread);
|
||||
|
||||
|
||||
printf("Trying locked region\n");
|
||||
cli->session->pid++;
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %d\n", __LINE__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
cli->session->pid--;
|
||||
memset(buf, 0, maxsize);
|
||||
io.read.in.offset = 0;
|
||||
io.read.in.count = ~0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test lockread ops
|
||||
*/
|
||||
static BOOL test_lockread(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_read io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const char *test_data = "TEST DATA";
|
||||
uint_t seed = time(NULL);
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_READ_LOCKREAD\n");
|
||||
io.generic.level = RAW_READ_LOCKREAD;
|
||||
|
||||
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 empty file read\n");
|
||||
io.lockread.in.file.fnum = fnum;
|
||||
io.lockread.in.count = 1;
|
||||
io.lockread.in.offset = 1;
|
||||
io.lockread.in.remaining = 0;
|
||||
io.lockread.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lockread.out.nread, 0);
|
||||
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
|
||||
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
printf("Trying zero file read\n");
|
||||
io.lockread.in.count = 0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_unlock(cli->tree, fnum, 1, 1);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.lockread.in.file.fnum = fnum+1;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
io.lockread.in.file.fnum = fnum;
|
||||
|
||||
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
|
||||
|
||||
printf("Trying small read\n");
|
||||
io.lockread.in.file.fnum = fnum;
|
||||
io.lockread.in.offset = 0;
|
||||
io.lockread.in.remaining = 0;
|
||||
io.lockread.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
|
||||
|
||||
smbcli_unlock(cli->tree, fnum, 1, 0);
|
||||
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lockread.out.nread, strlen(test_data));
|
||||
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying short read\n");
|
||||
io.lockread.in.offset = 1;
|
||||
io.lockread.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
|
||||
smbcli_unlock(cli->tree, fnum, 0, strlen(test_data));
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
CHECK_VALUE(io.lockread.out.nread, strlen(test_data)-1);
|
||||
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
||||
printf("Trying max offset\n");
|
||||
io.lockread.in.offset = ~0;
|
||||
io.lockread.in.count = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lockread.out.nread, 0);
|
||||
}
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
|
||||
memset(buf, 0, maxsize);
|
||||
|
||||
printf("Trying large read\n");
|
||||
io.lockread.in.offset = 0;
|
||||
io.lockread.in.count = ~0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
|
||||
smbcli_unlock(cli->tree, fnum, 1, strlen(test_data));
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_BUFFER(buf, seed, io.lockread.out.nread);
|
||||
smbcli_unlock(cli->tree, fnum, 0, 0xFFFF);
|
||||
|
||||
|
||||
printf("Trying locked region\n");
|
||||
cli->session->pid++;
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %d\n", __LINE__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
cli->session->pid--;
|
||||
memset(buf, 0, maxsize);
|
||||
io.lockread.in.offset = 0;
|
||||
io.lockread.in.count = ~0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test readx ops
|
||||
*/
|
||||
static BOOL test_readx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_read io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const char *test_data = "TEST DATA";
|
||||
uint_t seed = time(NULL);
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_READ_READX\n");
|
||||
|
||||
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 empty file read\n");
|
||||
io.generic.level = RAW_READ_READX;
|
||||
io.readx.in.file.fnum = fnum;
|
||||
io.readx.in.mincnt = 1;
|
||||
io.readx.in.maxcnt = 1;
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.remaining = 0;
|
||||
io.readx.in.read_for_execute = False;
|
||||
io.readx.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
|
||||
printf("Trying zero file read\n");
|
||||
io.readx.in.mincnt = 0;
|
||||
io.readx.in.maxcnt = 0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.readx.in.file.fnum = fnum+1;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
io.readx.in.file.fnum = fnum;
|
||||
|
||||
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
|
||||
|
||||
printf("Trying small read\n");
|
||||
io.readx.in.file.fnum = fnum;
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.remaining = 0;
|
||||
io.readx.in.read_for_execute = False;
|
||||
io.readx.in.mincnt = strlen(test_data);
|
||||
io.readx.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, strlen(test_data));
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying short read\n");
|
||||
io.readx.in.offset = 1;
|
||||
io.readx.in.mincnt = strlen(test_data);
|
||||
io.readx.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, strlen(test_data)-1);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
||||
printf("Trying max offset\n");
|
||||
io.readx.in.offset = 0xffffffff;
|
||||
io.readx.in.mincnt = strlen(test_data);
|
||||
io.readx.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
}
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
|
||||
memset(buf, 0, maxsize);
|
||||
|
||||
printf("Trying large read\n");
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 0xFFFF;
|
||||
io.readx.in.maxcnt = 0xFFFF;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
|
||||
CHECK_BUFFER(buf, seed, io.readx.out.nread);
|
||||
|
||||
printf("Trying extra large read\n");
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 100;
|
||||
io.readx.in.maxcnt = 80000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
if (lp_parm_bool(-1, "torture", "samba3", False)) {
|
||||
printf("SAMBA3: large read extension\n");
|
||||
CHECK_VALUE(io.readx.out.nread, 80000);
|
||||
} else {
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, io.readx.out.nread);
|
||||
|
||||
printf("Trying mincnt > maxcnt\n");
|
||||
memset(buf, 0, maxsize);
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 30000;
|
||||
io.readx.in.maxcnt = 20000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
|
||||
CHECK_BUFFER(buf, seed, io.readx.out.nread);
|
||||
|
||||
printf("Trying mincnt < maxcnt\n");
|
||||
memset(buf, 0, maxsize);
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 20000;
|
||||
io.readx.in.maxcnt = 30000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(io.readx.out.compaction_mode, 0);
|
||||
CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
|
||||
CHECK_BUFFER(buf, seed, io.readx.out.nread);
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_READX) {
|
||||
printf("Trying large readx\n");
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 0;
|
||||
io.readx.in.maxcnt = 0x10000 - 1;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0xFFFF);
|
||||
|
||||
io.readx.in.maxcnt = 0x10000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
if (lp_parm_bool(-1, "torture", "samba3", False)) {
|
||||
printf("SAMBA3: large read extension\n");
|
||||
CHECK_VALUE(io.readx.out.nread, 0x10000);
|
||||
} else {
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
}
|
||||
|
||||
io.readx.in.maxcnt = 0x10001;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
if (lp_parm_bool(-1, "torture", "samba3", False)) {
|
||||
printf("SAMBA3: large read extension\n");
|
||||
CHECK_VALUE(io.readx.out.nread, 0x10001);
|
||||
} else {
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Trying locked region\n");
|
||||
cli->session->pid++;
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %d\n", __LINE__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
cli->session->pid--;
|
||||
memset(buf, 0, maxsize);
|
||||
io.readx.in.offset = 0;
|
||||
io.readx.in.mincnt = 100;
|
||||
io.readx.in.maxcnt = 200;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying large offset read\n");
|
||||
io.readx.in.offset = ((uint64_t)0x2) << 32;
|
||||
io.readx.in.mincnt = 10;
|
||||
io.readx.in.maxcnt = 10;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock64(cli->tree, fnum, io.readx.in.offset, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %d\n", __LINE__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readx.out.nread, 0);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test readbraw ops
|
||||
*/
|
||||
static BOOL test_readbraw(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_read io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const char *test_data = "TEST DATA";
|
||||
uint_t seed = time(NULL);
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_READ_READBRAW\n");
|
||||
|
||||
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 empty file read\n");
|
||||
io.generic.level = RAW_READ_READBRAW;
|
||||
io.readbraw.in.file.fnum = fnum;
|
||||
io.readbraw.in.mincnt = 1;
|
||||
io.readbraw.in.maxcnt = 1;
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.timeout = 0;
|
||||
io.readbraw.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
|
||||
printf("Trying zero file read\n");
|
||||
io.readbraw.in.mincnt = 0;
|
||||
io.readbraw.in.maxcnt = 0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.readbraw.in.file.fnum = fnum+1;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
io.readbraw.in.file.fnum = fnum;
|
||||
|
||||
smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
|
||||
|
||||
printf("Trying small read\n");
|
||||
io.readbraw.in.file.fnum = fnum;
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = strlen(test_data);
|
||||
io.readbraw.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, strlen(test_data));
|
||||
if (memcmp(buf, test_data, strlen(test_data)) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying short read\n");
|
||||
io.readbraw.in.offset = 1;
|
||||
io.readbraw.in.mincnt = strlen(test_data);
|
||||
io.readbraw.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, strlen(test_data)-1);
|
||||
if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
|
||||
ret = False;
|
||||
printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
||||
printf("Trying max offset\n");
|
||||
io.readbraw.in.offset = ~0;
|
||||
io.readbraw.in.mincnt = strlen(test_data);
|
||||
io.readbraw.in.maxcnt = strlen(test_data);
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
}
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
|
||||
memset(buf, 0, maxsize);
|
||||
|
||||
printf("Trying large read\n");
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = ~0;
|
||||
io.readbraw.in.maxcnt = ~0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0xFFFF);
|
||||
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
|
||||
|
||||
printf("Trying mincnt > maxcnt\n");
|
||||
memset(buf, 0, maxsize);
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = 30000;
|
||||
io.readbraw.in.maxcnt = 20000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
|
||||
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
|
||||
|
||||
printf("Trying mincnt < maxcnt\n");
|
||||
memset(buf, 0, maxsize);
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = 20000;
|
||||
io.readbraw.in.maxcnt = 30000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
|
||||
CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
|
||||
|
||||
printf("Trying locked region\n");
|
||||
cli->session->pid++;
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %d\n", __LINE__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
cli->session->pid--;
|
||||
memset(buf, 0, maxsize);
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = 100;
|
||||
io.readbraw.in.maxcnt = 200;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
|
||||
printf("Trying locked region with timeout\n");
|
||||
memset(buf, 0, maxsize);
|
||||
io.readbraw.in.offset = 0;
|
||||
io.readbraw.in.mincnt = 100;
|
||||
io.readbraw.in.maxcnt = 200;
|
||||
io.readbraw.in.timeout = 10000;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
|
||||
if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
||||
printf("Trying large offset read\n");
|
||||
io.readbraw.in.offset = ((uint64_t)0x2) << 32;
|
||||
io.readbraw.in.mincnt = 10;
|
||||
io.readbraw.in.maxcnt = 10;
|
||||
io.readbraw.in.timeout = 0;
|
||||
status = smb_raw_read(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.readbraw.out.nread, 0);
|
||||
}
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
test read for execute
|
||||
*/
|
||||
static BOOL test_read_for_execute(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_open op;
|
||||
union smb_write wr;
|
||||
union smb_read rd;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum=0;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 900;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const uint8_t data[] = "TEST DATA";
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_READ_READX with read_for_execute\n");
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
op.ntcreatex.in.create_options = 0;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
wr.generic.level = RAW_WRITE_WRITEX;
|
||||
wr.writex.in.file.fnum = fnum;
|
||||
wr.writex.in.offset = 0;
|
||||
wr.writex.in.wmode = 0;
|
||||
wr.writex.in.remaining = 0;
|
||||
wr.writex.in.count = ARRAY_SIZE(data);
|
||||
wr.writex.in.data = data;
|
||||
status = smb_raw_write(cli->tree, &wr);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(wr.writex.out.nwritten, ARRAY_SIZE(data));
|
||||
|
||||
status = smbcli_close(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("open file with SEC_FILE_EXECUTE\n");
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_FILE_EXECUTE;
|
||||
op.ntcreatex.in.create_options = 0;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
|
||||
rd.generic.level = RAW_READ_READX;
|
||||
rd.readx.in.file.fnum = fnum;
|
||||
rd.readx.in.mincnt = 0;
|
||||
rd.readx.in.maxcnt = maxsize;
|
||||
rd.readx.in.offset = 0;
|
||||
rd.readx.in.remaining = 0;
|
||||
rd.readx.in.read_for_execute = True;
|
||||
rd.readx.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
|
||||
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
|
||||
|
||||
printf("read without FLAGS2_READ_PERMIT_EXECUTE (should fail)\n");
|
||||
rd.generic.level = RAW_READ_READX;
|
||||
rd.readx.in.file.fnum = fnum;
|
||||
rd.readx.in.mincnt = 0;
|
||||
rd.readx.in.maxcnt = maxsize;
|
||||
rd.readx.in.offset = 0;
|
||||
rd.readx.in.remaining = 0;
|
||||
rd.readx.in.read_for_execute = False;
|
||||
rd.readx.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
status = smbcli_close(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("open file with SEC_FILE_READ_DATA\n");
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
|
||||
op.ntcreatex.in.create_options = 0;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
|
||||
rd.generic.level = RAW_READ_READX;
|
||||
rd.readx.in.file.fnum = fnum;
|
||||
rd.readx.in.mincnt = 0;
|
||||
rd.readx.in.maxcnt = maxsize;
|
||||
rd.readx.in.offset = 0;
|
||||
rd.readx.in.remaining = 0;
|
||||
rd.readx.in.read_for_execute = True;
|
||||
rd.readx.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
|
||||
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
|
||||
|
||||
printf("read without FLAGS2_READ_PERMIT_EXECUTE\n");
|
||||
rd.generic.level = RAW_READ_READX;
|
||||
rd.readx.in.file.fnum = fnum;
|
||||
rd.readx.in.mincnt = 0;
|
||||
rd.readx.in.maxcnt = maxsize;
|
||||
rd.readx.in.offset = 0;
|
||||
rd.readx.in.remaining = 0;
|
||||
rd.readx.in.read_for_execute = False;
|
||||
rd.readx.out.data = buf;
|
||||
status = smb_raw_read(cli->tree, &rd);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
|
||||
CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
|
||||
CHECK_VALUE(rd.readx.out.compaction_mode, 0);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of read calls
|
||||
*/
|
||||
BOOL torture_raw_read(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_read");
|
||||
|
||||
ret &= test_read(cli, mem_ctx);
|
||||
ret &= test_readx(cli, mem_ctx);
|
||||
ret &= test_lockread(cli, mem_ctx);
|
||||
ret &= test_readbraw(cli, mem_ctx);
|
||||
ret &= test_read_for_execute(cli, mem_ctx);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
rename test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.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 CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%s) Incorrect %s %d - should be %d\n", \
|
||||
__location__, #v, (int)v, (int)correct); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define BASEDIR "\\testrename"
|
||||
|
||||
/*
|
||||
test SMBmv ops
|
||||
*/
|
||||
static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_rename io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum = -1;
|
||||
const char *fname1 = BASEDIR "\\test1.txt";
|
||||
const char *fname2 = BASEDIR "\\test2.txt";
|
||||
union smb_open op;
|
||||
|
||||
printf("Testing SMBmv\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Trying simple rename\n");
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
op.ntcreatex.in.create_options = 0;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = fname1;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
io.generic.level = RAW_RENAME_RENAME;
|
||||
io.rename.in.pattern1 = fname1;
|
||||
io.rename.in.pattern2 = fname2;
|
||||
io.rename.in.attrib = 0;
|
||||
|
||||
printf("trying rename while first file open\n");
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
|
||||
op.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_DELETE |
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.rename.in.pattern1 = fname2;
|
||||
io.rename.in.pattern2 = fname1;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.rename.in.pattern1 = fname1;
|
||||
io.rename.in.pattern2 = fname2;
|
||||
|
||||
printf("trying rename while not open\n");
|
||||
smb_raw_exit(cli->session);
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Trying self rename\n");
|
||||
io.rename.in.pattern1 = fname2;
|
||||
io.rename.in.pattern2 = fname2;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.rename.in.pattern1 = fname1;
|
||||
io.rename.in.pattern2 = fname1;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
|
||||
printf("trying wildcard rename\n");
|
||||
io.rename.in.pattern1 = BASEDIR "\\*.txt";
|
||||
io.rename.in.pattern2 = fname1;
|
||||
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("and again\n");
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Trying extension change\n");
|
||||
io.rename.in.pattern1 = BASEDIR "\\*.txt";
|
||||
io.rename.in.pattern2 = BASEDIR "\\*.bak";
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
printf("Checking attrib handling\n");
|
||||
torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN);
|
||||
io.rename.in.pattern1 = BASEDIR "\\test1.bak";
|
||||
io.rename.in.pattern2 = BASEDIR "\\*.txt";
|
||||
io.rename.in.attrib = 0;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
||||
status = smb_raw_rename(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 SMBntrename ops
|
||||
*/
|
||||
static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_rename io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum, i;
|
||||
const char *fname1 = BASEDIR "\\test1.txt";
|
||||
const char *fname2 = BASEDIR "\\test2.txt";
|
||||
union smb_fileinfo finfo;
|
||||
|
||||
printf("Testing SMBntrename\n");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Trying simple rename\n");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname1);
|
||||
|
||||
io.generic.level = RAW_RENAME_NTRENAME;
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.cluster_size = 0;
|
||||
io.ntrename.in.flags = RENAME_FLAG_RENAME;
|
||||
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Trying self rename\n");
|
||||
io.ntrename.in.old_name = fname2;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname1;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
printf("trying wildcard rename\n");
|
||||
io.ntrename.in.old_name = BASEDIR "\\*.txt";
|
||||
io.ntrename.in.new_name = fname1;
|
||||
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
|
||||
printf("Checking attrib handling\n");
|
||||
torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN);
|
||||
io.ntrename.in.old_name = fname2;
|
||||
io.ntrename.in.new_name = fname1;
|
||||
io.ntrename.in.attrib = 0;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
printf("Checking hard link\n");
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.flags = RENAME_FLAG_HARD_LINK;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname2;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 2);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
|
||||
|
||||
finfo.generic.in.file.path = fname1;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 2);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
|
||||
|
||||
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
smbcli_unlink(cli->tree, fname2);
|
||||
|
||||
finfo.generic.in.file.path = fname1;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
printf("Checking copy\n");
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.flags = RENAME_FLAG_COPY;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname1;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname2;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.generic.in.file.path = fname2;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
finfo.generic.in.file.path = fname1;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
|
||||
|
||||
torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
smbcli_unlink(cli->tree, fname2);
|
||||
|
||||
finfo.generic.in.file.path = fname1;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.all_info.out.nlink, 1);
|
||||
|
||||
printf("Checking invalid flags\n");
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.flags = 0;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
io.ntrename.in.flags = 300;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
io.ntrename.in.flags = 0x106;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
printf("Checking unknown field\n");
|
||||
io.ntrename.in.old_name = fname1;
|
||||
io.ntrename.in.new_name = fname2;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.flags = RENAME_FLAG_RENAME;
|
||||
io.ntrename.in.cluster_size = 0xff;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n");
|
||||
|
||||
io.ntrename.in.old_name = fname2;
|
||||
io.ntrename.in.new_name = fname1;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
|
||||
io.ntrename.in.cluster_size = 1;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
|
||||
|
||||
io.ntrename.in.flags = RENAME_FLAG_COPY;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
#if 0
|
||||
{
|
||||
char buf[16384];
|
||||
fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE);
|
||||
memset(buf, 1, sizeof(buf));
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE);
|
||||
memset(buf, 1, sizeof(buf));
|
||||
smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1);
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
torture_all_info(cli->tree, fname1);
|
||||
torture_all_info(cli->tree, fname2);
|
||||
}
|
||||
|
||||
|
||||
io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
|
||||
|
||||
for (i=0;i<20000;i++) {
|
||||
io.ntrename.in.cluster_size = i;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
printf("i=%d status=%s\n", i, nt_errstr(status));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("Checking other flags\n");
|
||||
|
||||
for (i=0;i<0xFFF;i++) {
|
||||
if (i == RENAME_FLAG_RENAME ||
|
||||
i == RENAME_FLAG_HARD_LINK ||
|
||||
i == RENAME_FLAG_COPY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
io.ntrename.in.old_name = fname2;
|
||||
io.ntrename.in.new_name = fname1;
|
||||
io.ntrename.in.flags = i;
|
||||
io.ntrename.in.attrib = 0;
|
||||
io.ntrename.in.cluster_size = 0;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
|
||||
printf("flags=0x%x status=%s\n", i, nt_errstr(status));
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of rename calls
|
||||
*/
|
||||
BOOL torture_raw_rename(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_rename");
|
||||
|
||||
if (!test_mv(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_ntrename(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Test samba3 hide unreadable/unwriteable
|
||||
Copyright (C) Volker Lendecke 2006
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
static void init_unixinfo_nochange(union smb_setfileinfo *info)
|
||||
{
|
||||
ZERO_STRUCTP(info);
|
||||
info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
|
||||
info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
|
||||
|
||||
info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
|
||||
info->unix_basic.in.end_of_file <<= 32;
|
||||
info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
|
||||
|
||||
info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
|
||||
info->unix_basic.in.num_bytes <<= 32;
|
||||
info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
|
||||
|
||||
info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
|
||||
info->unix_basic.in.status_change_time <<= 32;
|
||||
info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_LO;
|
||||
|
||||
info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
|
||||
info->unix_basic.in.access_time <<= 32;
|
||||
info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
|
||||
|
||||
info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
|
||||
info->unix_basic.in.change_time <<= 32;
|
||||
info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
|
||||
|
||||
info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
|
||||
info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
|
||||
}
|
||||
|
||||
struct list_state {
|
||||
const char *fname;
|
||||
BOOL visible;
|
||||
};
|
||||
|
||||
static void set_visible(struct clilist_file_info *i, const char *mask,
|
||||
void *priv)
|
||||
{
|
||||
struct list_state *state = priv;
|
||||
|
||||
if (strcasecmp_m(state->fname, i->name) == 0)
|
||||
state->visible = True;
|
||||
}
|
||||
|
||||
static BOOL is_visible(struct smbcli_tree *tree, const char *fname)
|
||||
{
|
||||
struct list_state state;
|
||||
|
||||
state.visible = False;
|
||||
state.fname = fname;
|
||||
|
||||
if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
|
||||
return False;
|
||||
}
|
||||
return state.visible;
|
||||
}
|
||||
|
||||
static BOOL is_readable(struct smbcli_tree *tree, const char *fname)
|
||||
{
|
||||
int fnum;
|
||||
fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
|
||||
if (fnum < 0) {
|
||||
return False;
|
||||
}
|
||||
smbcli_close(tree, fnum);
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
|
||||
const char *fname)
|
||||
{
|
||||
int fnum;
|
||||
fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
|
||||
if (fnum < 0) {
|
||||
return False;
|
||||
}
|
||||
smbcli_close(tree, fnum);
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is not an exact method because there's a ton of reasons why a getatr
|
||||
* might fail. But for our purposes it's sufficient.
|
||||
*/
|
||||
|
||||
static BOOL smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
|
||||
{
|
||||
return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
|
||||
uint64_t permissions)
|
||||
{
|
||||
union smb_setfileinfo sfinfo;
|
||||
init_unixinfo_nochange(&sfinfo);
|
||||
sfinfo.unix_basic.in.file.path = fname;
|
||||
sfinfo.unix_basic.in.permissions = permissions;
|
||||
return smb_raw_setpathinfo(tree, &sfinfo);
|
||||
}
|
||||
|
||||
BOOL torture_samba3_hide(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
const char *fname = "test.txt";
|
||||
int fnum;
|
||||
NTSTATUS status;
|
||||
struct smbcli_tree *hideunread;
|
||||
struct smbcli_tree *hideunwrite;
|
||||
|
||||
if (!torture_open_connection_share(
|
||||
torture, &cli, torture_setting_string(torture, "host", NULL),
|
||||
torture_setting_string(torture, "share", NULL), NULL)) {
|
||||
d_printf("torture_open_connection_share failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
status = torture_second_tcon(torture, cli->session, "hideunread",
|
||||
&hideunread);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("second_tcon(hideunread) failed: %s\n",
|
||||
nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
status = torture_second_tcon(torture, cli->session, "hideunwrite",
|
||||
&hideunwrite);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("second_tcon(hideunwrite) failed: %s\n",
|
||||
nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
status = smbcli_unlink(cli->tree, fname);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
|
||||
smbcli_setatr(cli->tree, fname, 0, -1);
|
||||
smbcli_unlink(cli->tree, fname);
|
||||
}
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
d_printf("Failed to create %s - %s\n", fname,
|
||||
smbcli_errstr(cli->tree));
|
||||
return False;
|
||||
}
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
if (!smbcli_file_exists(cli->tree, fname)) {
|
||||
d_printf("%s does not exist\n", fname);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* R/W file should be visible everywhere */
|
||||
|
||||
status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
if (!is_writeable(torture, cli->tree, fname)) {
|
||||
d_printf("File not writable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_readable(cli->tree, fname)) {
|
||||
d_printf("File not readable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(cli->tree, fname)) {
|
||||
d_printf("r/w file not visible via normal share\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(hideunread, fname)) {
|
||||
d_printf("r/w file not visible via hide unreadable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(hideunwrite, fname)) {
|
||||
d_printf("r/w file not visible via hide unwriteable\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/* R/O file should not be visible via hide unwriteable files */
|
||||
|
||||
status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
if (is_writeable(torture, cli->tree, fname)) {
|
||||
d_printf("r/o is writable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_readable(cli->tree, fname)) {
|
||||
d_printf("r/o not readable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(cli->tree, fname)) {
|
||||
d_printf("r/o file not visible via normal share\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(hideunread, fname)) {
|
||||
d_printf("r/o file not visible via hide unreadable\n");
|
||||
return False;
|
||||
}
|
||||
if (is_visible(hideunwrite, fname)) {
|
||||
d_printf("r/o file visible via hide unwriteable\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/* inaccessible file should be only visible on normal share */
|
||||
|
||||
status = smbcli_chmod(cli->tree, fname, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smbcli_chmod failed: %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
if (is_writeable(torture, cli->tree, fname)) {
|
||||
d_printf("inaccessible file is writable\n");
|
||||
return False;
|
||||
}
|
||||
if (is_readable(cli->tree, fname)) {
|
||||
d_printf("inaccessible file is readable\n");
|
||||
return False;
|
||||
}
|
||||
if (!is_visible(cli->tree, fname)) {
|
||||
d_printf("inaccessible file not visible via normal share\n");
|
||||
return False;
|
||||
}
|
||||
if (is_visible(hideunread, fname)) {
|
||||
d_printf("inaccessible file visible via hide unreadable\n");
|
||||
return False;
|
||||
}
|
||||
if (is_visible(hideunwrite, fname)) {
|
||||
d_printf("inaccessible file visible via hide unwriteable\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Test some misc Samba3 code paths
|
||||
Copyright (C) Volker Lendecke 2006
|
||||
|
||||
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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.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; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
BOOL torture_samba3_checkfsp(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
const char *fname = "test.txt";
|
||||
const char *dirname = "testdir";
|
||||
int fnum;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
ssize_t nread;
|
||||
char buf[16];
|
||||
struct smbcli_tree *tree2;
|
||||
|
||||
if ((mem_ctx = talloc_init("torture_samba3_checkfsp")) == NULL) {
|
||||
d_printf("talloc_init failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!torture_open_connection_share(
|
||||
torture, &cli, torture_setting_string(torture, "host", NULL),
|
||||
torture_setting_string(torture, "share", NULL), NULL)) {
|
||||
d_printf("torture_open_connection_share failed\n");
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
smbcli_deltree(cli->tree, dirname);
|
||||
|
||||
status = torture_second_tcon(torture, cli->session,
|
||||
torture_setting_string(torture, "share", NULL),
|
||||
&tree2);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
if (!NT_STATUS_IS_OK(status))
|
||||
goto done;
|
||||
|
||||
/* Try a read on an invalid FID */
|
||||
|
||||
nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf));
|
||||
CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
/* Try a read on a directory handle */
|
||||
|
||||
status = smbcli_mkdir(cli->tree, dirname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Open the directory */
|
||||
{
|
||||
union smb_open io;
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.fname = dirname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smb_open on the directory failed: %s\n",
|
||||
nt_errstr(status));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
}
|
||||
|
||||
/* Try a read on the directory */
|
||||
|
||||
nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf));
|
||||
if (nread >= 0) {
|
||||
d_printf("smbcli_read on a directory succeeded, expected "
|
||||
"failure\n");
|
||||
ret = False;
|
||||
}
|
||||
|
||||
CHECK_STATUS(smbcli_nt_error(cli->tree),
|
||||
NT_STATUS_INVALID_DEVICE_REQUEST);
|
||||
|
||||
/* Same test on the second tcon */
|
||||
|
||||
nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
|
||||
if (nread >= 0) {
|
||||
d_printf("smbcli_read on a directory succeeded, expected "
|
||||
"failure\n");
|
||||
ret = False;
|
||||
}
|
||||
|
||||
CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
/* Try a normal file read on a second tcon */
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
d_printf("Failed to create %s - %s\n", fname,
|
||||
smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
|
||||
CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
done:
|
||||
smbcli_deltree(cli->tree, dirname);
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
|
||||
{
|
||||
union smb_open open_parms;
|
||||
uint_t openfn=0;
|
||||
uint_t accessmode=0;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
NTSTATUS status;
|
||||
|
||||
mem_ctx = talloc_init("raw_open");
|
||||
if (!mem_ctx) return NT_STATUS_NO_MEMORY;
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
openfn |= OPENX_OPEN_FUNC_CREATE;
|
||||
}
|
||||
if (!(flags & O_EXCL)) {
|
||||
if (flags & O_TRUNC) {
|
||||
openfn |= OPENX_OPEN_FUNC_TRUNC;
|
||||
} else {
|
||||
openfn |= OPENX_OPEN_FUNC_OPEN;
|
||||
}
|
||||
}
|
||||
|
||||
accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDWR) {
|
||||
accessmode |= OPENX_MODE_ACCESS_RDWR;
|
||||
} else if ((flags & O_ACCMODE) == O_WRONLY) {
|
||||
accessmode |= OPENX_MODE_ACCESS_WRITE;
|
||||
}
|
||||
|
||||
#if defined(O_SYNC)
|
||||
if ((flags & O_SYNC) == O_SYNC) {
|
||||
accessmode |= OPENX_MODE_WRITE_THRU;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (share_mode == DENY_FCB) {
|
||||
accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
|
||||
}
|
||||
|
||||
open_parms.openx.level = RAW_OPEN_OPENX;
|
||||
open_parms.openx.in.flags = 0;
|
||||
open_parms.openx.in.open_mode = accessmode;
|
||||
open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
|
||||
open_parms.openx.in.file_attrs = 0;
|
||||
open_parms.openx.in.write_time = 0;
|
||||
open_parms.openx.in.open_func = openfn;
|
||||
open_parms.openx.in.size = 0;
|
||||
open_parms.openx.in.timeout = 0;
|
||||
open_parms.openx.in.fname = fname;
|
||||
|
||||
status = smb_raw_open(tree, mem_ctx, &open_parms);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
if (fnum && NT_STATUS_IS_OK(status)) {
|
||||
*fnum = open_parms.openx.out.file.fnum;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL torture_samba3_badpath(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli_nt;
|
||||
struct smbcli_state *cli_dos;
|
||||
const char *fname = "test.txt";
|
||||
const char *dirname = "testdir";
|
||||
char *fpath;
|
||||
int fnum;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
BOOL nt_status_support;
|
||||
|
||||
if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
|
||||
d_printf("talloc_init failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
nt_status_support = lp_nt_status_support();
|
||||
|
||||
if (!lp_set_cmdline("nt status support", "yes")) {
|
||||
printf("Could not set 'nt status support = yes'\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!torture_open_connection(&cli_nt, 0)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!lp_set_cmdline("nt status support", "no")) {
|
||||
printf("Could not set 'nt status support = yes'\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!torture_open_connection(&cli_dos, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!lp_set_cmdline("nt status support",
|
||||
nt_status_support ? "yes":"no")) {
|
||||
printf("Could not reset 'nt status support = yes'");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
smbcli_deltree(cli_nt->tree, dirname);
|
||||
|
||||
status = smbcli_mkdir(cli_nt->tree, dirname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, dirname);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree,
|
||||
talloc_asprintf(mem_ctx, "%s\\bla", dirname));
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
status = smbcli_chkpath(cli_dos->tree,
|
||||
talloc_asprintf(mem_ctx, "%s\\bla", dirname));
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree,
|
||||
talloc_asprintf(mem_ctx, "%s\\bla\\blub",
|
||||
dirname));
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
|
||||
status = smbcli_chkpath(cli_dos->tree,
|
||||
talloc_asprintf(mem_ctx, "%s\\bla\\blub",
|
||||
dirname));
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
|
||||
goto fail;
|
||||
}
|
||||
fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
d_printf("Could not create file %s: %s\n", fpath,
|
||||
smbcli_errstr(cli_nt->tree));
|
||||
goto fail;
|
||||
}
|
||||
smbcli_close(cli_nt->tree, fnum);
|
||||
|
||||
/*
|
||||
* Do a whole bunch of error code checks on chkpath
|
||||
*/
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, fpath);
|
||||
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
|
||||
status = smbcli_chkpath(cli_dos->tree, fpath);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, "..");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
status = smbcli_chkpath(cli_dos->tree, "..");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, ".");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_chkpath(cli_dos->tree, ".");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, "\t");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_chkpath(cli_dos->tree, "\t");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, "\t\\bla");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_chkpath(cli_dos->tree, "\t\\bla");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, "<");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_chkpath(cli_dos->tree, "<");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
status = smbcli_chkpath(cli_nt->tree, "<\\bla");
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_chkpath(cli_dos->tree, "<\\bla");
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
|
||||
|
||||
/*
|
||||
* .... And the same gang against getatr. Note that the DOS error codes
|
||||
* differ....
|
||||
*/
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
/* Try the same set with openX. */
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
|
||||
CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
|
||||
|
||||
goto done;
|
||||
|
||||
fail:
|
||||
ret = False;
|
||||
|
||||
done:
|
||||
if (cli_nt != NULL) {
|
||||
smbcli_deltree(cli_nt->tree, dirname);
|
||||
torture_close_connection(cli_nt);
|
||||
}
|
||||
if (cli_dos != NULL) {
|
||||
torture_close_connection(cli_dos);
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
seek test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define CHECK_STATUS(status, correct) do { \
|
||||
if (!NT_STATUS_EQUAL(status, correct)) { \
|
||||
printf("(%d) Incorrect status %s - should be %s\n", \
|
||||
__LINE__, nt_errstr(status), nt_errstr(correct)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%d) Incorrect value %s=%d - should be %d\n", \
|
||||
__LINE__, #v, (int)v, (int)correct); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define BASEDIR "\\testseek"
|
||||
|
||||
/*
|
||||
test seek ops
|
||||
*/
|
||||
static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_seek io;
|
||||
union smb_fileinfo finfo;
|
||||
union smb_setfileinfo sfinfo;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum, fnum2;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint8_t c[2];
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
|
||||
if (fnum == -1) {
|
||||
printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
|
||||
printf("Trying bad handle\n");
|
||||
io.lseek.in.file.fnum = fnum+1;
|
||||
io.lseek.in.mode = SEEK_MODE_START;
|
||||
io.lseek.in.offset = 0;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("Trying simple seek\n");
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_START;
|
||||
io.lseek.in.offset = 17;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 17);
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 0);
|
||||
|
||||
printf("Trying relative seek\n");
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_CURRENT;
|
||||
io.lseek.in.offset = -3;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 14);
|
||||
|
||||
printf("Trying end seek\n");
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_END;
|
||||
io.lseek.in.offset = 0;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
finfo.generic.level = RAW_FILEINFO_ALL_INFO;
|
||||
finfo.all_info.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size);
|
||||
|
||||
printf("Trying max seek\n");
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_START;
|
||||
io.lseek.in.offset = -1;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 0xffffffff);
|
||||
|
||||
printf("Testing position information change\n");
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 0);
|
||||
|
||||
printf("Trying max overflow\n");
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_CURRENT;
|
||||
io.lseek.in.offset = 1000;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 999);
|
||||
|
||||
printf("Testing position information change\n");
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 0);
|
||||
|
||||
printf("trying write to update offset\n");
|
||||
ZERO_STRUCT(c);
|
||||
if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) {
|
||||
printf("Write failed - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Testing position information change\n");
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 0);
|
||||
|
||||
io.lseek.in.file.fnum = fnum;
|
||||
io.lseek.in.mode = SEEK_MODE_CURRENT;
|
||||
io.lseek.in.offset = 0;
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 2);
|
||||
|
||||
if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) {
|
||||
printf("Read failed - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Testing position information change\n");
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 1);
|
||||
|
||||
status = smb_raw_seek(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.lseek.out.offset, 1);
|
||||
|
||||
printf("Testing position information\n");
|
||||
fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
|
||||
if (fnum2 == -1) {
|
||||
printf("2nd open failed - %s\n", smbcli_errstr(cli->tree));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
|
||||
sfinfo.position_information.in.file.fnum = fnum2;
|
||||
sfinfo.position_information.in.position = 25;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum2;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 25);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 1);
|
||||
|
||||
printf("position_information via paths\n");
|
||||
|
||||
sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
|
||||
sfinfo.position_information.in.file.path = fname;
|
||||
sfinfo.position_information.in.position = 32;
|
||||
status = smb_raw_setpathinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.fnum = fnum2;
|
||||
status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 25);
|
||||
|
||||
finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
|
||||
finfo.position_information.in.file.path = fname;
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(finfo.position_information.out.position, 0);
|
||||
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of seek calls
|
||||
*/
|
||||
BOOL torture_raw_seek(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_seek");
|
||||
|
||||
if (!test_seek(cli, mem_ctx)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_SFILEINFO_* individual test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "system/time.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\testsfileinfo"
|
||||
|
||||
/* basic testing of all RAW_SFILEINFO_* calls
|
||||
for each call we test that it succeeds, and where possible test
|
||||
for consistency between the calls.
|
||||
*/
|
||||
BOOL torture_raw_sfileinfo(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
int fnum_saved, d_fnum, fnum2, fnum = -1;
|
||||
char *fnum_fname;
|
||||
char *fnum_fname_new;
|
||||
char *path_fname;
|
||||
char *path_fname_new;
|
||||
union smb_fileinfo finfo1, finfo2;
|
||||
union smb_setfileinfo sfinfo;
|
||||
NTSTATUS status, status2;
|
||||
const char *call_name;
|
||||
time_t basetime = (time(NULL) - 86400) & ~1;
|
||||
BOOL check_fnum;
|
||||
int n = time(NULL) % 100;
|
||||
|
||||
asprintf(&path_fname, BASEDIR "\\fname_test_%d.txt", n);
|
||||
asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n);
|
||||
asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n);
|
||||
asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n);
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_sfileinfo");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
#define RECREATE_FILE(fname) do { \
|
||||
if (fnum != -1) smbcli_close(cli->tree, fnum); \
|
||||
fnum = create_complex_file(cli, mem_ctx, fname); \
|
||||
if (fnum == -1) { \
|
||||
printf("(%s) ERROR: open of %s failed (%s)\n", \
|
||||
__location__, fname, smbcli_errstr(cli->tree)); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define RECREATE_BOTH do { \
|
||||
RECREATE_FILE(path_fname); \
|
||||
smbcli_close(cli->tree, fnum); \
|
||||
RECREATE_FILE(fnum_fname); \
|
||||
} while (0)
|
||||
|
||||
RECREATE_BOTH;
|
||||
|
||||
#define CHECK_CALL_FNUM(call, rightstatus) do { \
|
||||
check_fnum = True; \
|
||||
call_name = #call; \
|
||||
sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
|
||||
sfinfo.generic.in.file.fnum = fnum; \
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
|
||||
if (!NT_STATUS_EQUAL(status, rightstatus)) { \
|
||||
printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
|
||||
nt_errstr(status), nt_errstr(rightstatus)); \
|
||||
ret = False; \
|
||||
} \
|
||||
finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
|
||||
finfo1.generic.in.file.fnum = fnum; \
|
||||
status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1); \
|
||||
if (!NT_STATUS_IS_OK(status2)) { \
|
||||
printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_CALL_PATH(call, rightstatus) do { \
|
||||
check_fnum = False; \
|
||||
call_name = #call; \
|
||||
sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
|
||||
sfinfo.generic.in.file.path = path_fname; \
|
||||
status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
|
||||
sfinfo.generic.in.file.path = path_fname_new; \
|
||||
status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
|
||||
} \
|
||||
if (!NT_STATUS_EQUAL(status, rightstatus)) { \
|
||||
printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
|
||||
nt_errstr(status), nt_errstr(rightstatus)); \
|
||||
ret = False; \
|
||||
} \
|
||||
finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
|
||||
finfo1.generic.in.file.path = path_fname; \
|
||||
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo1); \
|
||||
if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
|
||||
finfo1.generic.in.file.path = path_fname_new; \
|
||||
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo1); \
|
||||
} \
|
||||
if (!NT_STATUS_IS_OK(status2)) { \
|
||||
printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status2)); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK1(call) \
|
||||
do { if (NT_STATUS_IS_OK(status)) { \
|
||||
finfo2.generic.level = RAW_FILEINFO_ ## call; \
|
||||
if (check_fnum) { \
|
||||
finfo2.generic.in.file.fnum = fnum; \
|
||||
status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2); \
|
||||
} else { \
|
||||
finfo2.generic.in.file.path = path_fname; \
|
||||
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); \
|
||||
if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
|
||||
finfo2.generic.in.file.path = path_fname_new; \
|
||||
status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); \
|
||||
} \
|
||||
} \
|
||||
if (!NT_STATUS_IS_OK(status2)) { \
|
||||
printf("%s - %s\n", #call, nt_errstr(status2)); \
|
||||
ret = False; \
|
||||
} \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_VALUE(call, stype, field, value) do { \
|
||||
CHECK1(call); \
|
||||
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
|
||||
printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
|
||||
call_name, #stype, #field, \
|
||||
(uint_t)value, (uint_t)finfo2.stype.out.field); \
|
||||
dump_all_info(mem_ctx, &finfo1); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_TIME(call, stype, field, value) do { \
|
||||
CHECK1(call); \
|
||||
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
|
||||
printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
|
||||
call_name, #stype, #field, \
|
||||
(uint_t)value, \
|
||||
(uint_t)nt_time_to_unix(finfo2.stype.out.field)); \
|
||||
printf("\t%s", timestring(mem_ctx, value)); \
|
||||
printf("\t%s\n", nt_time_string(mem_ctx, finfo2.stype.out.field)); \
|
||||
dump_all_info(mem_ctx, &finfo1); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_STR(call, stype, field, value) do { \
|
||||
CHECK1(call); \
|
||||
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \
|
||||
printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \
|
||||
call_name, #stype, #field, \
|
||||
value, \
|
||||
finfo2.stype.out.field); \
|
||||
dump_all_info(mem_ctx, &finfo1); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
printf("test setattr\n");
|
||||
sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
|
||||
sfinfo.setattr.in.write_time = basetime;
|
||||
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
|
||||
CHECK_VALUE (ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
|
||||
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
|
||||
|
||||
printf("setting to NORMAL doesn't do anything\n");
|
||||
sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_NORMAL;
|
||||
sfinfo.setattr.in.write_time = 0;
|
||||
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
|
||||
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
|
||||
|
||||
printf("a zero write_time means don't change\n");
|
||||
sfinfo.setattr.in.attrib = 0;
|
||||
sfinfo.setattr.in.write_time = 0;
|
||||
CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
|
||||
|
||||
printf("test setattre\n");
|
||||
sfinfo.setattre.in.create_time = basetime + 20;
|
||||
sfinfo.setattre.in.access_time = basetime + 30;
|
||||
sfinfo.setattre.in.write_time = basetime + 40;
|
||||
CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
|
||||
|
||||
sfinfo.setattre.in.create_time = 0;
|
||||
sfinfo.setattre.in.access_time = 0;
|
||||
sfinfo.setattre.in.write_time = 0;
|
||||
CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
|
||||
|
||||
printf("test standard level\n");
|
||||
sfinfo.standard.in.create_time = basetime + 100;
|
||||
sfinfo.standard.in.access_time = basetime + 200;
|
||||
sfinfo.standard.in.write_time = basetime + 300;
|
||||
CHECK_CALL_FNUM(STANDARD, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
|
||||
printf("test basic_info level\n");
|
||||
basetime += 86400;
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
|
||||
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
|
||||
CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
|
||||
|
||||
printf("a zero time means don't change\n");
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
|
||||
sfinfo.basic_info.in.attrib = 0;
|
||||
CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
|
||||
|
||||
printf("test basic_information level\n");
|
||||
basetime += 86400;
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
|
||||
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
|
||||
CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
printf("a zero time means don't change\n");
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
|
||||
unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
|
||||
sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
|
||||
CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
|
||||
CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
|
||||
CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
|
||||
|
||||
/* interesting - w2k3 leaves change_time as current time for 0 change time
|
||||
in setpathinfo
|
||||
CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
|
||||
*/
|
||||
CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
printf("test disposition_info level\n");
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
|
||||
|
||||
sfinfo.disposition_info.in.delete_on_close = 0;
|
||||
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
|
||||
|
||||
printf("test disposition_information level\n");
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
|
||||
|
||||
/* this would delete the file! */
|
||||
/*
|
||||
CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
|
||||
*/
|
||||
|
||||
sfinfo.disposition_info.in.delete_on_close = 0;
|
||||
CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
|
||||
|
||||
CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
|
||||
|
||||
printf("test allocation_info level\n");
|
||||
sfinfo.allocation_info.in.alloc_size = 0;
|
||||
CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
|
||||
|
||||
sfinfo.allocation_info.in.alloc_size = 4096;
|
||||
CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
|
||||
RECREATE_BOTH;
|
||||
sfinfo.allocation_info.in.alloc_size = 0;
|
||||
CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
|
||||
|
||||
CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
|
||||
|
||||
sfinfo.allocation_info.in.alloc_size = 4096;
|
||||
CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
|
||||
/* setting the allocation size up via setpathinfo seems
|
||||
to be broken in w2k3 */
|
||||
CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 0);
|
||||
|
||||
printf("test end_of_file_info level\n");
|
||||
sfinfo.end_of_file_info.in.size = 37;
|
||||
CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 37);
|
||||
|
||||
sfinfo.end_of_file_info.in.size = 7;
|
||||
CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 7);
|
||||
|
||||
sfinfo.end_of_file_info.in.size = 37;
|
||||
CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 37);
|
||||
|
||||
CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 37);
|
||||
|
||||
sfinfo.end_of_file_info.in.size = 7;
|
||||
CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 7);
|
||||
|
||||
CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(ALL_INFO, all_info, size, 7);
|
||||
|
||||
printf("test position_information level\n");
|
||||
sfinfo.position_information.in.position = 123456;
|
||||
CHECK_CALL_FNUM(POSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
|
||||
|
||||
CHECK_CALL_PATH(POSITION_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(POSITION_INFORMATION, position_information, position, 0);
|
||||
|
||||
printf("test mode_information level\n");
|
||||
sfinfo.mode_information.in.mode = 2;
|
||||
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
|
||||
|
||||
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
|
||||
|
||||
sfinfo.mode_information.in.mode = 1;
|
||||
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
|
||||
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
|
||||
|
||||
sfinfo.mode_information.in.mode = 0;
|
||||
CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
|
||||
|
||||
CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
|
||||
#if 1
|
||||
printf("finally the rename_information level\n");
|
||||
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, fnum_fname_new));
|
||||
smbcli_close(cli->tree, create_complex_file(cli, mem_ctx, path_fname_new));
|
||||
|
||||
sfinfo.rename_information.in.overwrite = 0;
|
||||
sfinfo.rename_information.in.root_fid = 0;
|
||||
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
|
||||
|
||||
sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
|
||||
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
|
||||
|
||||
sfinfo.rename_information.in.new_name = fnum_fname_new;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
|
||||
|
||||
printf("Trying rename with dest file open\n");
|
||||
fnum2 = create_complex_file(cli, mem_ctx, fnum_fname);
|
||||
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
|
||||
|
||||
fnum_saved = fnum;
|
||||
fnum = fnum2;
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
|
||||
fnum = fnum_saved;
|
||||
|
||||
printf("Trying rename with dest file open and delete_on_close\n");
|
||||
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
|
||||
|
||||
printf("Trying rename with source file open twice\n");
|
||||
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
|
||||
|
||||
fnum2 = create_complex_file(cli, mem_ctx, fnum_fname);
|
||||
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 0;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 0;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
|
||||
|
||||
sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.overwrite = 1;
|
||||
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new);
|
||||
|
||||
sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
|
||||
|
||||
sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1;
|
||||
CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, path_fname);
|
||||
|
||||
printf("Trying rename with a root fid\n");
|
||||
status = create_directory_handle(cli->tree, BASEDIR, &d_fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
|
||||
sfinfo.rename_information.in.root_fid = d_fnum;
|
||||
CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER);
|
||||
CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printf("test unix_basic level\n");
|
||||
CHECK_CALL_FNUM(UNIX_BASIC, NT_STATUS_OK);
|
||||
CHECK_CALL_PATH(UNIX_BASIC, NT_STATUS_OK);
|
||||
|
||||
printf("test unix_link level\n");
|
||||
CHECK_CALL_FNUM(UNIX_LINK, NT_STATUS_OK);
|
||||
CHECK_CALL_PATH(UNIX_LINK, NT_STATUS_OK);
|
||||
#endif
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_close(cli->tree, fnum);
|
||||
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) {
|
||||
printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree));
|
||||
}
|
||||
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) {
|
||||
printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree));
|
||||
}
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
look for the w2k3 setpathinfo STANDARD bug
|
||||
*/
|
||||
BOOL torture_raw_sfileinfo_bug(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
const char *fname = "\\bug3.txt";
|
||||
union smb_setfileinfo sfinfo;
|
||||
NTSTATUS status;
|
||||
int fnum;
|
||||
|
||||
if (!torture_setting_bool(torture, "dangerous", False)) {
|
||||
printf("torture_raw_sfileinfo_bug disabled - enable dangerous tests to use\n");
|
||||
return True;
|
||||
}
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_sfileinfo");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
sfinfo.generic.level = RAW_SFILEINFO_STANDARD;
|
||||
sfinfo.generic.in.file.path = fname;
|
||||
|
||||
sfinfo.standard.in.create_time = 0;
|
||||
sfinfo.standard.in.access_time = 0;
|
||||
sfinfo.standard.in.write_time = 0;
|
||||
|
||||
status = smb_raw_setpathinfo(cli->tree, &sfinfo);
|
||||
printf("%s - %s\n", fname, nt_errstr(status));
|
||||
|
||||
printf("now try and delete %s\n", fname);
|
||||
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
test alternate data streams
|
||||
|
||||
Copyright (C) Andrew Tridgell 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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.h"
|
||||
|
||||
#define BASEDIR "\\teststreams"
|
||||
|
||||
#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 CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%s) Incorrect value %s=%d - should be %d\n", \
|
||||
__location__, #v, (int)v, (int)correct); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
/*
|
||||
check that a stream has the right contents
|
||||
*/
|
||||
static BOOL check_stream(struct smbcli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *fname, const char *sname,
|
||||
const char *value)
|
||||
{
|
||||
int fnum;
|
||||
const char *full_name;
|
||||
uint8_t *buf;
|
||||
ssize_t ret;
|
||||
|
||||
full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
|
||||
|
||||
fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
|
||||
|
||||
if (value == NULL) {
|
||||
if (fnum != -1) {
|
||||
printf("should have failed stream open of %s\n", full_name);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("Failed to open stream '%s' - %s\n",
|
||||
full_name, smbcli_errstr(cli->tree));
|
||||
return False;
|
||||
}
|
||||
|
||||
buf = talloc_size(mem_ctx, strlen(value)+11);
|
||||
|
||||
ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
|
||||
if (ret != strlen(value)) {
|
||||
printf("Failed to read %lu bytes from stream '%s' - got %d\n",
|
||||
(long)strlen(value), full_name, (int)ret);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (memcmp(buf, value, strlen(value)) != 0) {
|
||||
printf("Bad data in stream\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test basic io on streams
|
||||
*/
|
||||
static BOOL test_stream_io(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
union smb_open io;
|
||||
const char *fname = BASEDIR "\\stream.txt";
|
||||
const char *sname1, *sname2;
|
||||
BOOL ret = True;
|
||||
int fnum = -1;
|
||||
ssize_t retsize;
|
||||
|
||||
sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
|
||||
sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream");
|
||||
|
||||
printf("opening non-existant directory stream\n");
|
||||
io.generic.level = RAW_OPEN_NTCREATEX;
|
||||
io.ntcreatex.in.root_fid = 0;
|
||||
io.ntcreatex.in.flags = 0;
|
||||
io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
|
||||
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
|
||||
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io.ntcreatex.in.share_access = 0;
|
||||
io.ntcreatex.in.alloc_size = 0;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
|
||||
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io.ntcreatex.in.security_flags = 0;
|
||||
io.ntcreatex.in.fname = sname1;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
|
||||
|
||||
printf("creating a stream on a non-existant file\n");
|
||||
io.ntcreatex.in.create_options = 0;
|
||||
io.ntcreatex.in.fname = sname1;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One", NULL);
|
||||
|
||||
printf("check that open of base file is allowed\n");
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
io.ntcreatex.in.fname = fname;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
|
||||
|
||||
printf("writing to stream\n");
|
||||
retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
|
||||
CHECK_VALUE(retsize, 9);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One", "test data");
|
||||
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
io.ntcreatex.in.fname = sname1;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("modifying stream\n");
|
||||
retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
|
||||
CHECK_VALUE(retsize, 10);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One:$FOO", NULL);
|
||||
|
||||
printf("creating a stream2 on a existing file\n");
|
||||
io.ntcreatex.in.fname = sname2;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
printf("modifying stream\n");
|
||||
retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
|
||||
CHECK_VALUE(retsize, 13);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One", "test MORE DATA ");
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One:$DATA", "test MORE DATA ");
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Stream One:", NULL);
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Second Stream", "SECOND STREAM");
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:$DATA", "SECOND STREAM");
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:", NULL);
|
||||
ret &= check_stream(cli, mem_ctx, fname, "Second Stream:$FOO", NULL);
|
||||
|
||||
printf("deleting stream\n");
|
||||
status = smbcli_unlink(cli->tree, sname1);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("delete a stream via delete-on-close\n");
|
||||
io.ntcreatex.in.fname = sname2;
|
||||
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
||||
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = io.ntcreatex.out.file.fnum;
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
status = smbcli_unlink(cli->tree, sname2);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
|
||||
printf("deleting file\n");
|
||||
status = smbcli_unlink(cli->tree, fname);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
basic testing of streams calls
|
||||
*/
|
||||
BOOL torture_raw_streams(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_streams");
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ret &= test_stream_io(cli, mem_ctx);
|
||||
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
unlink test suite
|
||||
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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.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 "\\testunlink"
|
||||
|
||||
/*
|
||||
test unlink ops
|
||||
*/
|
||||
static BOOL test_unlink(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_unlink io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Trying non-existant file\n");
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
||||
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Trying a hidden file\n");
|
||||
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
||||
torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
|
||||
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
printf("Trying a directory\n");
|
||||
io.unlink.in.pattern = BASEDIR;
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR;
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
||||
|
||||
printf("Trying a bad path\n");
|
||||
io.unlink.in.pattern = "..";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
|
||||
io.unlink.in.pattern = "\\..";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\..\\..";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\..";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
|
||||
|
||||
printf("Trying wildcards\n");
|
||||
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
||||
io.unlink.in.pattern = BASEDIR "\\t*.t";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\z*";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\z*";
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\*";
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\?";
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\t*";
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\*.dat";
|
||||
io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
io.unlink.in.pattern = BASEDIR "\\*.tx?";
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
|
||||
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test delete on close
|
||||
*/
|
||||
static BOOL test_delete_on_close(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_open op;
|
||||
union smb_unlink io;
|
||||
struct smb_rmdir dio;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum, fnum2;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
const char *dname = BASEDIR "\\test.dir";
|
||||
const char *inside = BASEDIR "\\test.dir\\test.txt";
|
||||
union smb_setfileinfo sfinfo;
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
dio.in.path = dname;
|
||||
|
||||
io.unlink.in.pattern = fname;
|
||||
io.unlink.in.attrib = 0;
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
printf("Testing with delete_on_close 0\n");
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
|
||||
sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
sfinfo.disposition_info.in.delete_on_close = 0;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Testing with delete_on_close 1\n");
|
||||
fnum = create_complex_file(cli, mem_ctx, fname);
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_unlink(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
|
||||
printf("Testing with directory and delete_on_close 0\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
sfinfo.disposition_info.in.delete_on_close = 0;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
printf("Testing with directory delete_on_close 1\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
|
||||
printf("Testing with non-empty directory delete_on_close\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
fnum2 = create_complex_file(cli, mem_ctx, inside);
|
||||
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
sfinfo.disposition_info.in.delete_on_close = 1;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
sfinfo.disposition_info.in.file.fnum = fnum2;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
sfinfo.disposition_info.in.file.fnum = fnum;
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
printf("Testing open dir with delete_on_close\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
fnum2 = create_complex_file(cli, mem_ctx, inside);
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = dname;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
smbcli_deltree(cli->tree, dname);
|
||||
|
||||
printf("Testing double open dir with second delete_on_close\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
fnum2 = create_complex_file(cli, mem_ctx, inside);
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = dname;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = op.ntcreatex.out.file.fnum;
|
||||
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
smbcli_deltree(cli->tree, dname);
|
||||
|
||||
printf("Testing pre-existing open dir with second delete_on_close\n");
|
||||
status = create_directory_handle(cli->tree, dname, &fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, inside);
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
/* we have a dir with a file in it, no handles open */
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
|
||||
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = dname;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.file.fnum;
|
||||
|
||||
/* open without delete on close */
|
||||
op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum2 = op.ntcreatex.out.file.fnum;
|
||||
|
||||
/* close 2nd file handle */
|
||||
smbcli_close(cli->tree, fnum2);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
status = smb_raw_rmdir(cli->tree, &dio);
|
||||
CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
|
||||
|
||||
done:
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
basic testing of unlink calls
|
||||
*/
|
||||
BOOL torture_raw_unlink(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_unlink");
|
||||
|
||||
ret &= test_unlink(cli, mem_ctx);
|
||||
ret &= test_delete_on_close(cli, mem_ctx);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,730 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
test suite for various write 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 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"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/util.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 CHECK_VALUE(v, correct) do { \
|
||||
if ((v) != (correct)) { \
|
||||
printf("(%s) Incorrect value %s=%d - should be %d\n", \
|
||||
__location__, #v, v, correct); \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_BUFFER(buf, seed, len) do { \
|
||||
if (!check_buffer(buf, seed, len, __location__)) { \
|
||||
ret = False; \
|
||||
goto done; \
|
||||
}} while (0)
|
||||
|
||||
#define CHECK_ALL_INFO(v, field) do { \
|
||||
finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
|
||||
finfo.all_info.in.file.path = fname; \
|
||||
status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
|
||||
CHECK_STATUS(status, NT_STATUS_OK); \
|
||||
if ((v) != finfo.all_info.out.field) { \
|
||||
printf("(%s) wrong value for field %s %.0f - %.0f\n", \
|
||||
__location__, #field, (double)v, (double)finfo.all_info.out.field); \
|
||||
dump_all_info(mem_ctx, &finfo); \
|
||||
ret = False; \
|
||||
}} while (0)
|
||||
|
||||
|
||||
#define BASEDIR "\\testwrite"
|
||||
|
||||
|
||||
/*
|
||||
setup a random buffer based on a seed
|
||||
*/
|
||||
static void setup_buffer(uint8_t *buf, uint_t seed, int len)
|
||||
{
|
||||
int i;
|
||||
srandom(seed);
|
||||
for (i=0;i<len;i++) buf[i] = random();
|
||||
}
|
||||
|
||||
/*
|
||||
check a random buffer based on a seed
|
||||
*/
|
||||
static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, const char *location)
|
||||
{
|
||||
int i;
|
||||
srandom(seed);
|
||||
for (i=0;i<len;i++) {
|
||||
uint8_t v = random();
|
||||
if (buf[i] != v) {
|
||||
printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
|
||||
location, i, buf[i], v);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test write ops
|
||||
*/
|
||||
static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_write io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint_t seed = time(NULL);
|
||||
union smb_fileinfo finfo;
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_WRITE_WRITE\n");
|
||||
io.generic.level = RAW_WRITE_WRITE;
|
||||
|
||||
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 zero write\n");
|
||||
io.write.in.file.fnum = fnum;
|
||||
io.write.in.count = 0;
|
||||
io.write.in.offset = 0;
|
||||
io.write.in.remaining = 0;
|
||||
io.write.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.write.out.nwritten, 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying small write\n");
|
||||
io.write.in.count = 9;
|
||||
io.write.in.offset = 4;
|
||||
io.write.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying large write\n");
|
||||
io.write.in.count = 4000;
|
||||
io.write.in.offset = 0;
|
||||
io.write.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.write.out.nwritten, 4000);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.write.in.file.fnum = fnum+1;
|
||||
io.write.in.count = 4000;
|
||||
io.write.in.offset = 0;
|
||||
io.write.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("Setting file as sparse\n");
|
||||
status = torture_set_sparse(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying 2^32 offset\n");
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
io.write.in.file.fnum = fnum;
|
||||
io.write.in.count = 4000;
|
||||
io.write.in.offset = 0xFFFFFFFF - 2000;
|
||||
io.write.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.write.out.nwritten, 4000);
|
||||
CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test writex ops
|
||||
*/
|
||||
static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_write io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum, i;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint_t seed = time(NULL);
|
||||
union smb_fileinfo finfo;
|
||||
int max_bits=63;
|
||||
|
||||
if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
|
||||
max_bits=33;
|
||||
printf("dangerous not set - limiting range of test to 2^%d\n", max_bits);
|
||||
}
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_WRITE_WRITEX\n");
|
||||
io.generic.level = RAW_WRITE_WRITEX;
|
||||
|
||||
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 zero write\n");
|
||||
io.writex.in.file.fnum = fnum;
|
||||
io.writex.in.offset = 0;
|
||||
io.writex.in.wmode = 0;
|
||||
io.writex.in.remaining = 0;
|
||||
io.writex.in.count = 0;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying small write\n");
|
||||
io.writex.in.count = 9;
|
||||
io.writex.in.offset = 4;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying large write\n");
|
||||
io.writex.in.count = 4000;
|
||||
io.writex.in.offset = 0;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, 4000);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.writex.in.file.fnum = fnum+1;
|
||||
io.writex.in.count = 4000;
|
||||
io.writex.in.offset = 0;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("Testing wmode\n");
|
||||
io.writex.in.file.fnum = fnum;
|
||||
io.writex.in.count = 1;
|
||||
io.writex.in.offset = 0;
|
||||
io.writex.in.wmode = 1;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
|
||||
|
||||
io.writex.in.wmode = 2;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
|
||||
|
||||
|
||||
printf("Trying locked region\n");
|
||||
cli->session->pid++;
|
||||
if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
|
||||
printf("Failed to lock file at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
cli->session->pid--;
|
||||
io.writex.in.wmode = 0;
|
||||
io.writex.in.count = 4;
|
||||
io.writex.in.offset = 0;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
|
||||
printf("Setting file as sparse\n");
|
||||
status = torture_set_sparse(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying 2^32 offset\n");
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
io.writex.in.file.fnum = fnum;
|
||||
io.writex.in.count = 4000;
|
||||
io.writex.in.offset = 0xFFFFFFFF - 2000;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, 4000);
|
||||
CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
for (i=33;i<max_bits;i++) {
|
||||
printf("Trying 2^%d offset\n", i);
|
||||
setup_buffer(buf, seed+1, maxsize);
|
||||
io.writex.in.file.fnum = fnum;
|
||||
io.writex.in.count = 4000;
|
||||
io.writex.in.offset = ((uint64_t)1) << i;
|
||||
io.writex.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
if (i>33 &&
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
break;
|
||||
}
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writex.out.nwritten, 4000);
|
||||
CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed+1, 4000);
|
||||
}
|
||||
printf("limit is 2^%d\n", i);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test write unlock ops
|
||||
*/
|
||||
static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_write io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint_t seed = time(NULL);
|
||||
union smb_fileinfo finfo;
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_WRITE_WRITEUNLOCK\n");
|
||||
io.generic.level = RAW_WRITE_WRITEUNLOCK;
|
||||
|
||||
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 zero write\n");
|
||||
io.writeunlock.in.file.fnum = fnum;
|
||||
io.writeunlock.in.count = 0;
|
||||
io.writeunlock.in.offset = 0;
|
||||
io.writeunlock.in.remaining = 0;
|
||||
io.writeunlock.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying small write\n");
|
||||
io.writeunlock.in.count = 9;
|
||||
io.writeunlock.in.offset = 4;
|
||||
io.writeunlock.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
|
||||
0, WRITE_LOCK);
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying large write\n");
|
||||
io.writeunlock.in.count = 4000;
|
||||
io.writeunlock.in.offset = 0;
|
||||
io.writeunlock.in.data = buf;
|
||||
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
|
||||
0, WRITE_LOCK);
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
|
||||
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.writeunlock.in.file.fnum = fnum+1;
|
||||
io.writeunlock.in.count = 4000;
|
||||
io.writeunlock.in.offset = 0;
|
||||
io.writeunlock.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("Setting file as sparse\n");
|
||||
status = torture_set_sparse(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying 2^32 offset\n");
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
io.writeunlock.in.file.fnum = fnum;
|
||||
io.writeunlock.in.count = 4000;
|
||||
io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
|
||||
io.writeunlock.in.data = buf;
|
||||
smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
|
||||
0, WRITE_LOCK);
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
|
||||
CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test write close ops
|
||||
*/
|
||||
static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
union smb_write io;
|
||||
NTSTATUS status;
|
||||
BOOL ret = True;
|
||||
int fnum;
|
||||
uint8_t *buf;
|
||||
const int maxsize = 90000;
|
||||
const char *fname = BASEDIR "\\test.txt";
|
||||
uint_t seed = time(NULL);
|
||||
union smb_fileinfo finfo;
|
||||
|
||||
buf = talloc_zero_size(mem_ctx, maxsize);
|
||||
|
||||
if (!torture_setup_dir(cli, BASEDIR)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Testing RAW_WRITE_WRITECLOSE\n");
|
||||
io.generic.level = RAW_WRITE_WRITECLOSE;
|
||||
|
||||
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 zero write\n");
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
io.writeclose.in.count = 0;
|
||||
io.writeclose.in.offset = 0;
|
||||
io.writeclose.in.mtime = 0;
|
||||
io.writeclose.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
|
||||
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying small write\n");
|
||||
io.writeclose.in.count = 9;
|
||||
io.writeclose.in.offset = 4;
|
||||
io.writeclose.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf+4, seed, 9);
|
||||
CHECK_VALUE(IVAL(buf,0), 0);
|
||||
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
|
||||
printf("Trying large write\n");
|
||||
io.writeclose.in.count = 4000;
|
||||
io.writeclose.in.offset = 0;
|
||||
io.writeclose.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeclose.out.nwritten, 4000);
|
||||
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
printf("Trying bad fnum\n");
|
||||
io.writeclose.in.file.fnum = fnum+1;
|
||||
io.writeclose.in.count = 4000;
|
||||
io.writeclose.in.offset = 0;
|
||||
io.writeclose.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
|
||||
|
||||
printf("Setting file as sparse\n");
|
||||
status = torture_set_sparse(cli->tree, fnum);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
|
||||
printf("skipping large file tests - CAP_LARGE_FILES not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Trying 2^32 offset\n");
|
||||
setup_buffer(buf, seed, maxsize);
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
io.writeclose.in.count = 4000;
|
||||
io.writeclose.in.offset = 0xFFFFFFFF - 2000;
|
||||
io.writeclose.in.data = buf;
|
||||
status = smb_raw_write(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
CHECK_VALUE(io.writeclose.out.nwritten, 4000);
|
||||
CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
|
||||
|
||||
fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
|
||||
io.writeclose.in.file.fnum = fnum;
|
||||
|
||||
memset(buf, 0, maxsize);
|
||||
if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
|
||||
printf("read failed at %s\n", __location__);
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
CHECK_BUFFER(buf, seed, 4000);
|
||||
|
||||
done:
|
||||
smbcli_close(cli->tree, fnum);
|
||||
smb_raw_exit(cli->session);
|
||||
smbcli_deltree(cli->tree, BASEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
basic testing of write calls
|
||||
*/
|
||||
BOOL torture_raw_write(struct torture_context *torture)
|
||||
{
|
||||
struct smbcli_state *cli;
|
||||
BOOL ret = True;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (!torture_open_connection(&cli, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("torture_raw_write");
|
||||
|
||||
ret &= test_write(cli, mem_ctx);
|
||||
ret &= test_writeunlock(cli, mem_ctx);
|
||||
ret &= test_writeclose(cli, mem_ctx);
|
||||
ret &= test_writex(cli, mem_ctx);
|
||||
|
||||
torture_close_connection(cli);
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user