s4:torture:vfs_fruit: add test reading Netatalk metadata
authorRalph Boehme <rb@sernet.de>
Tue, 8 Jul 2014 03:50:09 +0000 (05:50 +0200)
committerVolker Lendecke <vl@samba.org>
Mon, 18 Aug 2014 15:42:50 +0000 (17:42 +0200)
Signed-off-by: Ralph Boehme <rb@sernet.de>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
source4/torture/vfs/fruit.c
source4/torture/wscript_build

index 2685a8fb4b8fc200280bbe780b73212d6c252f76..6b2bd89f7513fd66af97109023cb0c5129ae7cfe 100644 (file)
 */
 
 #include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "lib/cmdline/popt_common.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include "MacExtensions.h"
 
 #include "torture/torture.h"
 #include "torture/util.h"
 #include "torture/smb2/proto.h"
 #include "torture/vfs/proto.h"
 
+#define BASEDIR "vfs_fruit_dir"
+
+#define CHECK_STATUS(status, correct) do { \
+       if (!NT_STATUS_EQUAL(status, correct)) { \
+               torture_result(tctx, TORTURE_FAIL, \
+                   "(%s) Incorrect status %s - should be %s\n", \
+                   __location__, nt_errstr(status), nt_errstr(correct)); \
+               ret = false; \
+               goto done; \
+       }} while (0)
+
+/*
+ * REVIEW:
+ * This is hokey, but what else can we do?
+ */
+#if defined(HAVE_ATTROPEN) || defined(FREEBSD)
+#define AFPINFO_EA_NETATALK "org.netatalk.Metadata"
+#define AFPRESOURCE_EA_NETATALK "org.netatalk.ResourceFork"
+#else
+#define AFPINFO_EA_NETATALK "user.org.netatalk.Metadata"
+#define AFPRESOURCE_EA_NETATALK "user.org.netatalk.ResourceFork"
+#endif
+
+/*
+The metadata xattr char buf below contains the following attributes:
+
+-------------------------------------------------------------------------------
+Entry ID   : 00000008 : File Dates Info
+Offset     : 00000162 : 354
+Length     : 00000010 : 16
+
+-DATE------:          : (GMT)                    : (Local)
+create     : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+modify     : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+backup     : 80000000 : Unknown or Initial
+access     : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+
+-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)
+00000000   : 1B 44 21 69 1B 44 21 69 80 00 00 00 1B 44 21 69 : .D!i.D!i.....D!i
+
+-------------------------------------------------------------------------------
+Entry ID   : 00000009 : Finder Info
+Offset     : 0000007A : 122
+Length     : 00000020 : 32
+
+-FInfo-----:
+Type       : 42415252 : BARR
+Creator    : 464F4F4F : FOOO
+isAlias    : 0
+Invisible  : 1
+hasBundle  : 0
+nameLocked : 0
+Stationery : 0
+CustomIcon : 0
+Reserved   : 0
+Inited     : 0
+NoINITS    : 0
+Shared     : 0
+SwitchLaunc: 0
+Hidden Ext : 0
+color      : 000      : none
+isOnDesk   : 0
+Location v : 0000     : 0
+Location h : 0000     : 0
+Fldr       : 0000     : ..
+
+-FXInfo----:
+Rsvd|IconID: 0000     : 0
+Rsvd       : 0000     : ..
+Rsvd       : 0000     : ..
+Rsvd       : 0000     : ..
+AreInvalid : 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+CustomBadge: 0
+ObjctIsBusy: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+RoutingInfo: 0
+unknown bit: 0
+unknown bit: 0
+Rsvd|commnt: 0000     : 0
+PutAway    : 00000000 : 0
+
+-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)
+00000000   : 42 41 52 52 46 4F 4F 4F 40 00 00 00 00 00 00 00 : BARRFOOO@.......
+00000010   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+
+-------------------------------------------------------------------------------
+Entry ID   : 0000000E : AFP File Info
+Offset     : 00000172 : 370
+Length     : 00000004 : 4
+
+-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)
+00000000   : 00 00 01 A1                                     : ....
+ */
+
+char metadata_xattr[] = {
+       0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+       0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x08, 0x00, 0x00, 0x01, 0x62, 0x00, 0x00,
+       0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+       0x00, 0x7a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+       0x00, 0x0e, 0x00, 0x00, 0x01, 0x72, 0x00, 0x00,
+       0x00, 0x04, 0x80, 0x44, 0x45, 0x56, 0x00, 0x00,
+       0x01, 0x76, 0x00, 0x00, 0x00, 0x08, 0x80, 0x49,
+       0x4e, 0x4f, 0x00, 0x00, 0x01, 0x7e, 0x00, 0x00,
+       0x00, 0x08, 0x80, 0x53, 0x59, 0x4e, 0x00, 0x00,
+       0x01, 0x86, 0x00, 0x00, 0x00, 0x08, 0x80, 0x53,
+       0x56, 0x7e, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00,
+       0x00, 0x04, 0x42, 0x41, 0x52, 0x52, 0x46, 0x4f,
+       0x4f, 0x4f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1b, 0x44, 0x21, 0x69, 0x1b, 0x44,
+       0x21, 0x69, 0x80, 0x00, 0x00, 0x00, 0x1b, 0x44,
+       0x21, 0x69, 0x00, 0x00, 0x01, 0xa1, 0x00, 0xfd,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x20,
+       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xe3,
+       0x86, 0x53, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x01,
+       0x00, 0x00
+};
+
+/**
+ * Read 'count' bytes at 'offset' from stream 'fname:sname' and
+ * compare against buffer 'value'
+ **/
+static bool check_stream(struct smb2_tree *tree,
+                        const char *location,
+                        struct torture_context *tctx,
+                        TALLOC_CTX *mem_ctx,
+                        const char *fname,
+                        const char *sname,
+                        off_t read_offset,
+                        size_t read_count,
+                        off_t comp_offset,
+                        size_t comp_count,
+                        const char *value)
+{
+       struct smb2_handle handle;
+       struct smb2_create create;
+       struct smb2_read r;
+       NTSTATUS status;
+       const char *full_name;
+
+       full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname);
+       if (full_name == NULL) {
+           torture_comment(tctx, "talloc_asprintf error\n");
+           return false;
+       }
+       ZERO_STRUCT(create);
+       create.in.desired_access = SEC_FILE_READ_DATA;
+       create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+       create.in.create_disposition = NTCREATEX_DISP_OPEN;
+       create.in.fname = full_name;
+
+       torture_comment(tctx, "Open stream %s\n", full_name);
+
+       status = smb2_create(tree, mem_ctx, &create);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (value == NULL) {
+                       return true;
+               } else {
+                       torture_comment(tctx, "Unable to open stream %s\n",
+                           full_name);
+                       sleep(10000000);
+                       return false;
+               }
+       }
+
+       handle = create.out.file.handle;
+       if (value == NULL) {
+               return true;
+       }
+
+
+       ZERO_STRUCT(r);
+       r.in.file.handle = handle;
+       r.in.length      = read_count;
+       r.in.offset      = read_offset;
+
+       status = smb2_read(tree, tree, &r);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "(%s) Failed to read %lu bytes from "
+                   "stream '%s'\n", location, (long)strlen(value), full_name);
+               return false;
+       }
+
+       if (memcmp(r.out.data.data + comp_offset, value, comp_count) != 0) {
+               torture_comment(tctx, "(%s) Bad data in stream\n", location);
+               return false;
+       }
+
+       smb2_util_close(tree, handle);
+       return true;
+}
+
+static bool torture_setup_local_xattr(struct torture_context *tctx,
+                                     const char *path_option,
+                                     const char *name,
+                                     const char *metadata,
+                                     size_t size)
+{
+       int ret = true;
+       int result;
+       const char *spath;
+       char *path;
+
+       spath = torture_setting_string(tctx, path_option, NULL);
+       if (spath == NULL) {
+               printf("No sharepath for option %s\n", path_option);
+               return false;
+       }
+
+       path = talloc_asprintf(tctx, "%s/%s", spath, name);
+
+       result = setxattr(path, AFPINFO_EA_NETATALK, metadata, size, 0);
+       if (result != 0) {
+               ret = false;
+       }
+
+       TALLOC_FREE(path);
+
+       return ret;
+}
+
+/**
+ * Create a file or directory
+ **/
+static bool torture_setup_file(TALLOC_CTX *mem_ctx, struct smb2_tree *tree,
+                              const char *name, bool dir)
+{
+       struct smb2_create io;
+       NTSTATUS status;
+
+       smb2_util_unlink(tree, name);
+       ZERO_STRUCT(io);
+       io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+       io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
+       io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+       io.in.share_access =
+               NTCREATEX_SHARE_ACCESS_DELETE|
+               NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE;
+       io.in.create_options = 0;
+       io.in.fname = name;
+       if (dir) {
+               io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+               io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
+               io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
+               io.in.create_disposition = NTCREATEX_DISP_CREATE;
+       }
+
+       status = smb2_create(tree, mem_ctx, &io);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
+       status = smb2_util_close(tree, io.out.file.handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
+       return true;
+}
+
+static bool test_read_atalk_metadata(struct torture_context *tctx,
+                                    struct smb2_tree *tree1,
+                                    struct smb2_tree *tree2)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       const char *fname = BASEDIR "\\torture_read_metadata";
+       NTSTATUS status;
+       struct smb2_handle testdirh;
+       bool ret = true;
+
+       torture_comment(tctx, "Checking metadata access\n");
+
+       smb2_util_unlink(tree1, fname);
+
+       status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       smb2_util_close(tree1, testdirh);
+
+       ret = torture_setup_file(mem_ctx, tree1, fname, false);
+       if (ret == false) {
+               goto done;
+       }
+
+       ret = torture_setup_local_xattr(tctx, "localdir",
+                                       BASEDIR "/torture_read_metadata",
+                                       metadata_xattr, sizeof(metadata_xattr));
+       if (ret == false) {
+               goto done;
+       }
+
+       ret &= check_stream(tree1, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+                           0, 60, 0, 4, "AFP");
+
+       ret &= check_stream(tree1, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+                           0, 60, 16, 8, "BARRFOOO");
+
+done:
+       smb2_deltree(tree1, BASEDIR);
+       talloc_free(mem_ctx);
+       return ret;
+}
+
 /*
  * Note: This test depends on "vfs objects = catia fruit
  * streams_xattr".  Note: To run this test, use
  * "--option=torture:share1=<SHARENAME1>
  * --option=torture:share2=<SHARENAME2>
- * --option=torture:localpath=<SHAREPATH>"
+ * --option=torture:localdir=<SHAREPATH>"
  */
 struct torture_suite *torture_vfs_fruit(void)
 {
@@ -40,5 +391,7 @@ struct torture_suite *torture_vfs_fruit(void)
 
        suite->description = talloc_strdup(suite, "vfs_fruit tests");
 
+       torture_suite_add_2ns_smb2_test(suite, "read metadata", test_read_atalk_metadata);
+
        return suite;
 }
index c0de7bbeac09485ec12b8e6a4aadd5be567bff64..c13e7d45475a0c6f46359b0efc7627eb153db5fd 100755 (executable)
@@ -151,7 +151,7 @@ bld.SAMBA_MODULE('TORTURE_NTP',
        )
 
 bld.SAMBA_MODULE('TORTURE_VFS',
-       source='vfs/vfs.c',
+       source='vfs/vfs.c vfs/fruit.c',
        allow_warnings=True,
        subsystem='smbtorture',
        deps='LIBCLI_SMB POPT_CREDENTIALS TORTURE_UTIL smbclient-raw TORTURE_RAW',