Add another torture test inspired by George @ Apple.
[jra/samba/.git] / source4 / torture / raw / rename.c
index c839100e7cbe1d364171dcfdd9b0f32de6e18731..951d91a6841b61431bf5866ecd53c3ca240d6efe 100644 (file)
@@ -5,7 +5,7 @@
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "librpc/gen_ndr/ndr_security.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
 
 #define CHECK_STATUS(status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
-               printf("(%d) Incorrect status %s - should be %s\n", \
-                      __LINE__, nt_errstr(status), nt_errstr(correct)); \
-               ret = False; \
+               printf("(%s) Incorrect status %s - should be %s\n", \
+                      __location__, nt_errstr(status), nt_errstr(correct)); \
+               ret = false; \
                goto done; \
        }} while (0)
 
 #define CHECK_VALUE(v, correct) do { \
        if ((v) != (correct)) { \
-               printf("(%d) Incorrect %s %d - should be %d\n", \
-                      __LINE__, #v, (int)v, (int)correct); \
-               ret = False; \
+               printf("(%s) Incorrect %s %d - should be %d\n", \
+                      __location__, #v, (int)v, (int)correct); \
+               ret = false; \
        }} while (0)
 
 #define BASEDIR "\\testrename"
 /*
   test SMBmv ops
 */
-static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_mv(struct torture_context *tctx, 
+                                       struct smbcli_state *cli)
 {
        union smb_rename io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum = -1;
        const char *fname1 = BASEDIR "\\test1.txt";
        const char *fname2 = BASEDIR "\\test2.txt";
+       const char *Fname1 = BASEDIR "\\Test1.txt";
+       union smb_fileinfo finfo;
        union smb_open op;
 
        printf("Testing SMBmv\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Trying simple rename\n");
@@ -74,9 +79,9 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        op.ntcreatex.in.security_flags = 0;
        op.ntcreatex.in.fname = fname1;
 
-       status = smb_raw_open(cli->tree, mem_ctx, &op);
+       status = smb_raw_open(cli->tree, tctx, &op);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = op.ntcreatex.out.fnum;
+       fnum = op.ntcreatex.out.file.fnum;
 
        io.generic.level = RAW_RENAME_RENAME;
        io.rename.in.pattern1 = fname1;
@@ -94,9 +99,9 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                NTCREATEX_SHARE_ACCESS_DELETE | 
                NTCREATEX_SHARE_ACCESS_READ |
                NTCREATEX_SHARE_ACCESS_WRITE;
-       status = smb_raw_open(cli->tree, mem_ctx, &op);
+       status = smb_raw_open(cli->tree, tctx, &op);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = op.ntcreatex.out.fnum;
+       fnum = op.ntcreatex.out.file.fnum;
 
        printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
        status = smb_raw_rename(cli->tree, &io);
@@ -107,6 +112,22 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_rename(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
+       printf("Trying case-changing rename\n");
+       io.rename.in.pattern1 = fname1;
+       io.rename.in.pattern2 = Fname1;
+       status = smb_raw_rename(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+       finfo.all_info.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       if (strcmp(finfo.all_info.out.fname.s, Fname1) != 0) {
+               printf("(%s) Incorrect filename [%s] after case-changing "
+                      "rename, should be [%s]\n", __location__,
+                      finfo.all_info.out.fname.s, Fname1);
+       }
+
        io.rename.in.pattern1 = fname1;
        io.rename.in.pattern2 = fname2;
 
@@ -167,15 +188,98 @@ done:
 }
 
 
+static bool test_osxrename(struct torture_context *tctx,
+                          struct smbcli_state *cli)
+{
+       union smb_rename io;
+       union smb_unlink io_un;
+       NTSTATUS status;
+       bool ret = true;
+       int fnum = -1;
+       const char *fname1 = BASEDIR "\\test1";
+       const char *FNAME1 = BASEDIR "\\TEST1";
+       union smb_fileinfo finfo;
+       union smb_open op;
+
+       printf("\nTesting OSX Rename\n");
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+       op.generic.level = RAW_OPEN_NTCREATEX;
+       op.ntcreatex.in.root_fid = 0;
+       op.ntcreatex.in.flags = 0;
+       op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       op.ntcreatex.in.create_options = 0;
+       op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       op.ntcreatex.in.share_access =
+               NTCREATEX_SHARE_ACCESS_READ |
+               NTCREATEX_SHARE_ACCESS_WRITE;
+       op.ntcreatex.in.alloc_size = 0;
+       op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       op.ntcreatex.in.security_flags = 0;
+       op.ntcreatex.in.fname = fname1;
+
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = op.ntcreatex.out.file.fnum;
+
+       io.generic.level = RAW_RENAME_RENAME;
+       io.rename.in.attrib = 0;
+
+       smbcli_close(cli->tree, fnum);
+
+       /* Rename by changing case. First check for the
+        * existence of the file with the "newname".
+        * If we find one and both the output and input are same case,
+        * delete it. */
+
+       printf("Checking os X rename (case changing)\n");
+
+       finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+       finfo.all_info.in.file.path = FNAME1;
+       printf("Looking for file %s \n",FNAME1);
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+               printf("Name of the file found %s \n", finfo.all_info.out.fname.s);
+               if (strcmp(finfo.all_info.out.fname.s, finfo.all_info.in.file.path) == 0) {
+                       /* If file is found with the same case delete it */
+                       printf("Deleting File %s \n", finfo.all_info.out.fname.s);
+                       io_un.unlink.in.pattern = finfo.all_info.out.fname.s;
+                       io_un.unlink.in.attrib = 0;
+                       status = smb_raw_unlink(cli->tree, &io_un);
+                       CHECK_STATUS(status, NT_STATUS_OK);
+               }
+       }
+
+       io.rename.in.pattern1 = fname1;
+       io.rename.in.pattern2 = FNAME1;
+       status = smb_raw_rename(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+       finfo.all_info.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       printf("File name after rename %s \n",finfo.all_info.out.fname.s);
+
+done:
+       smbcli_close(cli->tree, fnum);
+       smb_raw_exit(cli->session);
+       smbcli_deltree(cli->tree, BASEDIR);
+       return ret;
+}
 
 /*
   test SMBntrename ops
 */
-static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_ntrename(struct torture_context *tctx, 
+                                                 struct smbcli_state *cli)
 {
        union smb_rename io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum, i;
        const char *fname1 = BASEDIR "\\test1.txt";
        const char *fname2 = BASEDIR "\\test2.txt";
@@ -184,12 +288,12 @@ static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        printf("Testing SMBntrename\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Trying simple rename\n");
 
-       fnum = create_complex_file(cli, mem_ctx, fname1);
+       fnum = create_complex_file(cli, tctx, fname1);
        
        io.generic.level = RAW_RENAME_NTRENAME;
        io.ntrename.in.old_name = fname1;
@@ -248,14 +352,14 @@ static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
 
        finfo.generic.level = RAW_FILEINFO_ALL_INFO;
-       finfo.generic.in.fname = fname2;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname2;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 2);
        CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
 
-       finfo.generic.in.fname = fname1;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 2);
        CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
@@ -264,10 +368,11 @@ static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        smbcli_unlink(cli->tree, fname2);
 
-       finfo.generic.in.fname = fname1;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 1);
+       CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
 
        printf("Checking copy\n");
        io.ntrename.in.old_name = fname1;
@@ -277,17 +382,31 @@ static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_rename(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
+       finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+       finfo.generic.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(finfo.all_info.out.nlink, 1);
+       CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
+       finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+       finfo.generic.in.file.path = fname2;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(finfo.all_info.out.nlink, 1);
+       CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
        torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
 
        finfo.generic.level = RAW_FILEINFO_ALL_INFO;
-       finfo.generic.in.fname = fname2;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname2;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 1);
        CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
 
-       finfo.generic.in.fname = fname1;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 1);
        CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
