summaryrefslogtreecommitdiff
path: root/source4/torture/raw
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
committerAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
commitef2e26c91b80556af033d3335e55f5dfa6fff31d (patch)
treefaa21bfd7e7b5247250b47c7891dc1a5ebee6be9 /source4/torture/raw
downloadsamba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.gz
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.bz2
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.zip
first public release of samba4 code
(This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f)
Diffstat (limited to 'source4/torture/raw')
-rw-r--r--source4/torture/raw/chkpath.c142
-rw-r--r--source4/torture/raw/close.c170
-rw-r--r--source4/torture/raw/context.c388
-rw-r--r--source4/torture/raw/ioctl.c156
-rw-r--r--source4/torture/raw/lock.c216
-rw-r--r--source4/torture/raw/missing.txt157
-rw-r--r--source4/torture/raw/mkdir.c141
-rw-r--r--source4/torture/raw/mux.c298
-rw-r--r--source4/torture/raw/notify.c140
-rw-r--r--source4/torture/raw/open.c895
-rw-r--r--source4/torture/raw/oplock.c288
-rw-r--r--source4/torture/raw/qfileinfo.c701
-rw-r--r--source4/torture/raw/qfsinfo.c295
-rw-r--r--source4/torture/raw/read.c732
-rw-r--r--source4/torture/raw/rename.c128
-rw-r--r--source4/torture/raw/search.c610
-rw-r--r--source4/torture/raw/seek.c152
-rw-r--r--source4/torture/raw/setfileinfo.c498
-rw-r--r--source4/torture/raw/unlink.c148
-rw-r--r--source4/torture/raw/write.c702
20 files changed, 6957 insertions, 0 deletions
diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c
new file mode 100644
index 0000000000..3364c39a73
--- /dev/null
+++ b/source4/torture/raw/chkpath.c
@@ -0,0 +1,142 @@
+/*
+ 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"
+
+#define BASEDIR "\\rawchkpath"
+
+#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 BOOL test_chkpath(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ struct smb_chkpath io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum = -1;
+
+ io.in.path = BASEDIR;
+
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.path = BASEDIR "\\nodir";
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\test.txt");
+ if (fnum == -1) {
+ printf("failed to open test.txt - %s\n", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ io.in.path = BASEDIR "\\test.txt";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ if (!torture_set_file_attribute(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN)) {
+ printf("failed to set basedir hidden\n");
+ ret = False;
+ goto done;
+ }
+
+ io.in.path = BASEDIR;
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.path = "";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.path = ".";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.in.path = "\\";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.path = "\\.";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.in.path = "\\..";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ io.in.path = BASEDIR "\\..";
+ printf("testing %s\n", io.in.path);
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ cli_close(cli, fnum);
+ return ret;
+}
+
+/*
+ basic testing of chkpath calls
+*/
+BOOL torture_raw_chkpath(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_chkpath");
+
+ if (cli_deltree(cli, BASEDIR) == -1) {
+ printf("Failed to clean " BASEDIR "\n");
+ return False;
+ }
+ if (!cli_mkdir(cli, BASEDIR)) {
+ printf("Failed to create " BASEDIR " - %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!test_chkpath(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/close.c b/source4/torture/raw/close.c
new file mode 100644
index 0000000000..40bb57f303
--- /dev/null
+++ b/source4/torture/raw/close.c
@@ -0,0 +1,170 @@
+/*
+ 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"
+
+
+/* basic testing of all RAW_CLOSE_* calls
+*/
+BOOL torture_raw_close(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+ union smb_close io;
+ struct 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)) {
+ 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.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.in.fname = fname;
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ 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",
+ time_string(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;
+ }
+
+
+ cli_unlink(cli, fname);
+ REOPEN;
+
+ finfo2.generic.in.fname = fname;
+ finfo2.generic.level = RAW_FILEINFO_ALL_INFO;
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.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.in.fname = fname;
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ 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.fnum = fnum;
+ status = smb_raw_close(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+ printf("testing flush\n");
+ cli_close(cli, fnum);
+
+ io_flush.in.fnum = fnum;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ io_flush.in.fnum = 0xffff;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ REOPEN;
+
+ io_flush.in.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.in.fnum = fnum;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/context.c b/source4/torture/raw/context.c
new file mode 100644
index 0000000000..c19fea458d
--- /dev/null
+++ b/source4/torture/raw/context.c
@@ -0,0 +1,388 @@
+/*
+ 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"
+
+#define BASEDIR "\\rawcontext"
+
+#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, v, correct); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+
+/*
+ test session ops
+*/
+static BOOL test_session(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ BOOL ret = True;
+ char *username, *domain, *password;
+ struct cli_session *session;
+ struct cli_tree *tree;
+ union smb_sesssetup setup;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ char c = 1;
+
+ printf("TESTING SESSION HANDLING\n");
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ username = lp_parm_string(-1, "torture", "username");
+ password = lp_parm_string(-1, "torture", "password");
+ domain = lp_workgroup();
+
+ printf("create a second security context on the same transport\n");
+ session = cli_session_init(cli->transport);
+ setup.generic.level = RAW_SESSSETUP_GENERIC;
+ setup.generic.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.generic.in.capabilities = 0; /* ignored in secondary session setup */
+ setup.generic.in.password = password;
+ setup.generic.in.user = username;
+ setup.generic.in.domain = domain;
+
+ status = smb_raw_session_setup(session, mem_ctx, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ session->vuid = setup.generic.out.vuid;
+
+ printf("use the same tree as the existing connection\n");
+ tree = cli_tree_init(session);
+ tree->tid = cli->tree->tid;
+ cli->tree->reference_count++;
+
+ printf("vuid1=%d vuid2=%d\n", cli->session->vuid, session->vuid);
+
+ 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_RIGHT_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.fnum;
+
+ printf("write using the old vuid\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.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("the fnum should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.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, which will also close the session
+ as the reference count will be 0 */
+ cli_tree_close(tree);
+
+done:
+ return ret;
+}
+
+
+/*
+ test tree ops
+*/
+static BOOL test_tree(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ BOOL ret = True;
+ char *share;
+ struct cli_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";
+ char c = 1;
+
+ printf("TESTING TREE HANDLING\n");
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ share = lp_parm_string(-1, "torture", "share");
+
+ printf("create a second tree context on the same session\n");
+ tree = cli_tree_init(cli->session);
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = 0;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = share;
+ tcon.tconx.in.device = "A:";
+ status = smb_tree_connect(tree, mem_ctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ tree->tid = tcon.tconx.out.cnum;
+ 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_tree_connect(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_RIGHT_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.fnum;
+
+ printf("write using the old tid\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.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.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 */
+ cli_tree_close(tree);
+
+done:
+ return ret;
+}
+
+
+/*
+ test pid ops
+*/
+static BOOL test_pid(struct cli_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";
+ char c = 1;
+ uint16 pid1, pid2;
+
+ printf("TESTING PID HANDLING\n");
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("create a second pid\n");
+ pid1 = cli->session->pid;
+ pid2 = pid1+1;
+
+ printf("pid1=%d pid2=%d\n", pid1, pid2);
+
+ printf("create a file using the new pid\n");
+ cli->session->pid = pid2;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHT_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.fnum;
+
+ printf("write using the old pid\n");
+ cli->session->pid = pid1;
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.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("write with the new pid\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 the old pid\n");
+ cli->session->pid = pid1;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("the fnum should still be accessible\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);
+
+ printf("exit the new pid\n");
+ cli->session->pid = pid2;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("the fnum should not now be accessible\n");
+ cli->session->pid = pid1;
+ 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.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;
+}
+
+
+/*
+ basic testing of session/tree context calls
+*/
+BOOL torture_raw_context(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_context");
+
+ if (!test_session(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_tree(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_pid(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/ioctl.c b/source4/torture/raw/ioctl.c
new file mode 100644
index 0000000000..d55db4c1e6
--- /dev/null
+++ b/source4/torture/raw/ioctl.c
@@ -0,0 +1,156 @@
+/*
+ Unix SMB/CIFS implementation.
+ ioctl 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"
+
+#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 cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ struct 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", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying QUERY_JOB_INFO\n");
+ ctl.in.fnum = fnum;
+ ctl.in.request = IOCTL_QUERY_JOB_INFO;
+
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+ printf("Trying bad handle\n");
+ ctl.in.fnum = fnum+1;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+done:
+ cli_close(cli, fnum);
+ return ret;
+}
+
+/* test some filesystem control functions */
+static BOOL test_fsctl(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ int fnum;
+ NTSTATUS status;
+ BOOL ret = True;
+ const char *fname = BASEDIR "\\test.dat";
+ struct smb_ntioctl 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", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("trying sparse file\n");
+ nt.in.function = FSCTL_SET_SPARSE;
+ nt.in.fnum = fnum;
+ nt.in.fsctl = True;
+ nt.in.filter = 0;
+
+ status = smb_raw_ntioctl(cli->tree, &nt);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying bad handle\n");
+ nt.in.fnum = fnum+1;
+ status = smb_raw_ntioctl(cli->tree, &nt);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+#if 0
+ nt.in.fnum = fnum;
+ for (i=0;i<100;i++) {
+ nt.in.function = FSCTL_FILESYSTEM + (i<<2);
+ status = smb_raw_ntioctl(cli->tree, &nt);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ printf("filesystem fsctl 0x%x - %s\n",
+ i, nt_errstr(status));
+ }
+ }
+#endif
+
+done:
+ cli_close(cli, fnum);
+ return ret;
+}
+
+/*
+ basic testing of some ioctl calls
+*/
+BOOL torture_raw_ioctl(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_ioctl");
+
+ if (cli_deltree(cli, BASEDIR) == -1) {
+ printf("Failed to clean " BASEDIR "\n");
+ return False;
+ }
+ if (!cli_mkdir(cli, BASEDIR)) {
+ printf("Failed to create " BASEDIR " - %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!test_ioctl(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_fsctl(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c
new file mode 100644
index 0000000000..b0b0b56451
--- /dev/null
+++ b/source4/torture/raw/lock.c
@@ -0,0 +1,216 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various lock operations
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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"
+
+#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, v, correct); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "\\testlock"
+
+
+/*
+ test SMBlock and SMBunlock ops
+*/
+static BOOL test_lock(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_LOCK_LOCK\n");
+ io.generic.level = RAW_LOCK_LOCK;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying 0/0 lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.fnum = fnum;
+ io.lock.in.count = 0;
+ io.lock.in.offset = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying 0/1 lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.fnum = fnum;
+ io.lock.in.count = 1;
+ io.lock.in.offset = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ printf("Trying max lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.fnum = fnum;
+ io.lock.in.count = 4000;
+ io.lock.in.offset = ~0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ printf("Trying wrong pid unlock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.fnum = fnum;
+ io.lock.in.count = 4002;
+ io.lock.in.offset = 10001;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ cli->session->pid--;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test locking&X ops
+*/
+static BOOL test_lockx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_LOCK_LOCKX\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 0;
+ lock[0].count = 0xFFFFFFFF;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of lock calls
+*/
+BOOL torture_raw_lock(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_lock");
+
+ if (!test_lockx(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_lock(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/missing.txt b/source4/torture/raw/missing.txt
new file mode 100644
index 0000000000..8e026b78ff
--- /dev/null
+++ b/source4/torture/raw/missing.txt
@@ -0,0 +1,157 @@
+- 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
+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
diff --git a/source4/torture/raw/mkdir.c b/source4/torture/raw/mkdir.c
new file mode 100644
index 0000000000..52120f0542
--- /dev/null
+++ b/source4/torture/raw/mkdir.c
@@ -0,0 +1,141 @@
+/*
+ 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"
+
+#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 mkdir ops
+*/
+static BOOL test_mkdir(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_mkdir md;
+ struct smb_rmdir rd;
+ const char *path = "\\test_mkdir.dir";
+ NTSTATUS status;
+ BOOL ret = True;
+
+ /* cleanup */
+ cli_rmdir(cli, path);
+ cli_unlink(cli, path);
+
+ /*
+ 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 */
+ cli_close(cli, 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);
+
+ cli_unlink(cli, 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_UNSUCCESSFUL);
+
+ printf("testing t2mkdir with EAs\n");
+
+ /* with EAs */
+ md.t2mkdir.in.num_eas = 1;
+ md.t2mkdir.in.eas = talloc(mem_ctx, sizeof(md.t2mkdir.in.eas[0]));
+ 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, "1", 1);
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+
+done:
+ cli_rmdir(cli, path);
+ cli_unlink(cli, path);
+ return ret;
+}
+
+
+/*
+ basic testing of all RAW_MKDIR_* calls
+*/
+BOOL torture_raw_mkdir(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_mkdir");
+
+ if (!test_mkdir(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/mux.c b/source4/torture/raw/mux.c
new file mode 100644
index 0000000000..05c5e3de09
--- /dev/null
+++ b/source4/torture/raw/mux.c
@@ -0,0 +1,298 @@
+/*
+ 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"
+
+#define BASEDIR "\\test_mux"
+
+#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 the delayed reply to a open that leads to a sharing violation
+*/
+static BOOL test_mux_open(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ struct cli_request *req;
+
+ printf("testing multiplexed open/open/close\n");
+
+ /*
+ file open with no share access
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHT_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ 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 = BASEDIR "\\open.dat";
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+
+ /* send an open that will conflict */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ /*
+ same request, but async
+ */
+ req = smb_raw_open_send(cli->tree, &io);
+
+ /* and close the file */
+ cli_close(cli, fnum);
+
+ /* see if the async open succeeded */
+ status = smb_raw_open_recv(req, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ cli_close(cli, io.ntcreatex.out.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 cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ struct cli_request *req;
+
+ printf("testing multiplexed lock/write/close\n");
+
+ fnum = cli_open(cli, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("open failed in mux_write - %s\n", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ cli->session->pid = 1;
+
+ /* lock a range */
+ if (!cli_lock(cli, fnum, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock failed in mux_write - %s\n", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ cli->session->pid = 2;
+
+ /* send an async write */
+ io.generic.level = RAW_WRITE_WRITEX;
+ io.writex.in.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;
+ cli_unlock(cli, fnum, 0, 4);
+
+ /* and recv the async write reply */
+ status = smb_raw_write_recv(req, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ cli_close(cli, fnum);
+
+done:
+ return ret;
+}
+
+
+/*
+ test a lock that conflicts with an existing lock
+*/
+static BOOL test_mux_lock(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ struct cli_request *req;
+ struct smb_lock_entry lock[1];
+
+ printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
+
+ fnum = cli_open(cli, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("open failed in mux_write - %s\n", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("establishing a lock\n");
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.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 = cli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("reopening with an exit\n");
+ smb_raw_exit(cli->session);
+ fnum = cli_open(cli, 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.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);
+
+ 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 = cli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ cli_close(cli, fnum);
+
+done:
+ return ret;
+}
+
+
+
+/*
+ basic testing of multiplexing notify
+*/
+BOOL torture_raw_mux(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_mux");
+
+ /* cleanup */
+ if (cli_deltree(cli, BASEDIR) == -1) {
+ printf("Failed to cleanup " BASEDIR "\n");
+ ret = False;
+ goto done;
+ }
+
+
+ if (!cli_mkdir(cli, BASEDIR)) {
+ printf("Failed to create %s\n", BASEDIR);
+ ret = False;
+ goto done;
+ }
+
+ 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;
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/notify.c b/source4/torture/raw/notify.c
new file mode 100644
index 0000000000..a123dc6702
--- /dev/null
+++ b/source4/torture/raw/notify.c
@@ -0,0 +1,140 @@
+/*
+ Unix SMB/CIFS implementation.
+ basic raw test suite for change notify
+ 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"
+
+#define BASEDIR "\\test_notify"
+
+#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_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ printf("(%d) wrong value for %s 0x%x - 0x%x\n", \
+ __LINE__, #v, (int)v, (int)correct); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_WSTR(field, value, flags) do { \
+ if (!field.s || strcmp(field.s, value) || wire_bad_flags(&field, flags)) { \
+ printf("(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+
+/*
+ basic testing of change notify
+*/
+BOOL torture_raw_notify(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ struct smb_notify notify;
+ union smb_open io;
+ int fnum = -1;
+ struct cli_request *req;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_notify");
+
+ /* cleanup */
+ if (cli_deltree(cli, BASEDIR) == -1) {
+ printf("Failed to cleanup " BASEDIR "\n");
+ ret = False;
+ goto done;
+ }
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SA_RIGHT_FILE_ALL_ACCESS;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ 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 = BASEDIR;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+
+ /* ask for a change notify */
+ notify.in.buffer_size = 4096;
+ notify.in.completion_filter = 0xFF;
+ notify.in.fnum = fnum;
+ notify.in.recursive = True;
+
+ printf("testing notify mkdir\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ cli_mkdir(cli, BASEDIR "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.out.num_changes, 1);
+ CHECK_VAL(notify.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WSTR(notify.out.changes[0].name, "subdir-name", STR_UNICODE);
+
+ printf("testing notify rmdir\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ cli_rmdir(cli, BASEDIR "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.out.num_changes, 1);
+ CHECK_VAL(notify.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WSTR(notify.out.changes[0].name, "subdir-name", STR_UNICODE);
+
+ printf("testing notify cancel\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smb_raw_ntcancel(req);
+ cli_mkdir(cli, BASEDIR "\\subdir-name");
+ status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/open.c b/source4/torture/raw/open.c
new file mode 100644
index 0000000000..9f77eb3f8e
--- /dev/null
+++ b/source4/torture/raw/open.c
@@ -0,0 +1,895 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_OPEN_* 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"
+
+/* enum for whether reads/writes are possible on a file */
+enum rdwr_mode {RDWR_NONE, RDWR_RDONLY, RDWR_WRONLY, RDWR_RDWR};
+
+#define BASEDIR "\\rawopen"
+
+/*
+ check if a open file can be read/written
+*/
+static enum rdwr_mode check_rdwr(struct cli_state *cli, int fnum)
+{
+ char c = 1;
+ BOOL can_read = (cli_read(cli, fnum, &c, 0, 1) == 1);
+ BOOL can_write = (cli_write(cli, fnum, 0, &c, 0, 1) == 1);
+ if ( can_read && can_write) return RDWR_RDWR;
+ if ( can_read && !can_write) return RDWR_RDONLY;
+ if (!can_read && can_write) return RDWR_WRONLY;
+ return RDWR_NONE;
+}
+
+/*
+ describe a RDWR mode as a string
+*/
+static const char *rdwr_string(enum rdwr_mode m)
+{
+ switch (m) {
+ case RDWR_NONE: return "NONE";
+ case RDWR_RDONLY: return "RDONLY";
+ case RDWR_WRONLY: return "WRONLY";
+ case RDWR_RDWR: return "RDWR";
+ }
+ return "-";
+}
+
+#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 CREATE_FILE do { \
+ fnum = create_complex_file(cli, mem_ctx, fname); \
+ if (fnum == -1) { \
+ printf("(%d) Failed to create %s - %s\n", __LINE__, fname, cli_errstr(cli)); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_RDWR(fnum, correct) do { \
+ enum rdwr_mode m = check_rdwr(cli, fnum); \
+ if (m != correct) { \
+ printf("(%d) Incorrect readwrite mode %s - expected %s\n", \
+ __LINE__, rdwr_string(m), rdwr_string(correct)); \
+ ret = False; \
+ }} while (0)
+
+#define CHECK_TIME(t, field) do { \
+ time_t t1, t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.fname = fname; \
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t1 = t & ~1; \
+ t2 = nt_time_to_unix(&finfo.all_info.out.field) & ~1; \
+ if (ABS(t1-t2) > 2) { \
+ printf("(%d) wrong time for field %s %s - %s\n", \
+ __LINE__, #field, \
+ time_string(mem_ctx, t1), \
+ time_string(mem_ctx, t2)); \
+ dump_all_info(mem_ctx, &finfo); \
+ ret = False; \
+ }} while (0)
+
+#define CHECK_NTTIME(t, field) do { \
+ NTTIME t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.fname = fname; \
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t2 = finfo.all_info.out.field; \
+ if (!nt_time_equal(&t, &t2)) { \
+ printf("(%d) wrong time for field %s %s - %s\n", \
+ __LINE__, #field, \
+ nt_time_string(mem_ctx, &t), \
+ nt_time_string(mem_ctx, &t2)); \
+ dump_all_info(mem_ctx, &finfo); \
+ ret = False; \
+ }} while (0)
+
+#define CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.fname = fname; \
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != finfo.all_info.out.field) { \
+ printf("(%d) wrong value for field %s 0x%x - 0x%x\n", \
+ __LINE__, #field, (int)v, (int)finfo.all_info.out.field); \
+ dump_all_info(mem_ctx, &finfo); \
+ ret = False; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ printf("(%d) wrong value for %s 0x%x - 0x%x\n", \
+ __LINE__, #v, (int)v, (int)correct); \
+ ret = False; \
+ }} while (0)
+
+#define SET_ATTRIB(sattrib) do { \
+ union smb_setfileinfo sfinfo; \
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; \
+ sfinfo.generic.file.fname = fname; \
+ ZERO_STRUCT(sfinfo.basic_info.in); \
+ sfinfo.basic_info.in.attrib = sattrib; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ printf("(%d) Failed to set attrib 0x%x on %s\n", \
+ __LINE__, sattrib, fname); \
+ }} while (0)
+
+/*
+ test RAW_OPEN_OPEN
+*/
+static BOOL test_open(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_open.txt";
+ NTSTATUS status;
+ int fnum, fnum2;
+ BOOL ret = True;
+
+ printf("Checking RAW_OPEN_OPEN\n");
+
+ io.open.level = RAW_OPEN_OPEN;
+ io.open.in.fname = fname;
+ io.open.in.flags = OPEN_FLAGS_FCB;
+ io.open.in.search_attrs = 0;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ fnum = io.open.out.fnum;
+
+ cli_unlink(cli, fname);
+ CREATE_FILE;
+ cli_close(cli, fnum);
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.open.out.fnum;
+ CHECK_RDWR(fnum2, RDWR_RDWR);
+ cli_close(cli, fnum2);
+ cli_close(cli, fnum);
+
+ /* check the read/write modes */
+ io.open.level = RAW_OPEN_OPEN;
+ io.open.in.fname = fname;
+ io.open.in.search_attrs = 0;
+
+ io.open.in.flags = OPEN_FLAGS_OPEN_READ;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+ CHECK_RDWR(fnum, RDWR_RDONLY);
+ cli_close(cli, fnum);
+
+ io.open.in.flags = OPEN_FLAGS_OPEN_WRITE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+ CHECK_RDWR(fnum, RDWR_WRONLY);
+ cli_close(cli, fnum);
+
+ io.open.in.flags = OPEN_FLAGS_OPEN_RDWR;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+ cli_close(cli, fnum);
+
+ /* check the share modes roughly - not a complete matrix */
+ io.open.in.flags = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_WRITE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+
+ if (io.open.in.flags != io.open.out.rmode) {
+ printf("(%d) rmode should equal flags - 0x%x 0x%x\n",
+ __LINE__, io.open.out.rmode, io.open.in.flags);
+ }
+
+ io.open.in.flags = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_NONE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.open.in.flags = OPEN_FLAGS_OPEN_READ | OPEN_FLAGS_DENY_NONE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.open.out.fnum;
+ CHECK_RDWR(fnum2, RDWR_RDONLY);
+ cli_close(cli, fnum);
+ cli_close(cli, fnum2);
+
+
+ /* check the returned write time */
+ io.open.level = RAW_OPEN_OPEN;
+ io.open.in.fname = fname;
+ io.open.in.search_attrs = 0;
+ io.open.in.flags = OPEN_FLAGS_OPEN_READ;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.open.out.fnum;
+
+ /* check other reply fields */
+ CHECK_TIME(io.open.out.write_time, write_time);
+ CHECK_ALL_INFO(io.open.out.size, size);
+ CHECK_ALL_INFO(io.open.out.attrib, attrib);
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_OPENX
+*/
+static BOOL test_openx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_openx.txt";
+ NTSTATUS status;
+ int fnum, fnum2;
+ BOOL ret = True;
+ int i;
+ struct {
+ uint16 open_func;
+ BOOL with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { OPENX_OPEN_FUNC_OPEN, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_FAIL, True, NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { OPENX_OPEN_FUNC_FAIL, False, NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
+ };
+
+ printf("Checking RAW_OPEN_OPENX\n");
+ cli_unlink(cli, fname);
+
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 1024*1024;
+ io.openx.in.timeout = 0;
+
+ /* check all combinations of open_func */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ d_printf("Failed to create file %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+ cli_close(cli, fnum);
+ }
+ io.openx.in.open_func = open_funcs[i].open_func;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ printf("(%d) incorrect status %s should be %s (i=%d with_file=%d open_func=0x%x)\n",
+ __LINE__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_func);
+ ret = False;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ cli_close(cli, io.openx.out.fnum);
+ cli_unlink(cli, fname);
+ }
+ }
+
+ /* check the basic return fields */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.fnum;
+
+ CHECK_ALL_INFO(io.openx.out.size, size);
+ CHECK_VAL(io.openx.out.size, 1024*1024);
+ CHECK_ALL_INFO(io.openx.in.size, size);
+ CHECK_TIME(io.openx.out.write_time, write_time);
+ CHECK_ALL_INFO(io.openx.out.attrib, attrib);
+ CHECK_VAL(io.openx.out.access, OPENX_MODE_ACCESS_RDWR);
+ CHECK_VAL(io.openx.out.ftype, 0);
+ CHECK_VAL(io.openx.out.devstate, 0);
+ CHECK_VAL(io.openx.out.action, OPENX_ACTION_CREATED);
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ /* check the fields when the file already existed */
+ fnum2 = create_complex_file(cli, mem_ctx, fname);
+ if (fnum2 == -1) {
+ ret = False;
+ goto done;
+ }
+ cli_close(cli, fnum2);
+
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.fnum;
+
+ CHECK_ALL_INFO(io.openx.out.size, size);
+ CHECK_TIME(io.openx.out.write_time, write_time);
+ CHECK_VAL(io.openx.out.action, OPENX_ACTION_EXISTED);
+ CHECK_VAL(io.openx.out.unknown, 0);
+ CHECK_ALL_INFO(io.openx.out.attrib, attrib);
+ cli_close(cli, fnum);
+
+ /* now check the search attrib for hidden files - win2003 ignores this? */
+ SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
+
+ io.openx.in.search_attrs = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli_close(cli, io.openx.out.fnum);
+
+ io.openx.in.search_attrs = 0;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli_close(cli, io.openx.out.fnum);
+
+ SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
+ cli_unlink(cli, fname);
+
+ /* and check attrib on create */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE, attrib);
+ cli_close(cli, io.openx.out.fnum);
+ cli_unlink(cli, fname);
+
+ /* check timeout on create - win2003 ignores the timeout! */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.fnum;
+
+ io.openx.in.timeout = 20000;
+ start_timer();
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ if (end_timer() > 3) {
+ printf("(%d) Incorrect timing in openx with timeout - waited %d seconds\n",
+ __LINE__, (int)end_timer());
+ ret = False;
+ }
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ /* now this is a really weird one - open for execute implies create?! */
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 0;
+ io.openx.in.timeout = 0;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli_close(cli, io.openx.out.fnum);
+
+ /* check the extended return flag */
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO | OPENX_FLAGS_EXTENDED_RETURN;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.openx.out.access_mask, STD_RIGHT_ALL_ACCESS);
+ cli_close(cli, io.openx.out.fnum);
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_T2OPEN
+
+ I can't work out how to get win2003 to accept a create file via TRANS2_OPEN, which
+ is why you see all the ACCESS_DENIED results below. When we finally work this out then this
+ test will make more sense
+*/
+static BOOL test_t2open(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_t2open.txt";
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ int i;
+ struct {
+ uint16 open_func;
+ BOOL with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { OPENX_OPEN_FUNC_OPEN, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_ACCESS_DENIED },
+ { OPENX_OPEN_FUNC_FAIL, True, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL, False, NT_STATUS_ACCESS_DENIED },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_ACCESS_DENIED },
+ { OPENX_OPEN_FUNC_TRUNC, True, NT_STATUS_ACCESS_DENIED },
+ { OPENX_OPEN_FUNC_TRUNC, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, True, NT_STATUS_ACCESS_DENIED },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_ACCESS_DENIED },
+ };
+
+ printf("Checking RAW_OPEN_T2OPEN\n");
+
+ io.t2open.level = RAW_OPEN_T2OPEN;
+ io.t2open.in.fname = fname;
+ io.t2open.in.flags = OPENX_FLAGS_ADDITIONAL_INFO |
+ OPENX_FLAGS_EA_LEN | OPENX_FLAGS_EXTENDED_RETURN;
+ io.t2open.in.open_mode = OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR;
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.file_attrs = 0;
+ io.t2open.in.write_time = 0;
+ io.t2open.in.size = 0;
+ io.t2open.in.timeout = 0;
+
+ io.t2open.in.eas = talloc(mem_ctx, sizeof(io.t2open.in.eas[0]));
+ io.t2open.in.num_eas = 1;
+ io.t2open.in.eas[0].flags = 0;
+ io.t2open.in.eas[0].name.s = "EAONE";
+ io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "1", 1);
+
+ /* check all combinations of open_func */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ d_printf("Failed to create file %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+ cli_close(cli, fnum);
+ }
+ io.t2open.in.open_func = open_funcs[i].open_func;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ printf("(%d) incorrect status %s should be %s (i=%d with_file=%d open_func=0x%x)\n",
+ __LINE__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_func);
+ ret = False;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ cli_close(cli, io.t2open.out.fnum);
+ cli_unlink(cli, fname);
+ }
+ }
+
+ /* check the basic return fields */
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ cli_close(cli, fnum);
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.t2open.out.fnum;
+
+ CHECK_ALL_INFO(io.t2open.out.size, size);
+ CHECK_VAL(io.t2open.out.write_time, 0);
+ CHECK_ALL_INFO(io.t2open.out.attrib, attrib);
+ CHECK_VAL(io.t2open.out.access, OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR);
+ CHECK_VAL(io.t2open.out.ftype, 0);
+ CHECK_VAL(io.t2open.out.devstate, 0);
+ CHECK_VAL(io.t2open.out.action, OPENX_ACTION_EXISTED);
+ cli_close(cli, fnum);
+
+ /* now check the search attrib for hidden files - win2003 ignores this? */
+ SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli_close(cli, io.t2open.out.fnum);
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli_close(cli, io.t2open.out.fnum);
+
+ SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
+ cli_unlink(cli, fname);
+
+ /* and check attrib on create */
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ /* check timeout on create - win2003 ignores the timeout! */
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.file_attrs = 0;
+ io.t2open.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_NTCREATEX
+*/
+static BOOL test_ntcreatex(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_ntcreatex.txt";
+ const char *dname = BASEDIR "\\torture_ntcreatex.dir";
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ int i;
+ struct {
+ uint32 open_disp;
+ BOOL with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { NTCREATEX_DISP_SUPERSEDE, True, NT_STATUS_OK },
+ { NTCREATEX_DISP_SUPERSEDE, False, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, True, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, True, NT_STATUS_OBJECT_NAME_COLLISION },
+ { NTCREATEX_DISP_CREATE, False, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, True, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, False, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, True, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_OVERWRITE_IF, True, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE_IF, False, NT_STATUS_OK },
+ { 6, True, NT_STATUS_INVALID_PARAMETER },
+ { 6, False, NT_STATUS_INVALID_PARAMETER },
+ };
+
+ printf("Checking RAW_OPEN_NTCREATEX\n");
+
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
+ io.ntcreatex.in.alloc_size = 1024*1024;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* test the open disposition */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = cli_open(cli, fname, O_CREAT|O_RDWR|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ d_printf("Failed to create file %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+ cli_close(cli, fnum);
+ }
+ io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ printf("(%d) incorrect status %s should be %s (i=%d with_file=%d open_disp=%d)\n",
+ __LINE__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file, (int)open_funcs[i].open_disp);
+ ret = False;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ cli_close(cli, io.ntcreatex.out.fnum);
+ cli_unlink(cli, fname);
+ }
+ }
+
+ /* basic field testing */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+
+ /* check fields when the file already existed */
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ ret = False;
+ goto done;
+ }
+ cli_close(cli, fnum);
+
+ 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.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+
+ /* create a directory */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
+ 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_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.fname = dname;
+ fname = dname;
+
+ cli_rmdir(cli, fname);
+ cli_unlink(cli, fname);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHT_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_VAL(io.ntcreatex.out.attrib, FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.is_directory, 1);
+ CHECK_VAL(io.ntcreatex.out.size, 0);
+ CHECK_VAL(io.ntcreatex.out.alloc_size, 0);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ cli_unlink(cli, fname);
+
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_MKNEW
+*/
+static BOOL test_mknew(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_mknew.txt";
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ time_t basetime = (time(NULL) + 3600*24*3) & ~1;
+ union smb_fileinfo finfo;
+
+ printf("Checking RAW_OPEN_MKNEW\n");
+
+ io.mknew.level = RAW_OPEN_MKNEW;
+ io.mknew.in.attrib = 0;
+ io.mknew.in.write_time = 0;
+ io.mknew.in.fname = fname;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.fnum;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ /* make sure write_time works */
+ io.mknew.in.write_time = basetime;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.fnum;
+ CHECK_TIME(basetime, write_time);
+
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ /* make sure file_attrs works */
+ io.mknew.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.fnum;
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE, attrib);
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_CTEMP
+*/
+static BOOL test_ctemp(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ NTSTATUS status;
+ int fnum;
+ BOOL ret = True;
+ time_t basetime = (time(NULL) + 3600*24*3) & ~1;
+ union smb_fileinfo finfo;
+ const char *name, *fname = NULL;
+
+ printf("Checking RAW_OPEN_CTEMP\n");
+
+ io.ctemp.level = RAW_OPEN_CTEMP;
+ io.ctemp.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ io.ctemp.in.write_time = basetime;
+ io.ctemp.in.directory = BASEDIR;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ctemp.out.fnum;
+
+ name = io.ctemp.out.name;
+
+ finfo.generic.level = RAW_FILEINFO_NAME_INFO;
+ finfo.generic.in.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fname = finfo.name_info.out.fname.s;
+ d_printf("ctemp name=%s real name=%s\n", name, fname);
+
+ CHECK_TIME(basetime, write_time);
+
+done:
+ cli_close(cli, fnum);
+ if (fname) {
+ cli_unlink(cli, fname);
+ }
+
+ return ret;
+}
+
+/* basic testing of all RAW_OPEN_* calls
+*/
+BOOL torture_raw_open(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_open");
+
+ if (cli_deltree(cli, BASEDIR) == -1) {
+ printf("Failed to clean " BASEDIR "\n");
+ return False;
+ }
+ if (!cli_mkdir(cli, BASEDIR)) {
+ printf("Failed to create " BASEDIR " - %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!test_open(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_openx(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_ntcreatex(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_t2open(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_mknew(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_ctemp(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
new file mode 100644
index 0000000000..888fcbdc13
--- /dev/null
+++ b/source4/torture/raw/oplock.c
@@ -0,0 +1,288 @@
+/*
+ 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"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ printf("(%d) wrong value for %s 0x%x - 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;
+ unsigned char level;
+ int count;
+} break_info;
+
+/*
+ a handler function for oplock break requests
+*/
+static BOOL oplock_handler_ack(struct cli_transport *transport, uint16 tid, uint16 fnum, uint8 level, void *private)
+{
+ struct cli_tree *tree = private;
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Acking in oplock handler\n");
+
+ return cli_oplock_ack(tree, fnum, level == 1? 0x102 : 2);
+}
+
+/*
+ a handler function for oplock break requests - close the file
+*/
+static BOOL oplock_handler_close(struct cli_transport *transport, uint16 tid, uint16 fnum, uint8 level, void *private)
+{
+ union smb_close io;
+ NTSTATUS status;
+ struct cli_tree *tree = private;
+
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.fnum = fnum;
+ io.close.in.write_time = 0;
+ status = smb_raw_close(tree, &io);
+
+ printf("Closing in oplock handler\n");
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("close failed in oplock_handler_close\n");
+ return False;
+ }
+ return True;
+}
+
+/*
+ test oplock ops
+*/
+static BOOL test_oplock(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ const char *fname = "\\test_oplock.dat";
+ NTSTATUS status;
+ BOOL ret = True;
+ union smb_open io;
+ struct smb_unlink unl;
+ union smb_read rd;
+ uint16 fnum, fnum2;
+
+ /* cleanup */
+ cli_unlink(cli, fname);
+
+ cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
+ 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(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ printf("unlink it - should be no break\n");
+ unl.in.pattern = fname;
+ unl.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &unl);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ CHECK_VAL(break_info.count, 0);
+
+ cli_close(cli, 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(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ printf("unlink should generate a break\n");
+ unl.in.pattern = fname;
+ unl.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &unl);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, 2);
+ CHECK_VAL(break_info.count, 1);
+
+
+ cli_close(cli, fnum);
+
+ printf("if we close on break then the unlink can succeed\n");
+ ZERO_STRUCT(break_info);
+ cli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ unl.in.pattern = fname;
+ unl.in.attrib = 0;
+ ZERO_STRUCT(break_info);
+ status = smb_raw_unlink(cli->tree, &unl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, 2);
+ CHECK_VAL(break_info.count, 1);
+
+ printf("a self read should not cause a break\n");
+ ZERO_STRUCT(break_info);
+ cli_close(cli, fnum);
+ cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ rd.read.level = RAW_READ_READ;
+ rd.read.in.fnum = fnum;
+ rd.read.in.count = 1;
+ rd.read.in.offset = 0;
+ rd.read.in.remaining = 0;
+ status = smb_raw_read(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+
+
+ printf("a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+ cli_close(cli, fnum);
+ cli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.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(cli->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, 2);
+
+ printf("a 2nd open should get an oplock when we close instead of ack\n");
+ ZERO_STRUCT(break_info);
+ cli_close(cli, fnum);
+ cli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.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(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.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, 2);
+
+
+done:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+ return ret;
+}
+
+
+/*
+ basic testing of oplocks
+*/
+BOOL torture_raw_oplock(int dummy)
+{
+ struct cli_state *cli1;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_oplock");
+
+ if (!test_oplock(cli1, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli1);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/qfileinfo.c b/source4/torture/raw/qfileinfo.c
new file mode 100644
index 0000000000..b1f508cae8
--- /dev/null
+++ b/source4/torture/raw/qfileinfo.c
@@ -0,0 +1,701 @@
+/*
+ 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"
+
+static struct {
+ const char *name;
+ enum fileinfo_level level;
+ unsigned only_paths:1;
+ unsigned only_handles:1;
+ uint32 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, const 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(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 */
+#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_FILEINFO_* calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+*/
+BOOL torture_raw_qfileinfo(int dummy)
+{
+ struct cli_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;
+ large_t correct_size;
+ uint32 correct_attrib;
+ const char *correct_name;
+ BOOL skip_streams = False;
+
+ if (!torture_open_connection(&cli)) {
+ 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, cli_errstr(cli));
+ 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.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.fname = 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 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 > 32) {
+ 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, \
+ time_string(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, \
+ time_string(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, &correct_time)); \
+ ret = False; \
+ }} while (0)
+
+#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, \
+ time_string(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, \
+ time_string(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, &correct_time)); \
+ ret = False; \
+ }} while (0)
+
+ /* 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, \
+ (unsigned)s1->stype.out.tfield, \
+ (unsigned)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, \
+ (unsigned)s1->stype.out.tfield, \
+ (unsigned)correct_size); \
+ ret = False; \
+ }} while (0)
+
+ s1 = fnum_find("STANDARD_INFO");
+ correct_size = s1->standard_info.out.size;
+ printf("size: %u\n", (unsigned)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", (unsigned)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, \
+ (unsigned)s1->stype.out.tfield, \
+ (unsigned)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, \
+ (unsigned)s1->stype.out.tfield, \
+ (unsigned)correct_attrib); \
+ ret = False; \
+ }} while (0)
+
+ s1 = fnum_find("BASIC_INFO");
+ correct_attrib = s1->basic_info.out.attrib;
+ printf("attrib: 0x%x\n", (unsigned)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(s1->stype.out.tfield.s, correct_name) != 0) || \
+ wire_bad_flags(&s1->stype.out.tfield, flags)) { \
+ 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(s1->stype.out.tfield.s, correct_name)) != 0 || \
+ wire_bad_flags(&s1->stype.out.tfield, flags)) { \
+ 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(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)) {
+ 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 */
+ cli_close(cli, fnum);
+ fnum = cli_nt_create_full(cli, correct_name, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
+ 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", cli_errstr(cli));
+ 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,
+ s1->all_eas.out.eas[i].value.length,
+ 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",
+ ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
+ 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); \
+ VAL_EQUAL(stype, field, stype, field); \
+} while (0)
+
+ NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, device);
+ NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, inode);
+ NAME_PATH_CHECK("POSITION_INFORMATION", position_information, 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
+
+#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, \
+ (unsigned)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, \
+ (unsigned)s1->stype.out.tfield); \
+ }} while (0)
+
+ /* 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:
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/qfsinfo.c b/source4/torture/raw/qfsinfo.c
new file mode 100644
index 0000000000..274d1073af
--- /dev/null
+++ b/source4/torture/raw/qfsinfo.c
@@ -0,0 +1,295 @@
+/*
+ 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"
+
+
+static struct {
+ const char *name;
+ enum fsinfo_level level;
+ uint32 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, },
+ {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
+ { 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) {
+ 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 STR_EQUAL(n1, v1, n2, v2) do {if (!s1->n1.out.v1 && !s2->n2.out.v2) return True; \
+ if (!s1->n1.out.v1 || !s2->n2.out.v2) return False; \
+ if (strcmp(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(int dummy)
+{
+ struct cli_state *cli;
+ int i;
+ BOOL ret = True;
+ int count;
+ union smb_fsinfo *s1, *s2;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ 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 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 > 10) {
+ 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_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_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 (wire_bad_flags(&s1->stype.out.field, flags)) { \
+ 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_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/read.c b/source4/torture/raw/read.c
new file mode 100644
index 0000000000..c231f52c9d
--- /dev/null
+++ b/source4/torture/raw/read.c
@@ -0,0 +1,732 @@
+/*
+ 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"
+
+#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, v, 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(char *buf, unsigned 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(char *buf, unsigned seed, int len, int line)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) {
+ char 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 cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_read io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned seed = time(NULL);
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_READ_READ\n");
+ io.generic.level = RAW_READ_READ;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.read.in.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.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.read.in.fnum = fnum;
+
+ cli_write(cli, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.read.in.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;
+ }
+
+ 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);
+ cli_write(cli, 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 (!cli_lock(cli, 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:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test lockread ops
+*/
+static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_read io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned seed = time(NULL);
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_READ_LOCKREAD\n");
+ io.generic.level = RAW_READ_LOCKREAD;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.lockread.in.fnum = fnum;
+ io.lockread.in.count = 1;
+ io.lockread.in.offset = 0;
+ 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);
+
+ printf("Trying zero file read\n");
+ io.lockread.in.count = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ printf("Trying bad fnum\n");
+ io.lockread.in.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.lockread.in.fnum = fnum;
+
+ cli_write(cli, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.lockread.in.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_FILE_LOCK_CONFLICT);
+
+ cli_unlock(cli, fnum, 0, 1);
+
+ 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);
+ cli_unlock(cli, 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;
+ }
+
+ 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);
+ cli_write(cli, 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);
+ cli_unlock(cli, 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);
+ cli_unlock(cli, fnum, 0, 0xFFFF);
+
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (!cli_lock(cli, 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:
+ cli_close(cli, fnum);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test readx ops
+*/
+static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_read io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned seed = time(NULL);
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_READ_READX\n");
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.generic.level = RAW_READ_READX;
+ io.readx.in.fnum = fnum;
+ io.readx.in.mincnt = 1;
+ io.readx.in.maxcnt = 1;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ 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.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.readx.in.fnum = fnum;
+
+ cli_write(cli, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.readx.in.fnum = fnum;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ 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;
+ }
+
+ 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);
+ cli_write(cli, fnum, 0, buf, 0, maxsize);
+ memset(buf, 0, maxsize);
+
+ printf("Trying large read\n");
+ io.readx.in.offset = 0;
+ 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.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 = 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);
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (!cli_lock(cli, 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);
+
+#ifdef LARGE_SMB_OFF_T
+ printf("Trying large offset read\n");
+ io.readx.in.offset = ((SMB_BIG_UINT)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 (!cli_lock64(cli, 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);
+#endif
+
+done:
+ cli_close(cli, fnum);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test readbraw ops
+*/
+static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_read io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned seed = time(NULL);
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_READ_READBRAW\n");
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.generic.level = RAW_READ_READBRAW;
+ io.readbraw.in.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.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.fnum = fnum;
+
+ cli_write(cli, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.readbraw.in.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;
+ }
+
+ 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);
+ cli_write(cli, 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 (!cli_lock(cli, 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);
+
+#ifdef LARGE_SMB_OFF_T
+ printf("Trying large offset read\n");
+ io.readbraw.in.offset = ((SMB_BIG_UINT)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);
+#endif
+
+done:
+ cli_close(cli, fnum);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of read calls
+*/
+BOOL torture_raw_read(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_read");
+
+ if (!test_read(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_readx(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_lockread(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_readbraw(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/rename.c b/source4/torture/raw/rename.c
new file mode 100644
index 0000000000..4cfa1c95c2
--- /dev/null
+++ b/source4/torture/raw/rename.c
@@ -0,0 +1,128 @@
+/*
+ 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"
+
+#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 BASEDIR "\\testrename"
+
+/*
+ test SMBmv ops
+*/
+static BOOL test_mv(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ struct smb_rename io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ const char *fname1 = BASEDIR "\\test1.txt";
+ const char *fname2 = BASEDIR "\\test2.txt";
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Trying simple rename\n");
+
+ fnum = create_complex_file(cli, mem_ctx, fname1);
+
+ io.in.pattern1 = fname1;
+ io.in.pattern2 = fname2;
+ io.in.attrib = 0;
+
+ 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 wildcard rename\n");
+ io.in.pattern1 = BASEDIR "\\*.txt";
+ io.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.in.pattern1 = BASEDIR "\\*.txt";
+ io.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.in.pattern1 = BASEDIR "\\test1.bak";
+ io.in.pattern2 = BASEDIR "\\*.txt";
+ io.in.attrib = 0;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of rename calls
+*/
+BOOL torture_raw_rename(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_rename");
+
+ if (!test_mv(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
new file mode 100644
index 0000000000..6cfdd2b3ff
--- /dev/null
+++ b/source4/torture/raw/search.c
@@ -0,0 +1,610 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_SEARCH_* 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"
+
+
+#define BASEDIR "\\testsearch"
+
+/*
+ callback function for single_search
+*/
+static BOOL single_search_callback(void *private, union smb_search_data *file)
+{
+ union smb_search_data *data = private;
+
+ *data = *file;
+
+ return True;
+}
+
+/*
+ do a single file (non-wildcard) search
+*/
+static NTSTATUS single_search(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *pattern,
+ enum search_level level,
+ union smb_search_data *data)
+{
+ union smb_search_first io;
+ NTSTATUS status;
+
+ io.generic.level = level;
+ if (level == RAW_SEARCH_SEARCH) {
+ io.search_first.in.max_count = 1;
+ io.search_first.in.search_attrib = 0;
+ io.search_first.in.pattern = pattern;
+ } else {
+ 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, (void *)data, single_search_callback);
+
+ return status;
+}
+
+
+static struct {
+ const char *name;
+ enum search_level level;
+ uint32 capability_mask;
+ NTSTATUS status;
+ union smb_search_data data;
+} levels[] = {
+ {"SEARCH", RAW_SEARCH_SEARCH, },
+ {"STANDARD", RAW_SEARCH_STANDARD, },
+ {"EA_SIZE", RAW_SEARCH_EA_SIZE, },
+ {"DIRECTORY_INFO", RAW_SEARCH_DIRECTORY_INFO, },
+ {"FULL_DIRECTORY_INFO", RAW_SEARCH_FULL_DIRECTORY_INFO, },
+ {"NAME_INFO", RAW_SEARCH_NAME_INFO, },
+ {"BOTH_DIRECTORY_INFO", RAW_SEARCH_BOTH_DIRECTORY_INFO, },
+ {"LEVEL_261", RAW_SEARCH_261, },
+ {"LEVEL_262", RAW_SEARCH_262, },
+ {"UNIX_INFO", RAW_SEARCH_UNIX_INFO, CAP_UNIX}
+};
+
+/* find a level in the table by name */
+static union smb_search_data *find(const char *name)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (NT_STATUS_IS_OK(levels[i].status) &&
+ strcmp(levels[i].name, name) == 0) {
+ return &levels[i].data;
+ }
+ }
+ return NULL;
+}
+
+/*
+ basic testing of all RAW_SEARCH_* calls using a single file
+*/
+static BOOL test_one_file(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ BOOL ret = True;
+ int fnum;
+ const char *fname = "\\torture_search.txt";
+ NTSTATUS status;
+ int i;
+ union smb_fileinfo all_info, alt_info, name_info;
+ union smb_search_data *s;
+
+ printf("Testing one file searches\n");
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ printf("ERROR: open of %s failed (%s)\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ /* call all the levels */
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ uint32 cap = cli->transport->negotiate.capabilities;
+
+ levels[i].status = single_search(cli, mem_ctx, fname,
+ levels[i].level, &levels[i].data);
+
+ /* see if this server claims to support this level */
+ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
+ continue;
+ }
+
+ printf("testing %s\n", levels[i].name);
+
+ if (!NT_STATUS_IS_OK(levels[i].status)) {
+ printf("search level %s(%d) failed - %s\n",
+ levels[i].name, (int)levels[i].level,
+ nt_errstr(levels[i].status));
+ ret = False;
+ }
+ }
+
+ /* get the all_info file into to check against */
+ all_info.generic.level = RAW_FILEINFO_ALL_INFO;
+ all_info.generic.in.fname = fname;
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &all_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("RAW_FILEINFO_ALL_INFO failed - %s\n", nt_errstr(status));
+ ret = False;
+ goto done;
+ }
+
+ alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
+ alt_info.generic.in.fname = fname;
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &alt_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("RAW_FILEINFO_ALT_NAME_INFO failed - %s\n", nt_errstr(status));
+ ret = False;
+ goto done;
+ }
+
+ name_info.generic.level = RAW_FILEINFO_NAME_INFO;
+ name_info.generic.in.fname = fname;
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &name_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("RAW_FILEINFO_NAME_INFO failed - %s\n", nt_errstr(status));
+ ret = False;
+ goto done;
+ }
+
+#define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != v.sname2.out.field2) { \
+ printf("(%d) %s/%s [%d] != %s/%s [%d]\n", \
+ __LINE__, \
+ #sname1, #field1, (int)s->sname1.field1, \
+ #sname2, #field2, (int)v.sname2.out.field2); \
+ ret = False; \
+ } \
+ }} while (0)
+
+#define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != (~1 & nt_time_to_unix(&v.sname2.out.field2))) { \
+ printf("(%d) %s/%s [%s] != %s/%s [%s]\n", \
+ __LINE__, \
+ #sname1, #field1, time_string(mem_ctx, s->sname1.field1), \
+ #sname2, #field2, nt_time_string(mem_ctx, &v.sname2.out.field2)); \
+ ret = False; \
+ } \
+ }} while (0)
+
+#define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (memcmp(&s->sname1.field1, &v.sname2.out.field2, sizeof(NTTIME))) { \
+ printf("(%d) %s/%s [%s] != %s/%s [%s]\n", \
+ __LINE__, \
+ #sname1, #field1, nt_time_string(mem_ctx, &s->sname1.field1), \
+ #sname2, #field2, nt_time_string(mem_ctx, &v.sname2.out.field2)); \
+ ret = False; \
+ } \
+ }} while (0)
+
+#define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
+ printf("(%d) %s/%s [%s] != %s/%s [%s]\n", \
+ __LINE__, \
+ #sname1, #field1, s->sname1.field1, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = False; \
+ } \
+ }} while (0)
+
+#define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \
+ wire_bad_flags(&s->sname1.field1, flags)) { \
+ printf("(%d) %s/%s [%s] != %s/%s [%s]\n", \
+ __LINE__, \
+ #sname1, #field1, s->sname1.field1.s, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = False; \
+ } \
+ }} while (0)
+
+#define CHECK_NAME(name, sname1, field1, fname, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, fname) || \
+ wire_bad_flags(&s->sname1.field1, flags)) { \
+ printf("(%d) %s/%s [%s] != %s\n", \
+ __LINE__, \
+ #sname1, #field1, s->sname1.field1.s, \
+ fname); \
+ ret = False; \
+ } \
+ }} while (0)
+
+ /* check that all the results are as expected */
+ CHECK_VAL("SEARCH", search, attrib, all_info, all_info, attrib);
+ CHECK_VAL("STANDARD", standard, attrib, all_info, all_info, attrib);
+ CHECK_VAL("EA_SIZE", ea_size, attrib, all_info, all_info, attrib);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("LEVEL_261", level_261, attrib, all_info, all_info, attrib);
+ CHECK_VAL("LEVEL_262", level_262, attrib, all_info, all_info, attrib);
+
+ CHECK_TIME("SEARCH", search, write_time, all_info, all_info, write_time);
+ CHECK_TIME("STANDARD", standard, write_time, all_info, all_info, write_time);
+ CHECK_TIME("EA_SIZE", ea_size, write_time, all_info, all_info, write_time);
+ CHECK_TIME("STANDARD", standard, create_time, all_info, all_info, create_time);
+ CHECK_TIME("EA_SIZE", ea_size, create_time, all_info, all_info, create_time);
+ CHECK_TIME("STANDARD", standard, access_time, all_info, all_info, access_time);
+ CHECK_TIME("EA_SIZE", ea_size, access_time, all_info, all_info, access_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("LEVEL_261", level_261, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("LEVEL_262", level_262, write_time, all_info, all_info, write_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("LEVEL_261", level_261, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("LEVEL_262", level_262, create_time, all_info, all_info, create_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("LEVEL_261", level_261, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("LEVEL_262", level_262, access_time, all_info, all_info, access_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("LEVEL_261", level_261, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("LEVEL_262", level_262, create_time, all_info, all_info, create_time);
+
+ CHECK_VAL("SEARCH", search, size, all_info, all_info, size);
+ CHECK_VAL("STANDARD", standard, size, all_info, all_info, size);
+ CHECK_VAL("EA_SIZE", ea_size, size, all_info, all_info, size);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, size, all_info, all_info, size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("LEVEL_261", level_261, size, all_info, all_info, size);
+ CHECK_VAL("LEVEL_262", level_262, size, all_info, all_info, size);
+
+ CHECK_VAL("STANDARD", standard, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("EA_SIZE", ea_size, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("LEVEL_261", level_261, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("LEVEL_262", level_262, alloc_size, all_info, all_info, alloc_size);
+
+ CHECK_VAL("EA_SIZE", ea_size, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("LEVEL_261", level_261, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("LEVEL_262", level_262, ea_size, all_info, all_info, ea_size);
+
+ CHECK_STR("SEARCH", search, name, alt_info, alt_name_info, fname);
+ CHECK_WSTR("BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE);
+
+ CHECK_NAME("STANDARD", standard, name, fname+1, 0);
+ CHECK_NAME("EA_SIZE", ea_size, name, fname+1, 0);
+ CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname+1, STR_TERMINATE_ASCII);
+ CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII);
+ CHECK_NAME("NAME_INFO", name_info, name, fname+1, STR_TERMINATE_ASCII);
+ CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII);
+ CHECK_NAME("LEVEL_261", level_261, name, fname+1, STR_TERMINATE_ASCII);
+ CHECK_NAME("LEVEL_262", level_262, name, fname+1, STR_TERMINATE_ASCII);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_unlink(cli, fname);
+
+ return ret;
+}
+
+
+struct multiple_result {
+ TALLOC_CTX *mem_ctx;
+ int count;
+ union smb_search_data *list;
+};
+
+/*
+ callback function for multiple_search
+*/
+static BOOL multiple_search_callback(void *private, union smb_search_data *file)
+{
+ struct multiple_result *data = private;
+
+
+ data->count++;
+ data->list = talloc_realloc(data->mem_ctx,
+ data->list,
+ data->count * (sizeof(data->list[0])));
+
+ data->list[data->count-1] = *file;
+
+ return True;
+}
+
+enum continue_type {CONT_FLAGS, CONT_NAME, CONT_RESUME_KEY};
+
+/*
+ do a single file (non-wildcard) search
+*/
+static NTSTATUS multiple_search(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *pattern,
+ enum search_level level,
+ enum continue_type cont_type,
+ void *data)
+{
+ union smb_search_first io;
+ union smb_search_next io2;
+ NTSTATUS status;
+ const int per_search = 300;
+ struct multiple_result *result = data;
+
+ io.generic.level = level;
+ if (level == RAW_SEARCH_SEARCH) {
+ io.search_first.in.max_count = per_search;
+ io.search_first.in.search_attrib = 0;
+ io.search_first.in.pattern = pattern;
+ } else {
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = per_search;
+ io.t2ffirst.in.flags = 0;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = pattern;
+ if (cont_type == CONT_RESUME_KEY) {
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME |
+ FLAG_TRANS2_FIND_BACKUP_INTENT;
+ }
+ }
+
+ status = smb_raw_search_first(cli->tree, mem_ctx,
+ &io, data, multiple_search_callback);
+
+
+ while (NT_STATUS_IS_OK(status)) {
+ io2.generic.level = level;
+ if (level == RAW_SEARCH_SEARCH) {
+ io2.search_next.in.max_count = per_search;
+ io2.search_next.in.search_attrib = 0;
+ io2.search_next.in.search_id = result->list[result->count-1].search.search_id;
+ } else {
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = per_search;
+ io2.t2fnext.in.resume_key = 0;
+ io2.t2fnext.in.flags = 0;
+ io2.t2fnext.in.last_name = "";
+ switch (cont_type) {
+ case CONT_RESUME_KEY:
+ if (level == RAW_SEARCH_STANDARD) {
+ io2.t2fnext.in.resume_key =
+ result->list[result->count-1].standard.resume_key;
+ } else {
+ io2.t2fnext.in.resume_key =
+ result->list[result->count-1].both_directory_info.file_index;
+ }
+ io2.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME |
+ FLAG_TRANS2_FIND_BACKUP_INTENT;
+ break;
+ case CONT_NAME:
+ if (level == RAW_SEARCH_STANDARD) {
+ io2.t2fnext.in.last_name =
+ result->list[result->count-1].standard.name.s;
+ } else {
+ io2.t2fnext.in.last_name =
+ result->list[result->count-1].both_directory_info.name.s;
+ }
+ break;
+ case CONT_FLAGS:
+ io2.t2fnext.in.flags = FLAG_TRANS2_FIND_CONTINUE;
+ break;
+ }
+ }
+
+ status = smb_raw_search_next(cli->tree, mem_ctx,
+ &io2, data, multiple_search_callback);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ if (level == RAW_SEARCH_SEARCH) {
+ if (io2.search_next.out.count == 0) {
+ break;
+ }
+ } else if (io2.t2fnext.out.count == 0 ||
+ io2.t2fnext.out.end_of_search) {
+ break;
+ }
+ }
+
+ return status;
+}
+
+#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, v, correct); \
+ ret = False; \
+ }} while (0)
+
+
+static int search_both_compare(union smb_search_data *d1, union smb_search_data *d2)
+{
+ return strcmp(d1->both_directory_info.name.s, d2->both_directory_info.name.s);
+}
+
+static int search_standard_compare(union smb_search_data *d1, union smb_search_data *d2)
+{
+ return strcmp(d1->standard.name.s, d2->standard.name.s);
+}
+
+static int search_old_compare(union smb_search_data *d1, union smb_search_data *d2)
+{
+ return strcmp(d1->search.name, d2->search.name);
+}
+
+
+/*
+ basic testing of search calls using many files
+*/
+static BOOL test_many_files(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ const int num_files = 700;
+ int i, fnum, t;
+ char *fname;
+ BOOL ret = True;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct {
+ const char *name;
+ const char *cont_name;
+ enum search_level level;
+ enum continue_type cont_type;
+ } search_types[] = {
+ {"BOTH_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_BOTH_DIRECTORY_INFO, CONT_FLAGS},
+ {"BOTH_DIRECTORY_INFO", "KEY", RAW_SEARCH_BOTH_DIRECTORY_INFO, CONT_RESUME_KEY},
+ {"BOTH_DIRECTORY_INFO", "NAME", RAW_SEARCH_BOTH_DIRECTORY_INFO, CONT_NAME},
+ {"STANDARD", "FLAGS", RAW_SEARCH_STANDARD, CONT_FLAGS},
+ {"STANDARD", "KEY", RAW_SEARCH_STANDARD, CONT_RESUME_KEY},
+ {"STANDARD", "NAME", RAW_SEARCH_STANDARD, CONT_NAME},
+ {"SEARCH", "ID", RAW_SEARCH_SEARCH, CONT_RESUME_KEY}
+ };
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Failed to create " BASEDIR " - %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ printf("Creating %d files\n", num_files);
+
+ for (i=0;i<num_files;i++) {
+ asprintf(&fname, BASEDIR "\\test%03d.txt", i);
+ fnum = cli_open(cli, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+ free(fname);
+ cli_close(cli, fnum);
+ }
+
+
+ for (t=0;t<ARRAY_SIZE(search_types);t++) {
+ ZERO_STRUCT(result);
+ result.mem_ctx = mem_ctx;
+
+ printf("Continue %s via %s\n", search_types[t].name, search_types[t].cont_name);
+
+ status = multiple_search(cli, mem_ctx, BASEDIR "\\*.*",
+ search_types[t].level,
+ search_types[t].cont_type,
+ &result);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, num_files);
+
+ if (search_types[t].level == RAW_SEARCH_BOTH_DIRECTORY_INFO) {
+ qsort(result.list, result.count, sizeof(result.list[0]), search_both_compare);
+ } else if (search_types[t].level == RAW_SEARCH_STANDARD) {
+ qsort(result.list, result.count, sizeof(result.list[0]), search_standard_compare);
+ } else {
+ qsort(result.list, result.count, sizeof(result.list[0]), search_old_compare);
+ }
+
+ for (i=0;i<num_files;i++) {
+ const char *s;
+ if (search_types[t].level == RAW_SEARCH_BOTH_DIRECTORY_INFO) {
+ s = result.list[i].both_directory_info.name.s;
+ } else if (search_types[t].level == RAW_SEARCH_STANDARD) {
+ s = result.list[i].standard.name.s;
+ } else {
+ s = result.list[i].search.name;
+ }
+ asprintf(&fname, "test%03d.txt", i);
+ if (strcmp(fname, s)) {
+ printf("Incorrect name %s at entry %d\n", s, i);
+ ret = False;
+ break;
+ }
+ free(fname);
+ }
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ basic testing of all RAW_SEARCH_* calls using a single file
+*/
+BOOL torture_raw_search(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_search");
+
+ if (!test_one_file(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_many_files(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/raw/seek.c b/source4/torture/raw/seek.c
new file mode 100644
index 0000000000..9379b676ab
--- /dev/null
+++ b/source4/torture/raw/seek.c
@@ -0,0 +1,152 @@
+/*
+ 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"
+
+#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, v, correct); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "\\testseek"
+
+/*
+ test seek ops
+*/
+static BOOL test_seek(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ struct smb_seek io;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ printf("Failed to open test.txt - %s\n", cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.fnum = fnum;
+
+ printf("Trying bad handle\n");
+ io.in.fnum = fnum+1;
+ io.in.mode = SEEK_MODE_START;
+ io.in.offset = 0;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ printf("Trying simple seek\n");
+ io.in.fnum = fnum;
+ io.in.mode = SEEK_MODE_START;
+ io.in.offset = 17;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.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.in.fnum = fnum;
+ io.in.mode = SEEK_MODE_CURRENT;
+ io.in.offset = -3;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.out.offset, 14);
+
+ printf("Trying end seek\n");
+ io.in.fnum = fnum;
+ io.in.mode = SEEK_MODE_END;
+ io.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.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.out.offset, finfo.all_info.out.size);
+
+ printf("Trying max seek\n");
+ io.in.fnum = fnum;
+ io.in.mode = SEEK_MODE_START;
+ io.in.offset = -1;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.out.offset, 0xffffffff);
+
+ printf("Trying max overflow\n");
+ io.in.fnum = fnum;
+ io.in.mode = SEEK_MODE_CURRENT;
+ io.in.offset = 1000;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.out.offset, 999);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of seek calls
+*/
+BOOL torture_raw_seek(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_seek");
+
+ if (!test_seek(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c
new file mode 100644
index 0000000000..c169895020
--- /dev/null
+++ b/source4/torture/raw/setfileinfo.c
@@ -0,0 +1,498 @@
+/*
+ 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"
+
+#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(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+ int 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)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_sfileinfo");
+
+ cli_deltree(cli, BASEDIR);
+ cli_mkdir(cli, BASEDIR);
+
+#define RECREATE_FILE(fname) do { \
+ if (fnum != -1) cli_close(cli, fnum); \
+ fnum = create_complex_file(cli, mem_ctx, fname); \
+ if (fnum == -1) { \
+ printf("(%d) ERROR: open of %s failed (%s)\n", \
+ __LINE__, fname, cli_errstr(cli)); \
+ ret = False; \
+ goto done; \
+ }} while (0)
+
+#define RECREATE_BOTH do { \
+ RECREATE_FILE(path_fname); \
+ cli_close(cli, 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.file.fnum = fnum; \
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
+ if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ printf("(%d) %s - %s (should be %s)\n", __LINE__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = False; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
+ finfo1.generic.in.fnum = fnum; \
+ status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1); \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ printf("(%d) %s pathinfo - %s\n", __LINE__, #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.file.fname = path_fname; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
+ sfinfo.generic.file.fname = path_fname_new; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ } \
+ if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ printf("(%d) %s - %s (should be %s)\n", __LINE__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = False; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
+ finfo1.generic.in.fname = 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.fname = path_fname_new; \
+ status2 = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo1); \
+ } \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ printf("(%d) %s pathinfo - %s\n", __LINE__, #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.fnum = fnum; \
+ status2 = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2); \
+ } else { \
+ finfo2.generic.in.fname = 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.fname = 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)); \
+ } \
+ }} while (0)
+
+#define CHECK_VALUE(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && finfo2.stype.out.field != value) { \
+ printf("(%d) %s - %s/%s should be 0x%x - 0x%x\n", __LINE__, \
+ call_name, #stype, #field, \
+ (uint_t)value, (uint_t)finfo2.stype.out.field); \
+ dump_all_info(mem_ctx, &finfo1); \
+ }} while (0)
+
+#define CHECK_TIME(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && nt_time_to_unix(&finfo2.stype.out.field) != value) { \
+ printf("(%d) %s - %s/%s should be 0x%x - 0x%x\n", __LINE__, \
+ call_name, #stype, #field, \
+ (uint_t)value, \
+ (uint_t)nt_time_to_unix(&finfo2.stype.out.field)); \
+ printf("\t%s", http_timestring(mem_ctx, value)); \
+ printf("\t%s\n", nt_time_string(mem_ctx, &finfo2.stype.out.field)); \
+ dump_all_info(mem_ctx, &finfo1); \
+ }} while (0)
+
+#define CHECK_STR(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && strcmp(finfo2.stype.out.field, value) != 0) { \
+ printf("(%d) %s - %s/%s should be '%s' - '%s'\n", __LINE__, \
+ call_name, #stype, #field, \
+ value, \
+ finfo2.stype.out.field); \
+ dump_all_info(mem_ctx, &finfo1); \
+ }} 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 = FILE_ATTRIBUTE_NORMAL;
+ 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_NORMAL);
+
+ 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_READONLY;
+ 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_READONLY);
+
+ 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_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 = 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);
+
+ printf("finally the rename_information level\n");
+ cli_close(cli, create_complex_file(cli, mem_ctx, fnum_fname_new));
+ cli_close(cli, 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+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);
+
+ sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+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);
+
+#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:
+ cli_close(cli, fnum);
+ if (!cli_unlink(cli, fnum_fname)) {
+ printf("Failed to delete %s - %s\n", fnum_fname, cli_errstr(cli));
+ }
+ if (!cli_unlink(cli, path_fname)) {
+ printf("Failed to delete %s - %s\n", path_fname, cli_errstr(cli));
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
+
+
+/*
+ look for the w2k3 setpathinfo STANDARD bug
+*/
+BOOL torture_raw_sfileinfo_bug(int dummy)
+{
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ const char *fname = "\\bug3.txt";
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+ int fnum;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_sfileinfo");
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ cli_close(cli, fnum);
+
+ sfinfo.generic.level = RAW_SFILEINFO_STANDARD;
+ sfinfo.generic.file.fname = 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;
+}
diff --git a/source4/torture/raw/unlink.c b/source4/torture/raw/unlink.c
new file mode 100644
index 0000000000..9cae91fe41
--- /dev/null
+++ b/source4/torture/raw/unlink.c
@@ -0,0 +1,148 @@
+/*
+ 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"
+
+#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 BASEDIR "\\testunlink"
+
+/*
+ test unlink ops
+*/
+static BOOL test_unlink(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ struct smb_unlink io;
+ NTSTATUS status;
+ BOOL ret = True;
+ const char *fname = BASEDIR "\\test.txt";
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Trying non-existant file\n");
+ io.in.pattern = fname;
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ cli_close(cli, cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE));
+
+ io.in.pattern = fname;
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying a hidden file\n");
+ cli_close(cli, cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE));
+ torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
+
+ io.in.pattern = fname;
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.in.pattern = fname;
+ io.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying a directory\n");
+ io.in.pattern = BASEDIR;
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+ io.in.pattern = BASEDIR;
+ io.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.in.pattern = "..";
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ printf("Trying wildcards\n");
+ cli_close(cli, cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE));
+ io.in.pattern = BASEDIR "\\t*.t";
+ io.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.in.pattern = BASEDIR "\\*";
+ io.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.in.pattern = BASEDIR "\\*.dat";
+ io.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.in.pattern = BASEDIR "\\*.tx?";
+ io.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);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of unlink calls
+*/
+BOOL torture_raw_unlink(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_unlink");
+
+ if (!test_unlink(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/raw/write.c b/source4/torture/raw/write.c
new file mode 100644
index 0000000000..117b322530
--- /dev/null
+++ b/source4/torture/raw/write.c
@@ -0,0 +1,702 @@
+/*
+ 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"
+
+#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, v, 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 CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.fname = fname; \
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != finfo.all_info.out.field) { \
+ printf("(%d) wrong value for field %s %.0f - %.0f\n", \
+ __LINE__, #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(char *buf, unsigned 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(char *buf, unsigned seed, int len, int line)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) {
+ char v = random();
+ if (buf[i] != v) {
+ printf("Buffer incorrect at line %d! ofs=%d buf=0x%x correct=0x%x\n",
+ line, i, buf[i], v);
+ return False;
+ }
+ }
+ return True;
+}
+
+/*
+ test write ops
+*/
+static BOOL test_write(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_WRITE_WRITE\n");
+ io.generic.level = RAW_WRITE_WRITE;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying zero write\n");
+ io.write.in.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 (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ 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 (cli_read(cli, fnum, buf, 0, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ printf("Trying bad fnum\n");
+ io.write.in.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);
+
+ printf("Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.write.in.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 + (SMB_BIG_UINT)io.write.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, io.write.in.offset, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test writex ops
+*/
+static BOOL test_writex(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_WRITE_WRITEX\n");
+ io.generic.level = RAW_WRITE_WRITEX;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying zero write\n");
+ io.writex.in.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 (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ 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 (cli_read(cli, fnum, buf, 0, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ printf("Trying bad fnum\n");
+ io.writex.in.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.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 (!cli_lock(cli, fnum, 3, 1, 0, WRITE_LOCK)) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ 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);
+
+ printf("Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writex.in.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 + (SMB_BIG_UINT)io.writex.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, io.writex.in.offset, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ printf("Trying 2^43 offset\n");
+ setup_buffer(buf, seed+1, maxsize);
+ io.writex.in.fnum = fnum;
+ io.writex.in.count = 4000;
+ io.writex.in.offset = ((SMB_BIG_UINT)1) << 43;
+ 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 + (SMB_BIG_UINT)io.writex.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, io.writex.in.offset, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed+1, 4000);
+
+
+ setup_buffer(buf, seed, maxsize);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test write unlock ops
+*/
+static BOOL test_writeunlock(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_WRITE_WRITEUNLOCK\n");
+ io.generic.level = RAW_WRITE_WRITEUNLOCK;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying zero write\n");
+ io.writeunlock.in.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 (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+ cli_lock(cli, 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 (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ 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;
+ cli_lock(cli, 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 (cli_read(cli, fnum, buf, 0, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ printf("Trying bad fnum\n");
+ io.writeunlock.in.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);
+
+ printf("Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writeunlock.in.fnum = fnum;
+ io.writeunlock.in.count = 4000;
+ io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
+ io.writeunlock.in.data = buf;
+ cli_lock(cli, 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 + (SMB_BIG_UINT)io.writeunlock.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test write close ops
+*/
+static BOOL test_writeclose(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ BOOL ret = True;
+ int fnum;
+ char *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero(mem_ctx, maxsize);
+
+ if (cli_deltree(cli, BASEDIR) == -1 ||
+ !cli_mkdir(cli, BASEDIR)) {
+ printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli));
+ return False;
+ }
+
+ printf("Testing RAW_WRITE_WRITECLOSE\n");
+ io.generic.level = RAW_WRITE_WRITECLOSE;
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, cli_errstr(cli));
+ ret = False;
+ goto done;
+ }
+
+ printf("Trying zero write\n");
+ io.writeclose.in.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 = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.fnum = fnum;
+
+ if (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ 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 = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, 0, 13) != 13) {
+ printf("read failed at %d\n", __LINE__);
+ 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 = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, 0, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ printf("Trying bad fnum\n");
+ io.writeclose.in.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);
+
+ printf("Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writeclose.in.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 + (SMB_BIG_UINT)io.writeclose.in.offset, size);
+
+ fnum = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (cli_read(cli, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
+ printf("read failed at %d\n", __LINE__);
+ ret = False;
+ goto done;
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smb_raw_exit(cli->session);
+ cli_deltree(cli, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of write calls
+*/
+BOOL torture_raw_write(int dummy)
+{
+ struct cli_state *cli;
+ BOOL ret = True;
+ TALLOC_CTX *mem_ctx;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ mem_ctx = talloc_init("torture_raw_write");
+
+ if (!test_write(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_writeunlock(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_writeclose(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ if (!test_writex(cli, mem_ctx)) {
+ ret = False;
+ }
+
+ torture_close_connection(cli);
+ talloc_destroy(mem_ctx);
+ return ret;
+}