@@ -296,8 +415,8 @@ static BOOL test_ntrename(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        smbcli_unlink(cli->tree, fname2);
 
-       finfo.generic.in.fname = fname1;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname1;
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(finfo.all_info.out.nlink, 1);
 
@@ -397,31 +516,109 @@ done:
        return ret;
 }
 
-
-/* 
-   basic testing of rename calls
+/*
+  test dir rename.
 */
-BOOL torture_raw_rename(void)
+static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *cli)
 {
-       struct smbcli_state *cli;
-       BOOL ret = True;
-       TALLOC_CTX *mem_ctx;
+        union smb_open io;
+       union smb_rename ren_io;
+       NTSTATUS status;
+        const char *dname1 = BASEDIR "\\dir_for_rename";
+        const char *dname2 = BASEDIR "\\renamed_dir";
+        const char *fname = BASEDIR "\\dir_for_rename\\file.txt";
+       bool ret = true;
+       int fnum = -1;
+
+        printf("Checking rename on a directory containing an open file.\n");
 
-       if (!torture_open_connection(&cli)) {
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
-       mem_ctx = talloc_init("torture_raw_rename");
+        /* create a directory */
+        smbcli_rmdir(cli->tree, dname1);
+        smbcli_rmdir(cli->tree, dname2);
+        smbcli_unlink(cli->tree, dname1);
+        smbcli_unlink(cli->tree, dname2);
+
+        ZERO_STRUCT(io);
+        io.generic.level = RAW_OPEN_NTCREATEX;
+        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+        io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+        io.ntcreatex.in.alloc_size = 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.open_disposition = NTCREATEX_DISP_CREATE;
+        io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+        io.ntcreatex.in.fname = dname1;
+        status = smb_raw_open(cli->tree, tctx, &io);
+        CHECK_STATUS(status, NT_STATUS_OK);
+
+        fnum = io.ntcreatex.out.file.fnum;
+       smbcli_close(cli->tree, fnum);
 
-       if (!test_mv(cli, mem_ctx)) {
-               ret = False;
-       }
+        /* Now create and hold open a file. */
+        ZERO_STRUCT(io);
+
+        io.generic.level = RAW_OPEN_NTCREATEX;
+        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+        io.ntcreatex.in.root_fid = 0;
+        io.ntcreatex.in.alloc_size = 0;
+        io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+        io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+        io.ntcreatex.in.create_options = 0;
+        io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+        io.ntcreatex.in.security_flags = 0;
+        io.ntcreatex.in.fname = fname;
+
+        /* Create the file. */
+
+        status = smb_raw_open(cli->tree, tctx, &io);
+        CHECK_STATUS(status, NT_STATUS_OK);
+        fnum = io.ntcreatex.out.file.fnum;
+
+        /* Now try and rename the directory. */
+
+        ZERO_STRUCT(ren_io);
+       ren_io.generic.level = RAW_RENAME_RENAME;
+       ren_io.rename.in.pattern1 = dname1;
+       ren_io.rename.in.pattern2 = dname2;
+       ren_io.rename.in.attrib = 0;
+       
+       status = smb_raw_rename(cli->tree, &ren_io);
+       CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
 
-       if (!test_ntrename(cli, mem_ctx)) {
-               ret = False;
+done:
+       
+       if (fnum != -1) {
+               smbcli_close(cli->tree, fnum);
        }
-
-       torture_close_connection(cli);
-       talloc_destroy(mem_ctx);
+       smb_raw_exit(cli->session);
+       smbcli_deltree(cli->tree, BASEDIR);
        return ret;
 }
+
+extern bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2);
+extern bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1);
+
+/* 
+   basic testing of rename calls
+*/
+struct torture_suite *torture_raw_rename(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "RENAME");
+
+       torture_suite_add_1smb_test(suite, "mv", test_mv);
+       /* test_trans2rename and test_nttransrename are actually in torture/raw/oplock.c to
+          use the handlers and macros there. */
+       torture_suite_add_2smb_test(suite, "trans2rename", test_trans2rename);
+       torture_suite_add_1smb_test(suite, "nttransrename", test_nttransrename);
+       torture_suite_add_1smb_test(suite, "ntrename", test_ntrename);
+       torture_suite_add_1smb_test(suite, "osxrename", test_osxrename);
+       torture_suite_add_1smb_test(suite, "directory rename", test_dir_rename);
+
+       return suite;
+}